Search code examples
c#castingserilog

Create a wrapper for Serilog


I'm using Serilog. To avoid configuration in each microservice I create a private NuGet package with extension like

namespace DFX.Logging
{
    public static class Extensions
    {
        public static IWebHostBuilder UseLogging(this IWebHostBuilder webHostBuilder) =>
            webHostBuilder.UseSerilog((context, loggerConfiguration) =>
            {
                var logLevel = context.Configuration.GetValue<string>("Serilog:MinimumLevel");
                if (!Enum.TryParse<LogEventLevel>(logLevel, true, out var level))
                {
                    level = LogEventLevel.Information;
                }

                loggerConfiguration.Enrich
                    .FromLogContext()
                    .MinimumLevel.Is(level);

                loggerConfiguration
                    .ReadFrom.Configuration(context.Configuration)
                    .WriteTo.Console(
                        theme: AnsiConsoleTheme.Code,
                        outputTemplate: "[{Timestamp:yy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} <s:{SourceContext}>{NewLine}{Exception}");
            });
    }
}

in controller (or somewhere else) I create logger

private readonly ILogger _logger = Log.ForContext<Application>();

for that I need to add using using Serilog;. I want to avoid it and use only my namespace using DFX.Logging;. How can I rich that? What I have tried so far:

namespace DFX.Logging
{
    // custom wrapper
    public static class Log
    {
        public static ILogger ForContext<TSource>()
        {
            return (ILogger)Serilog.Log.ForContext<TSource>();
        }
    }

    public interface ILogger : Serilog.ILogger
    {
    }
}

Then the code compile successfully but at the runtime I got

'Unable to cast object of type 'Serilog.Core.Logger' to type 'DFX.Logging.ILogger'.'

I realize that I can't cast Serilog.Core.Logger to my logger because Serilog.Core.Logger not implement DFX.Logging.ILogger, but how it can be implemented?


Solution

  • The short answer is: You can't. At least not as easily as how you are thinking.

    If you really want to go this route, some options could be:

    • Create your own static LoggerProxy class that implements your ILogger interface, and wraps an instance of Serilog's ILogger by ... writing the C# code
    • Create a dynamic LoggerProxy (a.k.a. LoggerInterceptor) class that gets generated during runtime, using something like Castle.DynamicProxy or LinFu.DynamicProxy
    • Modify Serilog's code to implement your interface, and recompile it
    • Modify Serilog's assembly via .NET IL Weaving, for example, using a Fody extension, to implement your interface