You can create the following code in some central library or folder if desired:
public static IApplicationBuilder UseCustomSerilogRequestLogging(this IApplicationBuilder app, bool includeHealthChecks = false)
{
return app.UseSerilogRequestLogging(options =>
{
if (!includeHealthChecks)
{
options.GetLevel = ExcludeHealthChecks;
}
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
var user = httpContext.User.Identity;
if (user != null && user.IsAuthenticated)
{
var userInfo = GetUserInfoFromHttpContext(user as ClaimsIdentity);
var userInfoJson = JsonConvert.SerializeObject(userInfo, Formatting.Indented);
diagnosticContext.Set("UserInfo", userInfoJson);
diagnosticContext.Set("LoginName", userInfo.UserName);
}
};
});
}
private static UserInfo GetUserInfoFromHttpContext(ClaimsIdentity user)
{
var excluded = new List<string>
{
"nbf", "exp", "auth_time", "amr", "sub", "aud", "jti"
};
const string userIdClaimType = "sub";
const string userNameClaimType = "userName";
var userId = user.Claims.FirstOrDefault(a => a.Type == userIdClaimType)?.Value;
var userName = user.Claims.FirstOrDefault(a => a.Type == userNameClaimType)?.Value;
var userInfo = new UserInfo
{
UserName = userName,
UserId = userId,
UserClaims = new Dictionary<string, List<string>>()
};
foreach (var distinctClaimType in user.Claims
.Where(a => excluded.All(ex => ex != a.Type))
.Select(a => a.Type)
.Distinct())
{
userInfo.UserClaims[distinctClaimType] = user.Claims
.Where(a => a.Type == distinctClaimType)
.Select(c => c.Value)
.ToList();
}
return userInfo;
}
private static LogEventLevel ExcludeHealthChecks(HttpContext ctx, double _, Exception ex) =>
ex != null
? LogEventLevel.Error
: ctx.Response.StatusCode > 499
? LogEventLevel.Error
: IsHealthCheckEndpoint(ctx) // Not an error, check if it was a health check
? LogEventLevel.Verbose // Was a health check, use Verbose
: LogEventLevel.Information;
private static bool IsHealthCheckEndpoint(HttpContext ctx)
{
var userAgent = ctx.Request.Headers["User-Agent"].FirstOrDefault() ?? "";
return ctx.Request.Path.Value.EndsWith("health", StringComparison.CurrentCultureIgnoreCase) ||
userAgent.Contains("HealthCheck", StringComparison.InvariantCultureIgnoreCase);
}
Then in the Configure method of Startup.cs, add this line:
app.UseCustomSerilogRequestLogging();