6

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

itmannz
  • 529
  • 9
  • 19

2 Answers2

4

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

C. Augusto Proiete
  • 24,684
  • 2
  • 63
  • 91
  • worth showing [`CallerMethodName`](https://stackoverflow.com/a/9621581/11635) in a helper tagged with `MethodImplOption.NoInlining` in your last example – Ruben Bartelink Sep 25 '18 at 06:22
0

Another workaround could be a custom middleware, that adds information you want to the messages without altering the logger itself and it works with other loggers also.

using System;
using System.Diagnostics;
using Serilog;

public static class LogMiddleware
{
  public static string From()
  {
      var methodInfo = new StackTrace().GetFrame(1).GetMethod();
      var className = methodInfo.ReflectedType.Name;
      var callingMethod = methodInfo.Name;
      return $"| [Class: {className}] | [Method: {callingMethod}] |";
  }

  public static void Info(this string callerInfo, string message)
  {
      Log.Information($"{callerInfo} -- {message}");            
  }


  public static void Error(this string callerInfo, string message, Exception exception)
  {
      Log.Error(exception, $"{callerInfo} -- {message}");
  }

  public static void Error(this string callerInfo, string message)
  {
      Log.Error($"{callerInfo} -- {message}");
  }
}

Usage

using LOG = Middleware.LogMiddleware; 

.
.
.

public void MyMethod()
{
   LOG.From().Info("my information");
}

Output:

2022-06-22 12:09:13.328 +03:00 [INF] | [Class: MyClass] | [Method: MyMethod] | -- my information
tataelm
  • 679
  • 8
  • 17