Skip to content

Instantly share code, notes, and snippets.

@dahlsailrunner
Created August 19, 2021 16:58
Show Gist options
  • Save dahlsailrunner/29776d5caa94d9012a7a30a44e32b13f to your computer and use it in GitHub Desktop.
Save dahlsailrunner/29776d5caa94d9012a7a30a44e32b13f to your computer and use it in GitHub Desktop.

Central Code within a Library or other location

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();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment