Add user to the log context when using Serilog and Asp.Net Core

serilog asp.net core
serilog-enrichers-aspnetcore
serilog request logging
serilog write to file .net core
g serilog aspnetcore
serilog aspnetcore changelog
github serilog aspnetcore
asp net core serilog middleware

I'm trying to use Serilog together with my ASP.Net Core 1.0 project. I just can't seem to get the current logged in user added to properties logged.

Has anyone figure this out yet?

I have tried this:

using System.Threading.Tasks;
using Serilog.Context;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using xxx.Models;

namespace xxx.Utils
{
    public class EnrichSerilogContextMiddleware
    {
        private readonly RequestDelegate _next;
        public EnrichSerilogContextMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {

            var username = httpContext.User.Identity.Name;
            if (httpContext.User.Identity.IsAuthenticated)
            {
                var userFullName = (((ClaimsIdentity)httpContext.User.Identity).FindFirst(Member.FullnameClaimName).Value);
                var userName = "anyone@gmail.com";
                LoggerEnricher.AddEntryPointContext(userFullName, userName);
            }
            else
            {
                LoggerEnricher.AddEntryPointContext();
            }


            await _next(httpContext);
        }
    }

    public static class LoggerEnricher

    {
        public static void AddEntryPointContext(string userFullName = null, string username = null)
        {
            if (!string.IsNullOrWhiteSpace(username) || !string.IsNullOrWhiteSpace(userFullName))
            {
                LogContext.PushProperty("Username", username);
                LogContext.PushProperty("UserFullename", userFullName);
            }
            else
            {
                LogContext.PushProperty("Username", "Anonymous");
            }

        }

        public static void EnrichLogger(this IApplicationBuilder app)
        {
            app.UseMiddleware<EnrichSerilogContextMiddleware>();
        }
    }
}

I trigger this in Startup.cs by adding:

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        loggerFactory.AddSerilog();
        app.EnrichLogger();
        ...
    }

But this always ends up with an "Anonymous" as the Username.

Thanks in advance

Søren Rokkedal

I was able to get the authenticated Active Directory user with just a few lines of code. I'm not very experienced with Core authentication, claims in particular, but perhaps this will get you on your way or at a minimum help others that come along with a similar problem to yours but with AD.

The key lines are Enrich.FromLogContext() and app.Use(async...

public class Startup
{
    public IConfigurationRoot Configuration { get; }

    public Startup(IHostingEnvironment env)
    {
        Log.Logger = new LoggerConfiguration()
                   .Enrich.FromLogContext() // Populates a 'User' property on every log entry
                   .WriteTo.MSSqlServer(Configuration.GetConnectionString("MyDatabase"), "Logs")
                   .CreateLogger();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.WithFilter(new FilterLoggerSettings
                                 {
                                     { "Default", LogLevel.Information },
                                     { "Microsoft", LogLevel.Warning },
                                     { "System", LogLevel.Warning }
                                 })
                     .AddSerilog();

        app.Use(async (httpContext, next) =>
                {
                    var userName = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "unknown";
                    LogContext.PushProperty("User", !String.IsNullOrWhiteSpace(userName) ? userName : "unknown");
                    await next.Invoke();
                });
    }
}

For AD Authentication via IIS/Kestrel the web.config requires a forwardWindowsAuthToken setting as follows:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <aspNetCore ... forwardWindowsAuthToken="true" />
  </system.webServer>
</configuration>

Setting up Serilog in ASP.NET Core 3, I'm trying to use Serilog together with my ASP.Net Core 1.0 project. I just can't seem to get the current logged in user added to properties logged. Has anyone  Serilog is an alternative logging implementation that plugs into ASP.NET Core. It supports the same structured logging APIs, and receives log events from the ASP.NET Core framework class libraries, but adds a stack of features that make it a more appealing choice for some kinds of apps and environments.

You need to invoke _next in a block like so:

public async Task Invoke(HttpContext httpContext)
{
    if (httpContext.User.Identity.IsAuthenticated)
    {
        var userFullName = (((ClaimsIdentity)httpContext.User.Identity).FindFirst(Member.FullnameClaimName).Value);
        var userName = "anyone@gmail.com";

        using (LogContext.PushProperty("Username", userName))
        using (LogContext.PushProperty("UserFullName", userFullName))
        {
            await _next(httpContext);
        }
    }
    else
    {
        await _next(httpContext);
    }
}

Extending Serilog with additional values to log, I'm trying to use Serilog together with my ASP.Net Core 1.0 project. I just can't seem to get the current logged in user added to properties  Serilog already has a good story for adding logging to your traditional HTTP ASP.NET Core apps with the Serilog.AspNetCore library, as well as an extensive list of available sinks. Unfortunately, the abstraction incompatibilities mean that you can't use this library with generic host ASP.NET Core apps.

Your middleware is probably fine. But the order in which you configure the middleware is important. Your EnrichLogger middleware is the very first one. That means it runs before the authentication middleware. Move the app.EnrichLogger call to just below where you add the authentication middleware (probably app.UseAuthentication). This way, the HttpContext.User property will be properly set when your EnrichLogger middleware runs.

Update

Actually, even moving this middleware below the authentication middleware might not be enough. It seems that the identity may be set (at least in some configurations) within the MVC middleware. This means that you can't access the user identity from middleware until after your controller actions have executed (by moving it down after the MVC middleware). But this will be too late to be any use in your logs.

Instead, you may have to use an MVC filter to add the user information to the log context. For example, you might create a filter like this:

public class LogEnrichmentFilter : IActionFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public LogEnrichmentFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext.User.Identity.IsAuthenticated)
        {
            LogContext.PushProperty("Username", httpContext.User.Identity.Name);
        }
        else
        {
            LogContext.PushProperty("Username", "Anonymous");
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
    }
}

