4

In the WriteTo.Observer method I want to pass the formatted log message as it is rendered using the formatting template. How might I accomplish that?

class Program
{
    static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.LiterateConsole()
            .WriteTo.RollingFile("log-{Date}.txt")
            .WriteTo.Observers(events => events.Do(evt => { Console.WriteLine($"Observed event {evt.MessageTemplate.Text}"); }).Subscribe())
            .WriteTo.Observers(events => events.Do(evt => { LogHandler(evt.MessageTemplate.Text);}).Subscribe())
            .CreateLogger();

        Log.Logger.Information("Log msg from Main");
        Console.ReadLine();
    }

    public static void LogHandler(string logMsg)
    {
        Console.WriteLine("LogHandler: " + logMsg); //I want the complete formatted log message as it would appear in a file i.e. "[10:20:14 INF] Log msg from DoNothing"
    }
}
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122

1 Answers1

12

I managed to resolve this all by myself as well as a couple of other questions I had about Serilog.

I originally posted this question about NLog and in the process of resolving it I discovered Serilog. I'm glad I did.

This answer illustrates several concepts:

1.) Calling a custom handler from the Logger

2.) Formatting the log message

3.) Including calling method name in the log message. Thanks and credit go to @MovGP0 for his answer found here.

class Program
{
    static void Main(string[] args)
    {
        var outputTemplate = "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}in method {MemberName} at {FilePath}:{LineNumber}{NewLine}{Exception}{NewLine}";
        Serilog.Formatting.Display.MessageTemplateTextFormatter tf = new Serilog.Formatting.Display.MessageTemplateTextFormatter(outputTemplate, CultureInfo.InvariantCulture);

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.CustomSink(tf, LogHandler)
            .CreateLogger();

        Log.Logger.Here().Information("Hello world");
        Console.ReadLine();
    }

    public static void LogHandler(string logMsg)
    {
        Console.WriteLine("LogHandler: " + logMsg); 
    }
}


public class CustomSink : ILogEventSink
{
    private readonly ITextFormatter _formatter;
    private readonly Action<string>[] _handlers;

    public CustomSink(ITextFormatter formatter, params Action<string>[] handlers)
    {
        _formatter = formatter;
        _handlers = handlers;
    }

    public void Emit(LogEvent logEvent)
    {
        var buffer = new StringWriter(new StringBuilder(256));
        _formatter.Format(logEvent, buffer);
        string message = buffer.ToString();

        foreach (Action<string> handler in _handlers)
            handler(message);
    }
}


public static class MySinkExtensions
{
    public static LoggerConfiguration CustomSink(
              this LoggerSinkConfiguration loggerConfiguration,
              ITextFormatter formatter = null, params Action<string>[] handlers)
    {
        return loggerConfiguration.Sink(new CustomSink(formatter, handlers));
    }


    public static ILogger Here(this ILogger logger,
    [CallerMemberName] string memberName = "",
    [CallerFilePath] string sourceFilePath = "",
    [CallerLineNumber] int sourceLineNumber = 0)
    {
        return logger
            .ForContext("MemberName", memberName)
            .ForContext("FilePath", sourceFilePath)
            .ForContext("LineNumber", sourceLineNumber);
    }

}
ahsteele
  • 26,243
  • 28
  • 134
  • 248