Reputation: 9013
I have the following exception:
public class InvalidStatusCodeException : Exception
{
public HttpStatusCode ReceivedStatusCode { get; set; }
public string ApiUrl { get; set; }
public InvalidStatusCodeException(HttpStatusCode receivedStatusCode, string apiUrl)
{
ReceivedStatusCode = receivedStatusCode;
ApiUrl = apiUrl;
}
}
throw it in some cases:
string url = "api/group/1/getAll";
var response = await _client.GetAsync(url);
if (!response.IsSuccessStatusCode)
throw new InvalidStatusCodeException(response.StatusCode, url);
if I catch and log this exception:
catch(InvalidStatusCodeException status_ex)
{
string error = $"Invalid Status code for request: '{status_ex.ApiUrl}', received code: {status_ex.ReceivedStatusCode}";
log.LogError(status_ex, error, "InvalidStatusCode");
}
I don't see values of my custom properties (ReceivedStatusCode, ApiUrl) and can see details only in error message.
If I don't catch this exception at all and exception is being logged automatically then no way to see details at all.
Any way to see these custom properties without additional catching of exception?
Upvotes: 1
Views: 2076
Reputation: 191
You can write a custom middleware for this. There are 3 steps:
Step 1: Customise what telemetry you want to capture:
public class CustomTelemetryMiddleware
{
private readonly RequestDelegate _next;
public CustomTelemetryMiddleware(RequestDelegate next)
{
_next = next;
}
// https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/686#issuecomment-530353448
public async Task Invoke(HttpContext context)
{
var requestTelemetry = context.Features.Get<RequestTelemetry>();
if (requestTelemetry != null)
{
var request = context.Request;
// add items to show up in Request Properties:
requestTelemetry.Context.User.Id = context.User.Identity.Name;
// add items to show up in Custom Properties:
requestTelemetry.Properties.Add("PayingCustomer", "Yes");
/* Capture the request body as a Custom Property
*/
if (request?.Body?.CanRead == true)
{
request.EnableBuffering();
var bodySize = (int)(request.ContentLength ?? request.Body.Length);
if (bodySize > 0)
{
request.Body.Position = 0;
byte[] body;
using (var ms = new MemoryStream(bodySize))
{
await request.Body.CopyToAsync(ms);
body = ms.ToArray();
}
request.Body.Position = 0;
var requestBodyString = Encoding.UTF8.GetString(body);
requestTelemetry.Properties.Add("RequestBody", requestBodyString);
}
}
}
await _next(context);
}
}
Step 2, register it:
public static class CustomTelemetryMiddlewareExtensions
{
public static IApplicationBuilder UseCustomTelemetry(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomTelemetryMiddleware>();
}
}
And finally, Step 3, register it in your Startup.cs
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
// put this towards the end of your pipeline
app.UseCustomTelemetry();
}
Upvotes: 0
Reputation: 10839
You can use the concept of structure logging which logs the named constant as custom properties.
catch(InvalidStatusCodeException status_ex)
{
log.LogError(status_ex, "Invalid Status code for request: '{ApiUrl}', received code: {ReceivedStatusCode}", status_ex.ApiUrl, status_ex.ReceivedStatusCode);
}
The above log will add ApiUrl
and ReceivedStatusCode
as custom properties in application insights log.
Update
You don't need to throw and catch the exception. You can log in the else block of if (response.IsSuccessStatusCode)
like shown below:
if (response.IsSuccessStatusCode)
{
}
else
{
log.LogError(status_ex, "Invalid Status code for request: '{ApiUrl}', received code: {ReceivedStatusCode}",
apiUrl, response.StatusCode);
}
Other way of logging custom properties is via Logging Scope (check this) and via TelemetryInitializer (check this)
Upvotes: 1
Reputation: 9044
Add a message to the base Exception
public class InvalidStatusCodeException : Exception
{
public HttpStatusCode ReceivedStatusCode { get; set; }
public string ApiUrl { get; set; }
public InvalidStatusCodeException(HttpStatusCode receivedStatusCode, string apiUrl)
: base($"Invalid Status code for request: '{apiUrl}', received code: {receivedStatusCode}")
{
ReceivedStatusCode = receivedStatusCode;
ApiUrl = apiUrl;
}
}
Upvotes: 1