Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serilog Logging with ClassName, Method Name

I am using serilog and SEQ in my project Angular,web api, EF. I am new to both.

1) How can I make sure every time I write error, information, debug it should contain ClassName.Method Name. I know I have to create Enrich but not sure how to get ClassName.Method Name

for example

Class Test
{
  public void testing(){
  // logger.Error("Error ....");}
}

Now,when I see the log it should display "29/09/2012 10:00:00, Test=>testing Error ....."

In, short DateTime, ClassName , MethodName and Message

like image 873
itmannz Avatar asked Sep 24 '18 06:09

itmannz


Video Answer


1 Answers

To get the method name automatically on every logging call, you'll have to use an enricher that reflects over the call stack (which is very expensive to do) to capture the method name.

Here is an example written by @nblumhardt: https://github.com/serilog/serilog/issues/1084#issuecomment-358117004

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;

namespace ConsoleApp24
{
    class CallerEnricher : ILogEventEnricher
    {
        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            var skip = 3;
            while (true)
            {
                var stack = new StackFrame(skip);
                if (!stack.HasMethod())
                {
                    logEvent.AddPropertyIfAbsent(new LogEventProperty("Caller", new ScalarValue("<unknown method>")));
                    return;
                }

                var method = stack.GetMethod();
                if (method.DeclaringType.Assembly != typeof(Log).Assembly)
                {
                    var caller = $"{method.DeclaringType.FullName}.{method.Name}({string.Join(", ", method.GetParameters().Select(pi => pi.ParameterType.FullName))})";
                    logEvent.AddPropertyIfAbsent(new LogEventProperty("Caller", new ScalarValue(caller)));
                }

                skip++;
            }
        }
    }

    static class LoggerCallerEnrichmentConfiguration
    {
        public static LoggerConfiguration WithCaller(this LoggerEnrichmentConfiguration enrichmentConfiguration)
        {
            return enrichmentConfiguration.With<CallerEnricher>();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .Enrich.WithCaller()
                .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message} (at {Caller}){NewLine}{Exception}")
                .CreateLogger();

            Log.Information("Hello, world!");

            SayGoodbye();

            Log.CloseAndFlush();
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        static void SayGoodbye()
        {
            Log.Information("Goodbye!");
        }
    }
}

Another alternative (if you only want to capture the method name in specific/more important places), is to create an extension method that you can call, which will add the method name to the logging context... E.g.

Logger.Here().Information("Hello, world!");

You can see an example of how to implement this Here method on a different question here on StackOverflow: https://stackoverflow.com/a/46905798

like image 153
C. Augusto Proiete Avatar answered Oct 22 '22 18:10

C. Augusto Proiete