Back to top

Moving from Serilog to ILogger in an existing .NET Framework

I love Serilog and have been using it for many years, in the past together with Seq (these days I mostly just use Application Insights).

However, for most recent projects I have found tha the Microsoft logging library provides enough functionality out of the box, and is very simple to setup and go with.

We’re moving from .NET Framework from .NET Core, and all our class libraries that are now targetting .NET Standard are still using Serilog for logging, as is our .NET Framework app.

In the .NET Core app, we want to use ILogger instead, and so we need all those class libraries to be updated to use ILogger instead.

I was delighted to learn that the Microsoft.Extensions.Logging library CAN be used in .NET Framework apps (version 4.6.2 and up), so I set about to use this as a way to allow the class libraries to use ILogger so that this could just be “handled” appropriately from whichever app was using them.

We are using StructureMap for our IoC, so these instructions are for that, but it should be faily easily converted to whatever tool you are using.

Failed attempt: direct use of ILogger

I did try achieve a full migration from Serilog to ILogger in the .NET Framework. However I had issues with this because no matter what I did, I couldn’t get it to be initialised in a way that “tied in” to the existing telemetry config, and it was always missing the Operation Id, Operation Name, etc in what it logged to App Insights. As a result, I was ending up with “orphaned” traces.

I will admit to having lost a few hours to this, before finally giving up.

We also didn’t want to have to update ALL our existing .NET Framework code at this stage to use ILogger, since we’re only going to be migrating it and throwing it away soon. So we did want to keep the existing Serilog code working for now.

The solution: let Serilog provide the ILogger logger in the Framework application

  • First, and I’m not totally sure if this was necessary to get this working, I upgraded Serilog to the latest version, which at the time of writing is 4.0.1. We were still on 2.11.0 before that.

  • Install the package Serilog.Extensions.Logging

    install-package Serilog.Extensions.Logging
    
  • In the DefaultRegistry for StructureMap, I create a LoggerFactory and called AddSerilog on it, and configured the dependency injection settings for ILogger.
    public class DefaultRegistry : Registry {

        public DefaultRegistry() {
            Scan(
                scan => {
                    scan.TheCallingAssembly();
                    scan.WithDefaultConventions();
            scan.With(new ControllerConvention());
                });

            // .... etc ....

            var loggerFactory = new LoggerFactory();
            loggerFactory.AddSerilog();

            For<ILoggerFactory>().Use(loggerFactory);
            For(typeof(ILogger<>)).Use(typeof(Logger<>));

        }
    }
    
  • In the class libraries, make the change to inject the ILogger using DI, and then use this for logging, for example:
        using Microsoft.Extensions.Logging;

        namespace MyNamespace
        {
            public class MyClass
            {
                private readonly ILogger<MyClass> _logger;

                public MyClass(ILogger<MyClass> logger)
                {
                    _logger = logger;
                }

                public void DoAThing()
                {
                    _logger.LogInformation("MyClass is doing a thing.");
                }
            }
        }
    
  1. And then in my Controllers and other classes in the .NET Framework project, I can choose to inject ILogger if I want to (but I’ll probably continue to just use the existing Serilog Log.Logxxxxx code for now)

Should we be using Serilog moving forward, anyway?

This is a question that I’m not 100% sure on the answer to yet. But for now, since we are no longer using any sinks other than App Insights (no file logged, console etc), I see no need for the extra overheads.

Next steps

So the next steps now are:

  • update all class libraries to use ILogger instead of Serilog, using dependency injection to get access to the Logger
  • eventually the .NET Framework app will fully migrated, and we will just no longer be using Serilog
  • if we do decide we want to use Serilog in the .NET Core app moving forward, then we could add that as an abstraction over the top of the ILogger code at that time.