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);
}
}