Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 = "[email protected]";
                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

like image 843
Søren Rokkedal Avatar asked Oct 06 '16 12:10

Søren Rokkedal


People also ask

How does Serilog work in NET Core?

Serilog is a . NET library that provides diagnostic logging to files, the console, and almost everywhere you would like. Serilog can be used in classic . NET Framework applications and for applications running on the latest and greatest .

Does Serilog support .NET Core?

Since Serilog supports ASP.NET Cores default logging APIs it can receive log events from ASP.NET Core framework libraries as well. Serilog in ASP.NET Core is very easy to set up and integrate. Serilog provides a structured logging framework and supports a wide variety of sinks to log to console, files, azure, etc.

How do I log exception with Serilog?

Debug(exception, "This is an {Exception} text", exception); logger. Debug(exception, "This is an {@Exception} structure", exception); The first line causes the logger to log an exception as plain text (by calling ToString()), and the second line causes the logger to write exception properties as separate fields.


Video Answer


1 Answers

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>
like image 169
Kevin Kalitowski Avatar answered Sep 28 '22 17:09

Kevin Kalitowski