2

Autofac has log4net Integration Module called LoggingModule.

However, I register Logger to ILog manually without using LoggingModule, and it seems working fine.

ILog log = LogManager.GetLogger("Logger");
builder.RegisterInstance(log).As<ILog>().SingleInstance();

My question is - what is the disadvantage/side effect of using above approach instead of using LoggingModule.

web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="mylogfile.txt" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="5" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="RollingFileAppender" />
    </root>
  </log4net>
</configuration>

Global.asax.cs

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace DemoLog4NetAuftofac
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            var builder = new ContainerBuilder();

            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            ILog log = LogManager.GetLogger("Logger");
            builder.RegisterInstance(log).As<ILog>().SingleInstance();

            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

HomeController

namespace DemoLog4NetAuftofac.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(ILog log)
        {
            log.Debug("Debug application");
            log.Error("Error application");
            log.Info("Info application");
        }
    }
}

Version

  <package id="Autofac" version="3.4.0" targetFramework="net45" />
  <package id="Autofac.Mvc5" version="3.3.4" targetFramework="net45" />
  <package id="log4net" version="2.0.3" targetFramework="net45" />
Win
  • 61,100
  • 13
  • 102
  • 181

2 Answers2

3

The LoggingModule provided by Autofac is an advanced sample of a custom Module.

The only difference between this module and a custom registration is that the module will use different ILog instance for each type where it is injected whereas in your code, you will only use one instance of ILog.

For example :

public class Foo
{
    public Foo(ILog log)
    { 
        Console.WriteLine(log.Logger.Name);
    }
}
public class Bar
{
    public Bar(ILog log)
    { 
        Console.WriteLine(log.Logger.Name);
    }
}

With your custom registration log injected to Foo and Bar will be the same and they will be the result of LogManager.GetLogger("Logger"). If you use the LoggingModule log will be the result of LogManager.GetLogger(typeof(Foo)) for Foo and LogManager.GetLogger(typeof(Bar)) for Bar.

Having different instance of ILog will help you filtering log for a specific type and things like that.

Your registration has no problem but using the LoggingModule will allow you to filter or specify log level for some class or namespace.

By the way, I recommend you to read the LoggingModule source code, it is not really difficult and it will help you better understand how Module and Parameter works with Autofac.

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
3

I would even go as far and say that injecting ILog directly in your code is wrong. Even though ILog is an abstraction, you will still be violating the Dependency Inversion Principle, because:

In a direct application of dependency inversion, the abstracts are owned by the upper/policy layers

while in your case the ILog abstraction is owned by a lower layer (the external log library).

This is bad because such abstraction in general is defined in a way that pleases the framework - not your code. It therefore pollutes your code and besides that, it makes your code still take a hard dependency on the external library. This makes it harder to replace the logging library with a different one later on.

But in the case of log4net it gets even worse, because the ILog interface is a big Interface Segregation Principle violation, because it contains 40 members. This makes the API much more complex than required and makes it much harder to mock implementation.

Instead, you would be much better of creating a application-specific abstraction for logging (with preferably one member as this example shows). When you defined a logging abstraction with one member, it will be trivial to create an adapter for log4net, Enterprise Library Logging Application Block, ELMAH or any other logging library you can think of.

And don't forget to ask yourself: Do I log too much?

Steven
  • 166,672
  • 24
  • 332
  • 435