8

Recencely I discoverd serilog ( structured logging for .net ) and saw a lot of its advantages. But I face some problems with it. I have 4 projects, one is web, one is infrastructure and the other two are windows services, I want to declare serilog configuration once and use it multiple times. And also I want to use it with dependency injection. I have been searching web for three days now, but I did not find any thing useful, please some one help me.

For example I want this class to be my logging class.

public interface IMyLogger
{
    void Information(string message, object[] parameters);
}

public class MyLogger : IMyLogger
{
    public MyLogger()
    {
    }
    public void Information(string message, object[] parameters)
    {
        Log.Information("LogType : {LogType} - Operation : {Operation}", parameters);
    }
}
public class UserClass
{
private readonly IMyLogger _myLogger;
public UserClass(IMyLogger myLogger)
        {
            _myLogger = myLogger;
        }
}

Now I don't know where I should put this line of code:

Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();

Tnx in advance.

jsDevia
  • 1,282
  • 4
  • 14
  • 37

1 Answers1

7

First off, in your Unity configuration, to get Serilog resolving properly, you need to use an InjectionFactory, like this:

        container.RegisterType<ILogger>(new ContainerControlledLifetimeManager(), new InjectionFactory((ctr, type, name) =>
        {
            ILogger log = new LoggerConfiguration()
                .WriteTo.Console() //Your serilog config here
                .CreateLogger();

            return log;
        }));   

In my implementation I'm not abstracting Serilog, but the code above is the missing link in any case. IMyLogger just needs to parameter inject ILogger, and everything will work itself out.

That solves the MVC part: you can inject IMyLogger into your controllers in MVC.

Which brings us to where to locate this in your solution. Because of your needs regarding services, you probably need to have a separate Inversion of Control project (MySolution.InversionOfControl) that contains your bindings. Then, for instance in your web site's UnityWebActivator.cs, you can do something like this:

    /// <summary>Integrates Unity when the application starts.</summary>
    public static void Start() 
    {
        //This is the important part:
        var container = UnityConfig.GetConfiguredContainer(); //This is a static class in the InversionOfControl project.

        //This is generic:
        FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
        FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }

Do the same for your services, and you should be good to go!

Brian MacKay
  • 31,133
  • 17
  • 86
  • 125
  • This works nicely. I noticed though that the default lifetime manager if none specified in Unity 4.0.1 is the transient lifetime manager. Which means that every call to resolve the ILogger is going to execute the injection factory and returna new instance. I believe the logger should use ContainerControllerLifetimeManager instead? – Sudhanshu Mishra May 11 '16 at 00:44
  • @dotnetguy Better late than never, I am updating this now. :) – Brian MacKay Mar 16 '17 at 13:16
  • 2
    For everyone else: ContainerControllerLifetimeManager does the best job of mimicking the singleton behavior Serilog was intended for. Other lifetime managers work, but this might be slightly more efficient than creating a new Serilog instance for each request. – Brian MacKay Mar 16 '17 at 13:42
  • 1
    ContainerControlledLifetimeManager and HierarchicalLifetimeManager are the only ones that call the dispose method. So, using anything else may affect your flushing of the log. Like @BrianMacKay, I also think container controlled is better for SeriLog. – MIWMIB May 22 '18 at 02:11
  • How do you go about configuring the logger (such as minimum level) through the factory? There's a weird catch 22 here. I use a command line parameter to determine if debug logging is enabled or not. However, processing command line arguments happens after the composition root is set up. But I need that input argument to configure the `LoggerConfiguration` to use a minimum level of debug or info. – void.pointer Mar 14 '21 at 01:09
  • @void.pointer Wow... That sounds like a new question. Maybe there's some way to change the logger's logging level later in the lifecycle? This is a super old answer by the way, this is not how I use Serilog in 2021. Haven't even used Unity in years. – Brian MacKay Mar 15 '21 at 11:53
  • By not using Unity does that mean you don't use DI containers at all? Or you just prefer a different implementation? – void.pointer Mar 15 '21 at 18:39
  • @void.pointer Well, in .NET Core MVC got its own DI container. So I've been using that. – Brian MacKay Mar 16 '21 at 00:26