I have a web application monitored with Application Insights but in the errors view I see non 500 http status responses being registered as errors. Is there a way to tell insights to only register 500 status codes or ignore 400 status codes from the captured events?
Yes, there is a way. What you can do is register a custom Telemetry Initializer and do something like this:
public void Initialize(Microsoft.ApplicationInsights.Channel.ITelemetry telemetry)
{
if (telemetry is RequestTelemetry && ((RequestTelemetry)telemetry).ResponseCode == "400")
{
((RequestTelemetry)telemetry).Success = true;
}
}
Related
Our ASP.NET Web API 2 application is consumed by mobile applications. Using Azure Application Insights we detected many responses with response code 500(Internal server error) without any Exception associated with them in Application Insights. During debugging session we did not encounter any Exception thrown.
We had a suspicion that this could be caused by client disconnects. After implementing a .net application simulating disconnects, we could replicate this issue even on a clean webapi2 project.
After further investigation we found out, that the result code 500(after the client is disconnected) occurs only when specific conditions are met. The request need to be cancelled on a non GET http operation and before ExecuteRequestHandler asp.net event is reached. On GET requests we cannot replicate this issue, neither on requests which entered or passed the ExecuteRequestHandler event.
Our goal is to filter out client disconnects from logs and focus on real issues.
This issue may be related to ASP.NET Web API OperationCanceledException when browser cancels the request, however the accepted solution does not work, because the disconnect occurs before any DelegatingHandler is reached. We would not use the mentioned solution, because client disconnects is not a Server issue but rather a client. For example in netcore the cancelled requests have response code 0 in logs. Anyway, the client will not see the result nor the result code because it is already gone.
Other possibly related question.
We are using the latest version Microsoft.AspNet.WebApi v5.2.7 and the investigation take place only on a development machine with IISExpress.
UPDATE
Including the minimal code to reproduce on clean webapi2 project.
Global.asax.cs
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
Debug.WriteLine($"{context.Response.StatusCode}:{context.Response.SubStatusCode}:{context.Request.Path}:{context.Request.Url.AbsoluteUri}");
}
}
HomeController.cs
[RoutePrefix("api/foo")]
public class HomeController : ApiController
{
[Route("bar")]
[HttpPut]
public async Task<IHttpActionResult> Put()
{
await Task.Delay(200);
return Ok();
}
}
PUT http://localhost:56952/api/foo/bar
On average 1 of 5 cancelled requests end with 500 when cancelled after 10ms. The response code is accessible from server logs Application Insights or Output Window in VS when logged. The client will not receive the response code, because the connection is closed before any response code is returned.
UPDATE 2
Telemetry from Application Insights
I am considering this as a bug in .Net Framework. I have written a workaround to end the currently executing request when the specified criterion are met:
Cancellation is requested from the client
Client is not connected
Handling should occur only before the ExecuteRequestHandler event
public class CancellationHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.OnExecuteRequestStep(OnExecuteRequestStep);
}
private void OnExecuteRequestStep(HttpContextBase context, Action step)
{
if (context.Response.StatusCode != 0
&& context.Response.ClientDisconnectedToken.IsCancellationRequested
&& !context.Response.IsClientConnected
&& (int)context.CurrentNotification < (int)RequestNotification.ExecuteRequestHandler)
{
context.Response.StatusCode = 0;
context.ApplicationInstance.CompleteRequest();
}
step();
}
public void Dispose()
{
}
}
After the handling takes places, status code is changed to zero(just like in .net core) and skipping all remaining events in ASP.NET pipeline to EndRequest event. I have tested this implementation on production for a month and did not find requests resulting into 500 without a corresponding Exception record in logs.
I use the code below to handle all unhandled errors on my controllers:
public abstract class BaseController: Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
if (IsJsonCall())
filterContext.Result = HandleJsonError(filterContext.Exception);
else
filterContext.Result = HandleError(filterContext.Exception);
}
}
In HandleJsonError function, I return a JSON object with information about the error. In my JavaScript code I detect this info and handle it properly.
Its working fine on localhost, returning a 200 HTTP Code to the client, but in my production environment, it returns the JSON object with the error info, so I can say its running all the code, but its returning a 500 HTTP code instead of 200, which is causing problems when JavaScript tries to recognize the returned content.
Why the codes returned are different event if the content is the same?
I've configured Application Insights on my web application however the telemetry is full of 'failed' requests from SingalR which makes spotting genuine issues difficult (see screenshot below). I want to filter out all SignalR requests and not send them to AI.
I've created a Telemetry Processor (see code below based on this example from MS) and registered it in the ApplicationInsights.config file, this works as expected when debugging locally and prevents any SignalR events from being sent however it doesn't seem to have any effect once the web application published and running in IIS.
public class SignalRFilter : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
public SignalRFilter(ITelemetryProcessor next)
{
this.Next = next;
}
public void Process(ITelemetry item)
{
if (!OKtoSend(item))
return;
else
this.Next.Process(item);
}
private bool OKtoSend(ITelemetry item)
{
if (item is RequestTelemetry && ((RequestTelemetry)item).Url.AbsolutePath.Contains("signalr"))
return false;
else
return true;
}
}
Any suggestions?
You're looking at these requests in Live Metrics Stream. For this particular view you can filter them out on demand. Feature is available in latest 2.4-beta (the stable version should be released soon). In this case you can click on Filter button and add proper filters to every stream. Similar behavior exists for charts:
Have you checked whether you see /signair/start in you Application Insights Analytics? It might be the case that you did filter them out successfully and they only show up in Live view.
I am trying to write my own authorization attribute where I run through some custom checks on any web api method with the CustomAuthorization attribute.
My code is as follows:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class CustomAuthorization : AuthorizationFilterAttribute
{
public override void OnAuthorization(AuthorizationContext context)
{
//// Attempt 1 - 404 error.
//// Doesnt block method with this attribute from executing (not desired behaviour).
//context.HttpContext.Response.StatusCode = 401;
//return;
//// Attempt 2 - 404 result.
//// Code with attribute doesnt execute (desired).
//// Error thrown says: An exception of type 'System.Web.Http.HttpResponseException' occurred in <namespace> but was not handled in user code
//// Additional information: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
//throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
// Attempt 3 - 404 result.
// Code with attribute doesnt execute (desired).
context.Result = new HttpUnauthorizedResult();
}
}
The problem I'm having is that I'm getting a 404 response from the web api instead of an expected 401. What am I doing wrong?
This is asp.net core 1.
Thanks in advance!
It may be because you have authentication setup to redirect to a login page for 401 responses and that login page is not being found (happened to me).
I want to pass an identifier to a custom error page in ASP.NET MVC.
I have the web.config set up to redirect to an error page when there is an status 500 error. I don't know how to pass an error id from the application code that throws the exception (also sets HTTP Status of 500) back to the error page that is configured.
It's easy if I just used Status 200 and returned a view from the Error method of the controller and did all the logic in there, however the Status code must be 500, so that's not an acceptable solution.
I also do not and will not use session for this. I'd like to use query string or view data.
Not a duplicate. This is about error handling (status code 500) and exceptions. 404 is about Page Not Found
I don't know a better way to customized information to error page configured in web.config. This is what I normally do when i need an error redirection:
I'll create an error handler action filter:
public class MyErrorHandler: HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.ExceptionHandled = true;
filterContext.Result = new RedirectResult("/error?error_id=123456", true);
return;
}
base.OnException(filterContext);
}
}
Within the Exception filter, you may try to handle differnet error with different error id, or whatever you prefer to alter the exception.
Then apply it onto controller or controler class:
[MyErrorHandler]
public class HomeController : Controller
{
....
}
And you will get a Http status 500 and will be redirected to:
http://<host>/error?error_id=123456