C# ASP.NET Core Serilog add class name and method to log C# ASP.NET Core Serilog add class name and method to log asp.net asp.net

C# ASP.NET Core Serilog add class name and method to log


I solved this issue by using a combination of Jordan's answer and this answer.

I changed my Loggerconfiguration by adding the logcontext through enrichment and I added the property 'method' to my outputTemplate:

var logger = new LoggerConfiguration()    .MinimumLevel.Verbose()    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)    .Enrich.FromLogContext()    .WriteTo.RollingFile(Configuration.GetValue<string>("LogFilePath") + "-{Date}.txt", LogEventLevel.Information,         outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{Method}) {Message}{NewLine}{Exception}")    .CreateLogger();

The Enrich.FromLogContext enables properties to be pushed to the outputTemplate by using the LogContext.PushProperty() method. In this case for the 'method' property (notice the {Method} in the outputTemplate).

Example for async methods:

using (LogContext.PushProperty("Method", new LogAsyncMethods().GetActualAsyncMethodName())){    _log.LogInformation("Log message.");}

Where GetActualAsyncMethodName() is written like this:

public static string GetActualAsyncMethodName([CallerMemberName]string name = null) => name;

This works fine for async methods.

Now for non-async methods this works fine:

using (LogContext.PushProperty("Method", System.Reflection.MethodBase.GetCurrentMethod().Name)){    _log.LogInformation("Changing of customer name succeeded");}

Now the method name is being displayed in the logging. The SourceContext adds the namespace + the class and by adding ".{Method}" it will result in:

Namespace.ClassName.MethodName


Using SeriLog with ASP.NET Core is lagging a bit behind the full .NET F/W if you are using the built-in logger factory. You can solve this by writing a series of extension methods like this:

public static class LoggerExtensions{    public static void LogAppError<T>(this ILogger<T> logger, EventId eventId, Exception exception, string message,        [CallerMemberName] string memberName = "",        [CallerFilePath] string sourceFilePath = "",        [CallerLineNumber] int sourceLineNumber = 0)    {        using (var prop = LogContext.PushProperty("MemberName", memberName))        {            LogContext.PushProperty("FilePath", sourceFilePath);            LogContext.PushProperty("LineNumber", sourceLineNumber);            logger.LogError(eventId, exception, message);        }    }}

The calling it from you code like this:

public PeopleController(ILogger<PeopleController> logger){    _logger.LogAppError("Ctor");}

This assumes that you have an output template similar to this:

private static string outputTemplate =    @"[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}Message:{Message}{NewLine}in method {MemberName} at {FilePath}:{LineNumber}{NewLine}{Exception}{NewLine}";

When you call into the extension method, the method, file, and line number are picked up by the respective attributes. Pushing a property onto the LogContext return an IDisposable that will remove that property and any property added after it. So, by wrapping the call in the using statement, once the LogError method is called on the logger, the properties are removed from the context and won't pollute any other logging calls.


In your logger configuration, you will need to enrich with the LogContext:

var logger = new LoggerConfiguration()    .MinimumLevel.Verbose()    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)    .Enrich.FromLogContext()    .WriteTo.RollingFile(        Configuration.GetValue<string>("LogFilePath") + "-{Date}.txt",         LogEventLevel.Information)    .CreateLogger();

But, to be honest, I don't recall if it logs the method name.