Search code examples
c#serilogserilog-sinks-file

How to log the classPath, methodName and lineNumber with Serilog in C#


I want to print log to file from my system (.NET Framework 4.6.1) I want to print this information: className, methodName, lineNumber from which log entry was Called.

I've a Serilog class: `

    public class SerilogClass
    {
        public static readonly ILogger _log;
        static SerilogClass()
        {
            string logsFolder = ConfigurationManager.AppSettings["logsFolder"];
            string environment = ConfigurationManager.AppSettings["environment"];
            _log = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .WriteTo.File(logsFolder + "//" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".log", outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:Ij}{NewLine}{Exception}")
                    .CreateLogger();
        }
    }

I'm trying to document the system with logs:

 public class MyClass
    {
        private readonly ILogger _log = SerilogClass._log;

        public void GetData()
        {
             _log.information("run GetData, **here I want to print by default the class path and the line number**")
        }
    }

What should I add in SerilogClass? I would be happy to advices. Thanks.


Solution

  • To automatically log the class name, method name, and line number in Serilog, you can use the Serilog.Enrichers.StackTrace NuGet package.

    public class SerilogClass
    {
        public static readonly ILogger _log;
        static SerilogClass()
        {
            string logsFolder = ConfigurationManager.AppSettings["logsFolder"];
            string environment = ConfigurationManager.AppSettings["environment"];
            _log = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .Enrich.WithDemystifiedStackTraces() // Add this to enrich with stack trace information
                    .WriteTo.File(
                        path: Path.Combine(logsFolder, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"),
                        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext}.{Method}({LineNumber}): {Message:lj}{NewLine}{Exception}")
                    .CreateLogger();
        }
    }
    
    public class MyClass
    {
        private readonly ILogger _log = SerilogClass._log.ForContext<MyClass>();
    
        public void GetData()
        {
            _log.Information("Run GetData");
        }
    }
    

    Below is an example of how a log entry might look when using Serilog configured with the Serilog.Enrichers.StackTrace:

    [15:42:01 INF] MyNamespace.MyClass.GetData(42): Run GetData
    

    To automatically log the class name, method name, and line number without the need for external packages like Serilog.Enrichers.StackTrace as Blindy said, you can use the compiler services features provided by C# such as CallerMemberName, CallerFilePath, and CallerLineNumber.

    Example:

    public static class SerilogExtensions
    {
        public static void LogWithDetailedInfo(
            this ILogger logger,
            string message,
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
        {
            var className = Path.GetFileNameWithoutExtension(sourceFilePath);
            logger.Information("{ClassName}.{MemberName}({LineNumber}): {Message}", className, memberName, sourceLineNumber, message);
        }
    }
    
    public static class SerilogClass
    {
        public static readonly ILogger Log;
    
        static SerilogClass()
        {
            string logsFolder = "path_to_logs_folder"; // Update with your configuration method
            string environment = "development"; // Update with your configuration method
            Log = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .WriteTo.File(
                        path: Path.Combine(logsFolder, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"),
                        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
                    .CreateLogger();
        }
    }
    
    public class MyClass
    {
        private readonly ILogger _log = SerilogClass.Log.ForContext<MyClass>();
    
        public void GetData()
        {
            _log.LogWithDetailedInfo("Run GetData");
        }
    }