Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

log4net with DI Simple Injector

I am trying to use Simple Injector ( + integration MVC) v 2.5.2. for an MVC 4 Application and I need to track/log performance (execution) as well(by log4net module). Current implementation (during runtime) creates log4net file in specified path but did not write any line of text into it (when I debug it everything went with no error to the end of _logger.Info("message") ).

Does anyone try to use Simple Injector DI for log4net?

The way how I've registered log4net module is:

public static class LoggingModule
{
    public static void RegisterServices(Container container)
    {
        string log4NetConfigFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config");
        log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(log4NetConfigFile));
        var logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        container.RegisterSingle(logger);

    }
}

And in Global.asax

LoggingModule.RegisterServices(container);

Log4net configuration file looks like so (I dont think there is any problem):

<log4net>
  <appender name="PerformanceLogFile" type="log4net.Appender.RollingFileAppender" >
  <param name="File" value="..\Performance\PricingManager" />
  <param name="AppendToFile" value="true" />
  <param name="RollingStyle" value="Date" />
  <param name="DatePattern" value="_yyyy-MM-dd.lo\g" />
  <param name="MaxSizeRollBackups" value="10" />
  <param name="StaticLogFileName" value="false" />
  <layout type="log4net.Layout.PatternLayout">
    <param name="ConversionPattern" value="%m%n"/>
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <param name="LevelMin" value="INFO" />
    <param name="LevelMax" value="FATAL" />
  </filter>
  </appender>
  <logger name="SoftTech.PricingEngine.PricingService.PerformanceStatisticLoggerWithAPI">
    <level value="ALL" />
    <appender-ref ref="PerformanceLogFile" />
  </logger>
</log4net>

And to turn on/off logging I've been using:

private static void RegisterIPerformanceStatisticLogger(Container container)
    {
        if (ShouldLogPerformance())
        {
            container.Register<IPerformanceStatisticLogger, PerformanceStatisticLogger>(WebLifestyle); 
        }
        else
        {
            // do nothing
            container.Register<IPerformanceStatisticLogger, DisabledPerformanceStatisticLogger>(WebLifestyle); 
        }
    }

And PerformanceStatisticLogger or DisablePerformanceStatisticLogger sets

IsLoggingEnabled = true; // | false
IsAPITraceEnabled = false; // | true

What I am doing wrong? Seems to me the problem of the way of injection. Thanks for any advice

like image 857
st35ly Avatar asked Aug 04 '14 05:08

st35ly


1 Answers

There's nothing special about Simple Injector when it comes to configuring log4net. For instance, you can register ILog as follows:

container.RegisterSingleton<ILog>(LogManager.GetLogger(typeof(object)));

Obviously this registered a single logger for the complete application. In case you want to inject a different logger per class, you will have to define your own adapter implementation:

public sealed class Log4NetAdapter<T> : LogImpl
{
    public Log4NetAdapter() : base(LogManager.GetLogger(typeof(T)).Logger) { }
}

You can register this adapter as follows:

container.RegisterConditional(typeof(ILog),
    c => typeof(Log4NetAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

This ensures that each consumer gets its own Log4NetAdapter<T> implementation.

Do note though that IMO it's much better to prevent application code to take a dependency on 3rd party library abstractions. I think it's much better to define you own logger abstraction.

My experience with log4net is that when log4net doesn't log anything, there's something wrong with your log4net configuration. What I hate about log4net is that it never throws any exceptions when you misconfigured it. It just swallows and continues, which makes working with log4net much more painful than it should be.

One thing that can help is hooking onto the LogLog.LogReceived event of log4net at startup. This allows you to check if there are any errors. For instance this is the code I used in a previous project:

LogLog.LogReceived += (s, e) =>
{
    if (e.LogLog.Prefix.Contains("ERROR"))
    {
        throw new ConfigurationErrorsException(e.LogLog.Message,
            e.LogLog.Exception);
    }
};

This makes sure your application directly stops with a clear exception when log4net is misconfigured.

like image 179
Steven Avatar answered Nov 15 '22 20:11

Steven