I've got an assembly in which I use log4net. I load this assembly into both Windows forms applications and console applications. It works as expected in Windows forms apps in both release and debug builds, and console apps in debug builds, but mysteriously fails for release builds of console apps.
I have the following in my AssemblyInfo.cs file:
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension="log4net", Watch = true)]
In classes that use logging I include the following member variable declaration:
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
And my Library.dll.log4net configuration file looks as follows:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="Library.log" />
<appendToFile value="true" />
<rollingStyle value="Once" />
<maxSizeRollBackups value="5" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
I've tried the suggestions in this article (Log4Net doesn’t write log in release mode - Console Application) but they don't seem to help.
I've also tried programmatically turning on internal debugging as soon as possible in the assembly (in the constructor of the first object referenced) but that also has no effect.
Any other ideas? Can anyone spot what I'm doing wrong?
As it states in the documentation for assembly configuration attributes:
Therefore if you use configuration attributes you must invoke log4net to allow it to read the attributes. A simple call to LogManager.GetLogger will cause the attributes on the calling assembly to be read and processed. Therefore it is imperative to make a logging call as early as possible during the application start-up, and certainly before any external assemblies have been loaded and invoked.
As the compiler is freer to reorganise things in Release builds, it seems likely that it's optimised something and the assembly attribute isn't being picked up soon enough.
If this is the case, a simple explicit logging call in the startup program will force log4net to load the configuration:
LogManager.GetLogger("Startup").Debug("This logging call loads the configuration");
However, this can still be problematic, for example with some web apps or if (as in comments) the startup application doesn't reference log4net: in those cases you must use an explicit call to the configuration system instead of the assembly attribute. It only needs to be called once.
For standalone log4net config files:
XmlConfigurator.Configure(new FileInfo(path_to_config));
For config in a configSection in web.config or app.config
XmlConfigurator.Configure();