|
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>log4net Configuration Demystified</title>
<style> H1, H2, H3, H4, H5, TH { font-weight: bold; }
H2, H3, H5 { color: #ff9900; }
H1 { font-size: 16pt; }
H2 { font-size: 13pt; }
H3 { font-family: Arial, sans-serif; font-size: 11pt; }
H4 { font-size: 10pt; margin-top: 2px; margin-bottom: 0px; }
H5 { font-size: 9pt; font-weight: bold; margin-bottom: 2px; }
H6 { color: #626262; font-size: 65%; font-weight: normal; }
CODE { color: #990000; font-family: "Courier New", Courier, mono; }
PRE { background-color: #FBEDBB; padding: 7pt; background-image: url(/images/codebg.gif); font: 9pt "Courier New", Courier, mono; white-space: pre; width: 100%; /*overflow: auto;*/ }
TD { font: 9pt "Arial"; }
.table table {
border-collapse:collapse;
font-size:100%;
width:90%;
}
.table th {
background-color:#CCCCCC;
border:1px solid #999999;
color:black;
font-weight:bolder;
padding:5px;
}
.table tr {
background-color:inherit;
border:1px solid #999999;
color:black;
padding:5px;
text-align:left;
}
.table td {
border:1px solid #999999;
padding:5px;
}
</style>
</head>
<body>
<h2>
Contents</h2>
<ul>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#Definitions">Definitions</a></li>
<li><a href="#objects">How the objects relate to each other.</a></li>
<li><a href="#Configuration">The Configuration</a></li>
<ul>
<li><a href="#Appender_Configuration">Appender Configuration</a></li>
<li><a href="#Appender_Loggers">Assigning Appenders to Loggers</a></li>
</ul>
<li><a href="#Summary">Summary</a></li>
<li><a href="#History">History</a></li>
<li><a href="#References">References</a></li>
</ul>
<h2>
<a name="Introduction">Introduction</a></h2>
Many of us from time to time have struggled with configuring log4net. I know that
in just about every application that I have worked on, I have taken a log4net configuration
file, copied it and changed it to my liking. Well after some research and fiddling
around with the configuration options available in log4net, I have come up with
some interesting discoveries.
<br />
<br />
The first is that we can easily create separate log file / appenders for each class,
assembly or even namespace if we want. Before I give you the answer, I want to tell
you a little bit about the log4net library.<br />
<h2>
<a name="Definitions">Definitions</a></h2>
log4net is essentially made up of six objects: <code>log4net</code>, <code>log4net.Appender</code>,
<code>log4net.Config</code>, <code>log4net.Filter</code>, <code>log4net.Layout</code>
and <code>log4net.Repository</code>. Here are there definitions.
<ul>
<li><code>ILog</code> interface is what is used for logging messages.</li>
<li><code>LogManager</code> is used to keep record of all of the loggers. A logger is
an object that wants to log some data.</li>
<li><code>Appender</code> is an object that writes log data to some data store, application
or library.</li>
<li><code>Filter</code> is an condition that can be applied to a Appender to restrict
the writing of log data.</li>
<li><code>Layout</code> is the display formatting that will be used for the log data
when it is written to the appender.</li>
<li><code>Repository</code> is the central store for the log4net configuration and LogManager.</li>
</ul>
<h2>
<a name="objects">How the objects relate to each other.</a></h2>
Each repository has one <code>LogManager</code>. Each <code>LogManager</code> has
one or more Loggers. Each logger has one or more Appenders. Each Appender has one
or more filters and one layout.<br />
<br />
<img src="log4net_objects.gif" />
<br />
<h2>
<a name="Configuration">The Configuration</a></h2>
The easiest and most flexible way to configure log4net is with XML files. log4net
provides a configuration reader for XML files in the <code>log4net.Config.XmlConfigurator</code>class.
The XML file is comprised of 2 parts (that I know of). The first is one or more
Appender definitions, the second defines the loggers and what Appender definitions
to a logger in the repository.
<br />
<p>
The <code><log4net></code> element supports the following attributes:
</p>
<div class="table">
<table cellspacing="0">
<colgroup>
<col style="width: 7em; white-space: nowrap; text-align: left" />
<col style="text-align: left" />
</colgroup>
<tr>
<th style="width: 7em">
Attribute</th>
<th>
Description</th>
</tr>
<tr>
<td style="width: 7em">
debug</td>
<td>
Optional attribute. Value must be either <code>true</code> or <code>false</code>.
The default value is <span class="code">false</span>. Set this attribute to <code>true</code>
to enable internal log4net debugging for this configuration.
</td>
</tr>
<tr>
<td style="width: 7em">
update</td>
<td>
Optional attribute. Value must be either <code>Merge</code> or <code>Overwrite</code>.
The default value is <span class="code">Merge</span>. Set this attribute to <code>Overwrite</code>
to reset the configuration of the repository being configured before applying this
configuration.
</td>
</tr>
<tr>
<td style="width: 7em">
threshold</td>
<td>
Optional attribute. Value must be the name of a level registered on the repository.
The default value is <code>ALL</code>. Set this attribute to limit the messages
that are logged across the whole repository, regardless of the logger that the message
is logged to.
</td>
</tr>
</table>
</div>
<p>
The <code><log4net></code> element supports the following child elements:
</p>
<div class="table">
<table cellspacing="0">
<colgroup>
<col style="width: 7em; white-space: nowrap; text-align: left" />
<col style="text-align: left" />
</colgroup>
<tr>
<th>
Element</th>
<th>
Description</th>
</tr>
<tr>
<td>
appender</td>
<td>
Zero or more elements allowed. Defines an appender.
</td>
</tr>
<tr>
<td>
logger</td>
<td>
Zero or more elements allowed. Defines the configuration of a logger.
</td>
</tr>
<tr>
<td>
renderer</td>
<td>
Zero or more elements allowed. Defines an object renderer.
</td>
</tr>
<tr>
<td>
root</td>
<td>
Optional element, maximum of one allowed. Defines the configuration of the root
logger.
</td>
</tr>
<tr>
<td>
param</td>
<td>
Zero or more elements allowed. Repository specific parameters</td>
</tr>
</table>
</div>
<br />
<h3>
<a name="Appender_Configuration">Appender Configuration</a></h3>
Each appender has different configuration options. The XML element looks similar
to this.
<pre lang="xml"><appender name="rootRollingFile" type="log4net.Appender.RollingFileAppender,log4net">
<threshold value="ALL"/>
<param name="File" value="logs/MasterLog"/>
<param name="AppendToFile" value="true"/>
<param name="RollingStyle" value="Date"/>
<param name="DatePattern" value=".yyyy.MM.dd.'log'"/>
<param name="StaticLogFileName" value="false"/>
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%date [%-5thread] %-5level %logger - %message%newline %exception"/>
</layout>
</appender>
</pre>
<p>
The <code><appender></code> element supports the following attributes:
</p>
<div class="table">
<table cellspacing="0">
<colgroup>
<col style="width: 7em; white-space: nowrap; text-align: left" />
<col style="text-align: left" />
</colgroup>
<tr>
<th>
Attribute</th>
<th>
Description</th>
</tr>
<tr>
<td>
name</td>
<td>
Required attribute. Value must be a string name for this appender. The name must
be unique among all the appenders defined in this configuration file. This name
is used by the <code><appender-ref></code> element of a Logger to reference
an appender.
</td>
</tr>
<tr>
<td>
type</td>
<td>
Required attribute. Value must be the type name for this appender. If the appender
is not defined in the log4net assembly this type name must be fully assembly qualified.
</td>
</tr>
</table>
</div>
<p>
The <code><appender></code> element supports the following child elements:
</p>
<div class="table">
<table cellspacing="0">
<colgroup>
<col style="width: 7em; white-space: nowrap; text-align: left" />
<col style="text-align: left" />
</colgroup>
<tr>
<th>
Element</th>
<th>
Description</th>
</tr>
<tr>
<td>
appender-ref</td>
<td>
Zero or more elements allowed. Allows the appender to reference other appenders.
Not supported by all appenders.
</td>
</tr>
<tr>
<td>
filter</td>
<td>
Zero or more elements allowed. Defines the filters used by this appender.
</td>
</tr>
<tr>
<td>
layout</td>
<td>
Optional element, maximum of one allowed. Defines the layout used by this appender.
</td>
</tr>
<tr>
<td>
param</td>
<td>
Zero or more elements allowed. Appender specific parameters.</td>
</tr>
</table>
</div>
<br />
<h3>
<a name="Appender_Loggers">Assigning Appenders to Loggers</a></h3>
There are two elements that are used for assigning Appenders to loggers, root and
logger. With each of these elements you can assign two child <code>elements</code>,
<code>level</code> and <code>appender-ref</code>.
<br />
The <code><level></code> element tells log4net what log messages will be sent
to this appender, this is the equivalent to the <code><threshold></code> element
on the appender. The <code><appender-ref></code> element is used to assign
the appender to the specific logger. The format of the element is <code><appender-ref
ref="nameOfAppender" /></code> where the <i>nameOfAppender</i> is the name
that was specified in the name attribute of the <code><appender></code> element.<br />
<br />
When the <code><root></code> element is used, all logging message for the
LogManager / logging Repository will be written to these appenders.<br />
The <code><logger></code> element has one attribute, name, the name attribute
can be a namespace, class, or object name that you want to attach a special appender
to. This is how we are going to be able to attach a different appender for each
class or library.<br />
<pre lang="xml"><root>
<level value="ALL"/>
<appender-ref ref="rootTrace"/>
<appender-ref ref="rootConsole"/>
<appender-ref ref="rootRollingFile"/>
<appender-ref ref="rootEventLog"/>
</root>
<logger name="MyCompany">
<level value="WARN" />
<appender-ref ref="MyCompany_rollingFile" />
</logger>
<logger name="MyCompany.MultipleClasses">
<level value="WARN" />
<appender-ref ref="MyCompany_Multiple_rollingFile" />
</logger>
<logger name="MyCompany.MultipleClasses.Class1">
<level value="DEBUG" />
<appender-ref ref="class1File" />
</logger>
<logger name="MyCompany.MultipleClasses.Class2">
<level value="DEBUG" />
<appender-ref ref="class2File" />
</logger>
<logger name="MyCompany.MultipleClasses.Class3">
<level value="DEBUG" />
<appender-ref ref="class3File" />
</logger>
<logger name="MyCompany.Library1.MyFirstClass">
<level value="DEBUG" />
<appender-ref ref="lib1_MyFirstClass_File" />
</logger>
<logger name="MyCompany.Library2.MySecondClass">
<level value="DEBUG" />
<appender-ref ref="lib2_MySecondClass_File" />
</logger>
<logger name="MyCompany.Library2.MyThirdClass">
<level value="DEBUG" />
<appender-ref ref="lib2_MyThirdClass_File" />
</logger>
</pre>
With this in mind, by looking at the configuration above, we can determine the following.<br />
<br />
<div class="table">
<table cellspacing="0">
<colgroup>
<col style="width: 7em; white-space: nowrap; text-align: left" />
<col style="text-align: left; width: 7em;" />
<col style="text-align: left;" />
</colgroup>
<tr>
<th>
Logger Name</th>
<th>
Level</th>
<th>
What gets logged</th>
<th>
To What Appender</th>
</tr>
<tr>
<td>
MyCompany.MultipleClasses.Class3
</td>
<td>
Debug</td>
<td>
Any debug or higher messages within the MyCompany.MulitpleClasses.Class3.</td>
<td>
class3File</td>
</tr>
<tr>
<td>
MyCompany.MultipleClasses.Class2
</td>
<td>
Debug</td>
<td>
Any debug or higher messages within the MyCompany.MulitpleClasses.Class2.</td>
<td>
class2File</td>
</tr>
<tr>
<td>
MyCompany.MultipleClasses.Class1</td>
<td>
Debug</td>
<td>
Any debug or higher messages within the MyCompany.MulitpleClasses.Class1.</td>
<td>
class1File</td>
</tr>
<tr>
<td>
MyCompany.Library1.MyFirstClass</td>
<td>
Debug</td>
<td>
Any debug or higher messages within the MyCompany.Library1.MyFirstClass</td>
<td>
lib1_MyFirstClass_File</td>
</tr>
<tr>
<td style="height: 17px">
MyCompany.Library2.MySecondClass
</td>
<td style="height: 17px">
Debug</td>
<td style="height: 17px">
Any debug or higher messages within the MyCompany.Library2.MySecondClass..</td>
<td style="height: 17px">
lib2_MySecondClass_File</td>
</tr>
<tr>
<td>
MyCompany.Library2.MyThirdClass</td>
<td>
Debug</td>
<td>
Any debug or higher messages within the MyCompany.Library2.MyThirdClass.</td>
<td>
lib2_MyThirdClass_File</td>
</tr>
<tr>
<td>
MyCompany.MulitpleClasses</td>
<td>
Warn</td>
<td>
Any warning messages or higher within the MyCompany.MultipleClasses namespace.</td>
<td>
MyCompany_rollingFile</td>
</tr>
<tr>
<td>
MyCompany</td>
<td>
Warn</td>
<td>
Any warning messages or higher within the MyCompany namespace</td>
<td>
</td>
</tr>
<tr>
<td>
Root</td>
<td>
All</td>
<td>
Any message by the application.</td>
<td>
rootTrace<br />
rootConsole<br />
rootRollingFile<br />
rootEventLog</td>
</tr>
</table>
</div>
<br />
<h2>
<a name="Summary">Summary</a></h2>
I know this was a lot to digest, if you have any questions, thoughts or comments
on this article, please feel free to let me know.<br />
<br />
<h2>
<a name="References">References</a></h2>
<ul>
<li><a href="http://logging.apache.org/log4net/">log4net Home</a></li>
<li><a href="http://logging.apache.org/log4net/release/manual/configuration.html">log4net
Configuration</a></li>
</ul>
<h2>
<a name="History">History</a></h2>
<div class="table">
<table>
<tr>
<th>
<strong>Version</strong>
</th>
<th>
<strong>Date</strong>
</th>
<th>
<strong>What was done</strong>
</th>
</tr>
<tr>
<td>
<strong>1.0</strong></td>
<td>
6/16/07
</td>
<td>
Initial release.</td>
</tr>
</table>
</div>
</body>
</html>
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I have been in software development for about 15 years or so. I started out with a small book on QuickBASIC, then moved the Visual Basic for DOS, then Visual Basic for Windows, then Visual Basic .NET and eventually Visual C#. When I am not working at my full time job I donate my time to several community efforts like:
Former President of INETA North America, currently Vice President.
President of the Southeast Valley .NET User Group (SEVDNUG) in Chandler, AZ.
Serving on my City's Parks and Recreation board.
I have or have had the following "MVP" awards:
- Visual Basic MVP in 1996
- C# MVP since 2009
- Telerik MVP since 2010
I maintain a Open Source project on CodePlex which wraps the Bing API called BingSharp.
I also help / organize or participate in several community events:
- Desert Code Camp
- AZGiveCamp
- Organizer for the 1st Time MVP event at the MVP Summit
- MVP 2 MVP Sessions at MVP Summit.
- Awesome bean pusher at GeekGive at the MVP Summit.