And yet - I still do not remember all the steps needed to get it up and running, and hence this blog - a place for me and hopefully others to go to get log4net up and running so we can get onto more important tasks.
Installation and Setup
These days I usually use nuget to install log4net. You can also get it from Apache. It consists of one dll of 292kB.The minimum steps needed to get it working are:
- Reference the log4net.dll
- Add a line to AssemblyInfo.cs
- Declare a logger in each class
- Add logging statements
- Modify the .config file as needed - this is where the magic happens!
In AssemblyInfo.cs, add the line:
[assembly: log4net.Config.XmlConfigurator(ConfigFile="log4net.config", Watch = true)]
This tells your program to call the default configurator for log4net, use the file "log4net.config", and watch the file for changes. You could leave out the ConfigFile, in which case it would use the application's app.config file. I long ago decided that I would just use the same filename "log4net.config", for all my applications. Then I can simply copy over this file anytime I needed it. So far, this has worked out well and I tend to re-use the same settings 90% of the time.
Note that if you want to use the app.config file you still need to update AssemblyInfo.cs with:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Also note that you can call the configurator explicitly in your code. I have found that this just does not work as well as declaring it in the assembly. In particular, declaring in the assembly means that you put that exact same line in assembly.cs for console, windows, ASP.NET and Service applications.
Next, let's add logging to the code. Here is the basic code:
public class MyClass {
[assembly: log4net.Config.XmlConfigurator(ConfigFile="log4net.config", Watch = true)]
This tells your program to call the default configurator for log4net, use the file "log4net.config", and watch the file for changes. You could leave out the ConfigFile, in which case it would use the application's app.config file. I long ago decided that I would just use the same filename "log4net.config", for all my applications. Then I can simply copy over this file anytime I needed it. So far, this has worked out well and I tend to re-use the same settings 90% of the time.
Note that if you want to use the app.config file you still need to update AssemblyInfo.cs with:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Also note that you can call the configurator explicitly in your code. I have found that this just does not work as well as declaring it in the assembly. In particular, declaring in the assembly means that you put that exact same line in assembly.cs for console, windows, ASP.NET and Service applications.
Using it in your code
Next, let's add logging to the code. Here is the basic code:
public class MyClass {
static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void Foo () {
log.Warn("This is a Warning message");
log.Info("This is an Info message");
log.Debug("This is Debug message");
}
}
GetLogger takes either a Type or a String. In this case, I am using reflection to get the type of "this" class.
I really like this way of doing it, since, it means that this same line can be cut and pasted into any class,
and will not need to be edited.
The log is also static, since I don't want to waste time and resources instantiating one in each instance of my class.
Next, I make calls to the logger, as in:
log.Info("This is an Info message");
Configuring log output
Log4net can be configured in the app.config file, within the code itself, or from any xml-formatted file. I like to just call my file log4net.config and be done with it.
My favorite log4net.config file can be found here. I'm not including the text directly in the interest of saving space. Feel free to copy it from GitHub!
TraceAppender
I work in Visual Studio, and so want to see my log output in the Debug Output window. The Trace Apender does that:
<appender name="TraceAppender" type="log4net.Appender.TraceAppender" >
<threshold value="DEBUG"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p %m%n" />
</layout>
</appender>
The file name is set in the <file> tag. It basically gets the name of the executable itself and the machine name. So if my program is called foo.exe, running on Bombur, the file will be named "foo.exe_Bombur.log" The file also rolls, meaning that if it exceeds a certain size, then it will rename the current log file and start a new one. You can tell it how far to back up before deleting old log files, as well as how large to let those files get. With the settings above, I generally have enough history to find recent issues, and the files are small enough to be read easily.
<appSettings>
<add key="log4net.Internal.Debug" value="false"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\log4net_internal.log"/>
</listeners>
</trace>
</system.diagnostics>
In the appsettings you tell log4net to run its internal debugging. If you run from the console you'll see many messages as log4net created repositories, adds appenders, and sets various properties. However, if you are debugging an ASP.NET application, you won't have a console. But the good news is that log4net's messages are emitted as trace calls. So you can add a tracelistener, such as a simple TextWriter in the example above. Now you'll see the messages in your log file.
This should be sufficient to find out what is going wrong.
However, if you still are getting no logs, then you can also just run from the debugger and step into the log4net code itself. It is all available in the download, and if you want to, you can even modify it yourself!
<appender name="TraceAppender" type="log4net.Appender.TraceAppender" >
<threshold value="DEBUG"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p %m%n" />
</layout>
</appender>
I generally want to see everything in this trace.ConsoleAppender
The ConsoleAppender simply outputs messages to the console. Many of my apps are console apps or have some form of console mode. There is even a color-coded console appender if you want to get fancy.
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<threshold value="INFO"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p %m%n" />
</layout>
</appender>
I generally put the threshold to Info here, so that it does not show the verbose Debug messages.
RollingFile Appender
For persistent diagnostics, you want to log to a file. But what file? What happens when the file gets large? Log4net's file naming options take care of the first question, and the RollingFileAppender takes care of the second.
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<threshold value="DEBUG"/>
<file type="log4net.Util.PatternString"
value="%appdomain_%property{log4net:HostName}.log"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level: %message%newline" />
</layout>
<rollingStyle value="Composite"/>
<datePattern value="yyyyMMdd"/>
<maxSizeRollBackups value="100"/>
<maximumFileSize value="15MB"/>
</appender>
The file name is set in the <file> tag. It basically gets the name of the executable itself and the machine name. So if my program is called foo.exe, running on Bombur, the file will be named "foo.exe_Bombur.log" The file also rolls, meaning that if it exceeds a certain size, then it will rename the current log file and start a new one. You can tell it how far to back up before deleting old log files, as well as how large to let those files get. With the settings above, I generally have enough history to find recent issues, and the files are small enough to be read easily.
Log4net Debugging
But what if you don't see any messages? This is a concern about using a 3rd party logging system. If it does not work, how will you know? The answer is that you can turn on log4net's own built-in debugging by putting the following into app.config:<appSettings>
<add key="log4net.Internal.Debug" value="false"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\log4net_internal.log"/>
</listeners>
</trace>
</system.diagnostics>
In the appsettings you tell log4net to run its internal debugging. If you run from the console you'll see many messages as log4net created repositories, adds appenders, and sets various properties. However, if you are debugging an ASP.NET application, you won't have a console. But the good news is that log4net's messages are emitted as trace calls. So you can add a tracelistener, such as a simple TextWriter in the example above. Now you'll see the messages in your log file.
This should be sufficient to find out what is going wrong.
However, if you still are getting no logs, then you can also just run from the debugger and step into the log4net code itself. It is all available in the download, and if you want to, you can even modify it yourself!