JianYA
JianYA

Reputation: 3024

ASP.NET Core Serilog not pushing property to its custom column

I have this setup in appsettings.json for my Serilog installation

"Serilog": {
  "MinimumLevel": "Information",
  "Enrich": [ "LogUserName" ],
  "Override": {
    "Microsoft": "Critical"
  },
  "WriteTo": [
    {
      "Name": "MSSqlServer",
      "Args": {
        "connectionString": "Server=.\\SQLEXPRESS;Database=Apple;Trusted_Connection=True;MultipleActiveResultSets=true;,
        "schemaName": "Apple",
        "tableName": "EventLogs",
        "columnOptionsSection": {
          "customColumns": [
            {
              "ColumnName": "UserName",
              "DataType": "nvarchar",
              "DataLength": 256,
              "AllowNull": true
            }
          ]
        }
      }
    }
  ]
},

I also have a custom enricher called LogUserName that is supposed to add the users username to a column called UserName in the db.

This is the enricher:

public class LogUserName
{
    private readonly RequestDelegate next;

    public LogUserName(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        LogContext.PushProperty("UserName", context.User.Identity.Name);
        await next(context);
        //return next(context);
    }
}

I have added .Enrich.FromLogContext() to my Program.cs.

So far I am able to see the UserName in the property tag but I am unable to push it to the column.

EDIT:

I use this model for my logs to the database:

public class EventLogs
{
    [Key]
    public int Id { get; set; }
    public string Level { get; set; }
    public DateTime TimeStamp { get; set; }
    public string UserName { get; set; }
    public string Properties { get; set; }
    public string LogEvent { get; set; }
    public string Exception { get; set; }
    public string Message { get; set; }
    public string MessageTemplate { get; set; }
}

Upvotes: 6

Views: 5293

Answers (1)

mason
mason

Reputation: 32704

Your enricher isn't valid. You're mixing up two concepts. Adding a property to the log context is not the same as creating an actual enricher. An actual enricher should implement ILogEventEnricher, as shown in this example.

What you actually created is ASP.NET Middleware. The LogContext.PushProprety returns an IDisposable and should be wrapped in a using statement, and then anything inside the using statement block should have the log context with the additional property. Like shown in the documentation.

One way to fix this is to remove LogUserName from your enrichers configuration. Then change your middleware to this:

public class LogUserNameMiddleware
{
    private readonly RequestDelegate next;

    public LogUserNameMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        using(LogContext.PushProperty("UserName", context.User.Identity.Name))
        {
            await next(context);
        }       
    }
}

Note you'll need tell ASP.NET Core about the Middleware, if you haven't already done so.

public static class LogUserNameMiddlewareExtensions
{
    public static IApplicationBuilder UseLogUserNameMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<LogUserNameMiddleware>();
    }
}

and in the Startup.Configure method, you can add the middleware to your pipeline:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseLogUserNameMiddleware();
        //your other middleware
    }
}

Note, you may want to clean up your middleware to handle if there isn't a logged in user, so you don't get a NullReferenceException.

Upvotes: 4

Related Questions