WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Using log4net
Pages: 1, 2, 3

Repository

The second layer is responsible for maintaining the organization of loggers. By organization, I am talking about the logical structure of the loggers inside of the framework. Before the current version of log4net, the framework only supported the hierarchical organization. As we discussed earlier, this hierarchical nature is an implementation of the repository and is defined in the log4net.Repository.Hierarchy namespace. To implement a Repository, it is necessary to implement the log4net.Repository.ILoggerRepository interface. But instead of directly implementing this interface, another class, log4net.Repository.LoggerRepositorySkeleton, is provided to work as the base class; e.g., the hierarchical repository is implemented by the log4net.Repository.Hierarchy.Hierarchy class.

If you are a normal developer only using the log4net framework instead of extending it, then you would probably not use any of these Repository classes in your code. Instead, you would use the LogManager class, as described earlier, to automatically manage the repositories and the loggers.

Appender

Any good logging framework should be able to generate output for multiple destinations, such as outputting the trace statements to the console or serializing it into a log file. log4net is a perfect match for this requirement. It uses a component called Appender to define this output medium. As the name suggests, these components append themselves to the Logger component and relay the output to an output stream. You can append multiple appenders to a single logger. There are several appenders provided by the log4net framework; the complete list of appenders provided by the log4net framework can be found here.

With all of these appenders provided, there is not much need for writing your own, but if you wish to, you can start by inheriting the log4net.Appender.AppenderSkeleton class, which works as an adapter between your class and the IAppender interface.

Appender Filters

An Appender defaults to pass all logging events to the Layout. Appender Filters can be used to select events by different criteria. There are several filters defined under the log4net.Filter namespace. By using a filter, you can either filter a range of level values, or filter out any log message with a particular string. We'll see filters in action later in our example. More information about filters is provided in the API documentation.

Layout

The Layout component is used to display the final formatted output to the user. The output can be shown in multiple formats, depending upon the layout we are using. It can be linear or an XML file. The layout component works with an appender. There is a list of different layouts in the API documentation. You cannot use multiple layouts with an appender. To create your own layout, you need to inherit the log4net.Layout.LayoutSkeleton class, which implements the ILayout interface.

Using log4net in Your Application

Before you start logging your application, you need to heat up the log4net engine. Technically, this means that you need to configure the three components that we discussed earlier. There are two different methods by which you can specify the configuration: you can either define them in a separate configuration file, or you can place them inside of your code, configuring it programmatically.

The first method is always recommended, for the following reasons.

  • You can change the settings without recompiling the source files.
  • You can change the settings even when your application is running. This is very important in web application and remote application scenarios.

Considering the importance of the first method, we'll see it first.

Using a Configuration File

The configuration settings required are put into either of the following files:

  1. In the application config file (AssemblyName.config or web.config).
  2. Into your own file. The filename could be anything you like, or it could be name of the assembly with a different extension concatenated onto it (such as AppName.exe.xyz).

The log4net framework looks for the configuration file in the file path relative to the application's base directory defined by the AppDomain.CurrentDomain.BaseDirectory property. The only thing that the log4net framework searches for inside of the configuration file is the <log4net> tag. A complete sample configuration file is shown below:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler,
            log4net-net-1.0" 
    />
  </configSections>

  <log4net>
    
    <logger name="testApp.Logging">
      <level value="DEBUG"/>
    </logger>
    
    <root>
      <level value="WARN" />
      <appender-ref ref="LogFileAppender" />
      <appender-ref ref="ConsoleAppender" />
    </root>
    
    <appender name="LogFileAppender" 
             type="log4net.Appender.FileAppender" >
      <param name="File" value="log-file.txt" />
      <param name="AppendToFile" value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="[Header]\r\n"/>
        <param name="Footer" value="[Footer]\r\n"/>
        <param name="ConversionPattern" 
           value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n"
         />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="WARN" />
      </filter>
    </appender>
    
    <appender name="ConsoleAppender" 
              type="log4net.Appender.ConsoleAppender" >
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" 
           value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n" 
        />
      </layout>
    </appender>
    
  </log4net>
</configuration>

You can copy the above file to use in any application, but it is always better to know what constitutes the configuration file. The <section> entry inside of the <configSection> tag is only necessary if you are using the application's configuration file. Otherwise, only the text inside of the <log4net> tag is required. It is not a requirement to maintain the sequence of individual tags; I am only putting it this way to maintain the flow of describing things. Taking each tag individually, we start with the <logger> element.

<Logger>

<logger name="testApp.Logging">
  <level value="DEBUG"/>
  <appender-ref ref="LogFileAppender" />
  <appender-ref ref="ConsoleAppender" />
</logger>
 

The <logger> element defines the settings for an individual logger. Then by calling LogManager.GetLogger(...), you can retrieve the same logger by the name. You can also define the appenders to use with that logger through the <appender-ref> tag. <appender-ref> defines a reference to an appender which is actually defined anywhere else.

<root>


