1

I've got a C# (.NET 3.5) application that extensively use log4net. The log4net configuration resides in the app.config file.

Configuration is done using [assembly: XmlConfigurator(Watch = true)] in AssemlyInfo.cs App uses single application-wide logger instance, instantiated in a static constructor of a logger wrapper class:

public class Logger{
    //....
    private static readonly ILog logger;
    static Logger()
    {
        logger = LogManager.GetLogger(Assembly.GetEntryAssembly().GetName().Name);

        AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
    }
    //....
}

The app is designed to be run on distant server, by scheduler, with no human presense, alone in the dark. :) The problem is, in case of missing config file it just silently crashes (no log4net config => no logging).

Are there any way to check if there are any appenders in the config, and if not - programmatically add some kind of fallback appender.

I'm rather new to log4X loggers family, so, if I'm asking something trivial - please be kind, log4net documentation is really awful. :)

J0HN
  • 26,063
  • 5
  • 54
  • 85
  • 1
    It's possible to manipulate the Log, take a look at this answer: http://stackoverflow.com/questions/1519728/programmatically-adding-and-removing-log-appenders-in-log4net – Thinhbk Jun 27 '12 at 11:29
  • Test for the existence of the config file. If it doesn't exist, create your logger in code - http://stackoverflow.com/questions/1436713/cant-configure-log4net-in-code. Alternatively, package the log4net config with the app as an embedded resource so it can never go missing. Or just make sure you always ship the config with the app ;-) – dash Jun 27 '12 at 12:09

1 Answers1

0

Ok, the question already on google, and I've found the answer, so I'll just left it here. :)

The key to manipulating appenders is a IAppenderAttachable interface, since it implements AddAppender, removeAppender methods.

What's returned by LogManager.GetLogger() is an instance of ILog, which in turn contains property Logger. The object returned by the ILog.Logger is a Logger class instance. Logger class implements IAppenderAttachable interface and contains Repository property to extract repository of the logger. Repository has method GetAppenders that returns AppenderCollection class instance (implements ICollection, IList, Ienumerable, etc.) with all the active appenders of the logger.

To sum up:

//no need to put it in the static constructor, but in my case it is so
static Logger() 
{
    logger = LogManager.GetLogger(...);
    if (logger.Logger.Repository.GetAppenders().Length == 0) {
        (logger.Logger as IAppenderAttachable).AddAppender(CreateConsoleAppender());
    }
}

private static ConsoleAppender CreateConsoleAppender()
{
    var appender = new ConsoleAppender();
    appender.Layout = CreateDefaultLayout();
    appender.AddFilter(CreateDefaultFilter());
    appender.ActivateOptions(); // if omitted - throws an excpetion
    log4net.Config.BasicConfigurator.Configure(appender); //if omitted - no errors, but logging does not work
    return appender;
}

private static ILayout CreateDefaultLayout()
{
    PatternLayout layout = new PatternLayout();
    layout.ConversionPattern = "%d{yyyy-MM-dd hh:mm:ss} - %level %m%n";
    layout.ActivateOptions();
    return layout;
}


private static IFilter CreateDefaultFilter()
{
    LevelRangeFilter filter = new LevelRangeFilter { LevelMin = Level.Info };
    filter.ActivateOptions();
    return filter;
}

Note that in case of missing or corrupted file log4net does not throw any exceptions (at least out of the box), but have no appenders attached to logger.

J0HN
  • 26,063
  • 5
  • 54
  • 85
  • Thanks for providing this. Just few notes: The line `log4net.Config.BasicConfigurator.Configure(appender);` need probably just to signal to repository that it is configured. It may also probably add unnecessary appender to Root appender if called multiple times (in your case this was not a case, since you use static). You may just add line `logger.Logger.Repository.Configured = true;` just after `(logger.Logger as IAppenderAttachable).AddAppender(CreateConsoleAppender());`. Hope this helps anyone to understand this part of code. – Serge Ageyev Feb 28 '20 at 09:03