Click here to Skip to main content
15,894,825 members
Articles / Programming Languages / Visual Basic

log4net XmlConfigurator Simplified

Rate me:
Please Sign up or sign in to vote.
4.71/5 (16 votes)
16 Jun 2007CPOL5 min read 95.2K   990   60  
This article covers the configuration of log4net using the XmlConfigurator. This article also demonstrates how to create multiple log files for your application.
<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>&lt;log4net&gt;</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>&lt;log4net&gt;</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">&lt;appender name="rootRollingFile" type="log4net.Appender.RollingFileAppender,log4net"&gt;
&nbsp;&lt;threshold value="ALL"/&gt;
&nbsp;&lt;param name="File" value="logs/MasterLog"/&gt;
&nbsp;&lt;param name="AppendToFile" value="true"/&gt;
&nbsp;&lt;param name="RollingStyle" value="Date"/&gt;
&nbsp;&lt;param name="DatePattern" value=".yyyy.MM.dd.'log'"/&gt;
&nbsp;&lt;param name="StaticLogFileName" value="false"/&gt;
&nbsp;&lt;layout type="log4net.Layout.PatternLayout,log4net"&gt;
&nbsp;&nbsp;&lt;param name="ConversionPattern" value="%date [%-5thread] %-5level %logger - %message%newline %exception"/&gt;
&nbsp;&lt;/layout&gt;
&lt;/appender&gt;
</pre>
    <p>
        The <code>&lt;appender&gt;</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>&lt;appender-ref&gt;</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>&lt;appender&gt;</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>&lt;level&gt;</code> element tells log4net what log messages will be sent
    to this appender, this is the equivalent to the <code>&lt;threshold&gt;</code> element
    on the appender. The <code>&lt;appender-ref&gt;</code> element is used to assign
    the appender to the specific logger. The format of the element is <code>&lt;appender-ref
        ref="nameOfAppender" /&gt;</code> where the <i>nameOfAppender</i> is the name
    that was specified in the name attribute of the <code>&lt;appender&gt;</code> element.<br />
    <br />
    When the <code>&lt;root&gt;</code> element is used, all logging message for the
    LogManager / logging Repository will be written to these appenders.<br />
    The <code>&lt;logger&gt;</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">&lt;root&gt;
&nbsp;&lt;level value="ALL"/&gt;
&nbsp;&lt;appender-ref ref="rootTrace"/&gt;
&nbsp;&lt;appender-ref ref="rootConsole"/&gt;
&nbsp;&lt;appender-ref ref="rootRollingFile"/&gt;
&nbsp;&lt;appender-ref ref="rootEventLog"/&gt;
&lt;/root&gt;
&lt;logger name="MyCompany"&gt;
&nbsp;&lt;level value="WARN" /&gt;
&nbsp;&lt;appender-ref ref="MyCompany_rollingFile" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.MultipleClasses"&gt;
&nbsp;&lt;level value="WARN" /&gt;
&nbsp;&lt;appender-ref ref="MyCompany_Multiple_rollingFile" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.MultipleClasses.Class1"&gt;
&nbsp;&lt;level value="DEBUG" /&gt;
&nbsp;&lt;appender-ref ref="class1File" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.MultipleClasses.Class2"&gt;
&nbsp;&lt;level value="DEBUG" /&gt;
&nbsp;&lt;appender-ref ref="class2File" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.MultipleClasses.Class3"&gt;
&nbsp;&lt;level value="DEBUG" /&gt;
&nbsp;&lt;appender-ref ref="class3File" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.Library1.MyFirstClass"&gt;
&nbsp;&lt;level value="DEBUG" /&gt;
&nbsp;&lt;appender-ref ref="lib1_MyFirstClass_File" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.Library2.MySecondClass"&gt;
&nbsp;&lt;level value="DEBUG" /&gt;
&nbsp;&lt;appender-ref ref="lib2_MySecondClass_File" /&gt;
&lt;/logger&gt;
&lt;logger name="MyCompany.Library2.MyThirdClass"&gt;
&nbsp;&lt;level value="DEBUG" /&gt;
&nbsp;&lt;appender-ref ref="lib2_MyThirdClass_File" /&gt;
&lt;/logger&gt;
</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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
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.

Comments and Discussions