<root>
  <level value="WARN" />
  <appender-ref ref="LogFileAppender" />
  <appender-ref ref="ConsoleAppender" />
</root>

The <root> tag is next to the logger tag. All loggers in the hierarchy are children of the root logger; therefore the framework uses the properties defined here if there are no loggers explicitly defined in the configuration file. After knowing this, we can also tell that the <logger> tag that we see above is not necessary. Inside of the <root> tag, the default values are defined. Both the level value and the appender list can be put in here. The default value of LEVEL, if not defined anywhere else, is set to DEBUG. Obviously, the individual setting for a logger in the <logger> tag overrides the settings in the root tag for that particular logger. In the case of an appender, the <logger> tag will inherit all of the appenders defined by its ancestor. This default behavior can be changed by explicitly setting the additivity attribute for the <logger> tag to false.

<logger name="testApp.Logging" additivity="false">
</logger>

This attribute is set to true by default. The <root> tag is not necessary, but recommended.

<appender>


<appender name="LogFileAppender" 
          type="log4net.Appender.FileAppender" >
  <param name="File" value="log-file.txt" />
  <param name="AppendToFile" value="true" />
  <layout type="log4net.Layout.PatternLayout">
    <param name="Header" value="[Header]\r\n" />
    <param name="Footer" value="[Footer]\r\n"/>
    <param name="ConversionPattern" 
      value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" 
    />
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <param name="LevelMin" value="DEBUG" />
    <param name="LevelMax" value="WARN" />
  </filter>
</appender>
 

The appenders listed either in the <root> tag or in the individual <logger> tag are defined individually using the <appender> tag. The basic format of the <appender> tag is defined above. It uses the appender name and maps it to the class that defines that appender. Other important things to see here are the tags inside of the <appender> element. The <param> tag varies with different appenders. Here, to use the FileAppender, you need a file name that you can define as a parameter. To complete the picture, a Layout is defined inside of the <appender> tag. The layout is declared in its own <layout> tag. The <layout> element defines the layout type (PatternLayout in the example) and the parameters that are required by that layout (as in the pattern string used by the PatternLayout class).

The Header and Footer tags provide the text to print before and after a logging session. The details of configuring each appender are further described in the documentation here, where you can see individual appender section as examples.

The last thing is the <filter> tag in the Appender element. It defines the filter to apply to a specific Appender. In this example, we are applying the LevelRangeFilter, which extracts only those messages that fall between the levels defined between the LevelMin and LevelMax parameters. Similarly, other tags are defined, as appropriate. Multiple filters can be applied to an appender, which then work in a pipeline in the sequence in which they are ordered. Other filters and information on using them can be found in the log4net SDK documents.

These are the necessary elements that we needed to initialize the log4net framework for our application. Now that we have created the configuration file, it's time to link to it from our application.

By default, every standalone executable assembly defines its own configuration settings. The log4net framework uses the log4net.Config.DOMConfiguratorAttribute on the assembly level to set the configuration file. There are three properties for this attribute.

  1. ConfigFile: The property is only used if we are defining the <log4net> tag into our own configuration file.
  2. ConfigFileExtension: If we are using the application compiled assembly with a different extension, then we need to define the extension here.
  3. Watch (Boolean): This is the property by which the log4net system decides whether to watch the file for runtime changes or not. If the value is true, then the FileSystemWatcher class is used to monitor the file for change, rename, and delete notifications.
  
[assembly:log4net.Config.DOMConfigurator(ConfigFile="filename", 
  ConfigFileExtension="ext",Watch=true/false)]

The log4net framework will consider the application's configuration file if you do not define either the ConfigFile or ConfigFileExtension attribute. These attributes are mutually exclusive. We also need to keep it in mind that the DOMConfigurator attribute is necessary and can be defined as follows, with no parameters:


[assembly: log4net.Config.DOMConfigurator()]

There is another technique that saves you from having to use the attributes. It uses the DOMConfigurator class inside of the code to load the configuration file provided in the parameter. This method takes a FileInfo object instead of a file name. This method has the same effect as loading the file through the attribute, as shown previously.


log4net.Config.DOMConfigurator.Configure(
  new FileInfo("TestLogger.Exe.Config")); 

There is another method, ConfigureAndWatch(..), in the DOMConfigurator class, to configure the framework to watch the file for any changes.

The above step concludes everything related to configuration. Next, the following two steps are required in our code to use the logger.

  1. Create a new logger or get the logger you already created. It uses the setting defined in the configuration file. If this particular logger is not defined in the configuration file, then the framework uses the logger's hierarchy to gather different parameters from its ancestors and, lastly, from the root logger.
    
    Log4net.ILog log = log4net.LogManager.GetLogger("logger-name");
    
  2. Use the log object to call any of the logger methods. You can also check the level of the logger through the IsXXXEnabled Boolean variables before calling the methods to boost performance.
    
    if (log.IsDebugEnabled) log.Debug("message");
    if (log.IsInfoEnabled) log.Info("message);
    //….
    

Pages: 1, 2, 3

Next Pagearrow