You could then apply your filter globally using DI. In your Services.cs file:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<LogEnrichmentFilter>();
        services.AddMvc(o =>
        {
            o.Filters.Add<LogEnrichmentFilter>();
        });
        ...
    }

Adding Useful Information to ASP.NET Core Web API Serilog Logs , NET Core 3 comes with reasonable defaults for diagnostic logging: the Serilog is an alternative logging implementation that plugs into ASP.NET through the same (Serilog) logging pipeline, and to do that we add Windows users can alternatively grab the Seq MSI and install an instance with that. Adding Useful Information to ASP.NET Core Web API Serilog Logs We add the user name to all the log entries by using ← ASP.NET Core Logging with Serilog and

Use the .Enrich.WithEnvironmentUserName() method on the LoggerConfiguration object, eg:

public static IWebHost BuildWebHost(string[] args) =>
  WebHost.CreateDefaultBuilder(args)
    .ConfigureLogging((hostingContext, config) =>
    {
      config.ClearProviders();
    })
    .UseStartup<Startup>()             
    .UseSerilog((ctx, cfg) =>
    {
      cfg.ReadFrom.Configuration(ctx.Configuration)
        .Enrich.WithEnvironmentUserName()
    })
    .Build();

I also have the following setting in web.config, although I haven't proved if it is required on all IIS servers or not:

<system.webServer><aspNetCore ... forwardWindowsAuthToken="true"> ...

Taken from here: Logging in ASP NET Core with Serilog

Help with configuring Serilog to log the important data on ASP.NET , NET Core application with Serilog. Add properties to LogContext User.​Identity.Name : "anonymous"; LogContext.PushProperty("User"  First step is to create a new solution. Choose ASP.NET Core Web Application, enter solution and project names and click OK. The next step is to choose project template. We will use API as template. Choose it and click OK.

Logging MVC properties with Serilog.AspNetCore: Using Serilog , We add the user name to all the log entries by using LogContext.PushProperty . You can see capturing the request and response body is a little  If you are using .NET full framework or .NET Core, check out these enrichment libraries: Full .NET Framework; ASP.NET Core; Note: There are also some other enrichment libraries for other various ASP.NET frameworks. How to view Serilog logs by ASP.NET web request. Log files can quickly become a spaghetti mess of log messages.

Serilog and ASP.NET Core: Split Log Data Using Serilog , I would love a way to simply add the host/ipaddress into the logs of my Core 2.0 MVC application without coding a bunch of overhead. @  @JianYA It will only add the username to the log context after authorisation. If I wanted to log something during the actual signin process, I'd handle that separately, in the controller/handler/service that was responsible. – Cocowalla Dec 21 '18 at 10:33

Serilog Tutorial for .NET Logging: 16 Best Practices and Tips, AspNetCore's request logging middleware. are only available in an MVC context, so can't be directly accessed by Serilog's middleware. With Serilog.AspNetCore installed and configured, you can write log messages directly through Serilog or any ILogger interface injected by ASP.NET. All loggers will use the same underlying implementation, levels, and destinations. Instructions. First, install the Serilog.AspNetCore NuGet package into your app.

Comments
  • Have you tried adding this to your pipeline after authentication?
  • Not sure what You mean with this
  • I mean call app.EnrichLogger(); after the call to app.UseAuthentication(....);, or whatever your authentication method is. You're injecting the logger too early in the pipeline before the user has been authenticated so it will always be Anonymous.
  • I have app.UseIdentity() before my call to enrich the logger
  • @SørenRokkedal .. appreciate this is an old post but did you ever figure this out? Thanks
  • Thanks for the reply. I believe the original posting included the await _next(httpContext). Implementing the suggested solution did not make it work. Every time the Invoke method is called, the httpContext.User.Identity.IsAuthenticated is false. Any ideas?
  • Thanks for the follow-up. Not sure about this one then. Do you have Enrich.FromLogContext() set on your LoggerConfiguration?
  • Yes, I have configure this
  • You make some valid points about the middleware approach, but the username is not available everywhere with this approach too - for example, it isn't logged for Microsoft.AspNetCore.Hosting, Microsoft.AspNetCore.Mvc.ViewFeatures, Microsoft.AspNetCore.Routing.EndpointMiddleware and many others
  • As the name indicated, WithEnvironmentUserName will get the user from an environment variable - so it's going to get the server's username, not that of the current web app user