4.2 Diagnosing Without Downtime via log4net

log4net is an application logging framework for the .NET platform, originally ported from the popular log4j framework for Java. Application logging serves two main purposes: to aid in application development and testing, and to enable runtime monitoring and diagnosis of applications in production.

log4net provides a mechanism for standardized, runtime-configurable application logging with minimal impact on application development and runtime performance.

log4net at a Glance

Tool

log4net

Version covered

1.2

Home page

http://logging.apache.org/log4net/

Power Tools page

http://www.windevpowertools.com/tools/143

Summary

Application logging framework for .NET

License type

Apache License 2.0

Online resources

Mailing lists

Supported Frameworks

.NET 1.0, 1.1, 2.0

.NET Compact Framework 1.0 (1.0.5000)

Mono 1.1.13

Microsoft Shared Source CLI 1.0 Compatible

Getting Started

Setting up your project to use log4net is straightforward. Just download the distribution from the Downloads link on the tool’s home page, extract the log4net distribution, and follow these four steps.

Step 1: Referencing the assembly

You must select the correct build of log4net for your environment. For example, if you are using version 1.1 of the .NET Framework, you should select the log4net.dll file located in the bin\net\1.1\release folder in the log4net distribution. To add a reference to your Visual Studio project, select Add Reference from the Project menu.

Step 2: Configuring log4net

log4net can be configured in the app.config file or via an external XML file. To configure log4net in the app.config file, add the following fragment to the file under the configuration element:

<configSections>
    <section name="log4net"
             type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>

<log4net>
    <appender name="MyAppender1" type="log4net.Appender.DebugAppender" >
        <layout type="log4net.Layout.PatternLayout
                value="%date [%thread] %-5level %logger - %message%newline" />
    </appender>
    <root>
        <level value="DEBUG" />
        <appender-ref ref="MyAppender1" />
    </root>
</log4net>

To configure log4net in an external XML file, or to review configuration options and examples, please see the log4net web site.

Step 3: Initializing logging within the application

There are two ways to initialize logging within your application. The first is to directly configure log4net in your code; this call should be made as early as possible during application initialization. Use a code fragment like the following that is appropriate for your language:

log4net.Config.XmlConfigurator.Configure( );

There are a number of overloaded versions of this method that you can use to supply parameters such as the name of a configuration file. Further details are available in the log4net documentation.

Alternatively, you can create an attribute on the application’s main assembly specifying the location of the log4net configuration settings. log4net will then automatically configure itself when the first logger is created. The assembly attribute should be specified in a project source file, such as AssemblyInfo.cs or AssemblyInfo.vb, as follows:

[assembly: log4net.Config.XmlConfigurator( )]

Step 4: Adding logging messages to the code

To output logging messages from code, you must first create a logger. You can do this by adding the following line of code to each of your types (in this example, we assume that the type is named Form1):

private static readonly ILog log = LogManager.GetLogger(typeof(Form1));

Logging messages can then be added as follows:

// Simple example
log.Debug("Something happened");

// Example showing variable substitution
log.DebugFormat("Something happened because {0} is less then {1}", var1, var2);

// More complex example demonstrating level test
if (log.IsDebugEnabled)
{
    string s = ComplicatedMethod( );
    log.DebugFormat("The value of ComplicatedMethod is {0}", s);
}

Using log4net

The use you will make of log4net will depend on whether you are a developer (as we assume to be the case, since you’re reading this book) or an administrator (a role you may fill from time to time):

For developers

Logging aids debugging during development by showing the flow through the application. Logging tools complement other development tools, such as debuggers and profilers. Logging should never be removed from an application; if it was useful once, it may prove useful again.

For system administrators

Logging is an invaluable tool for aiding system administrators in the diagnosis of problems with their applications in a production environment. Administrators are better able to communicate with the development team when they have extensive logs available with which to detect and diagnose issues.

The log4net framework makes use of three key concepts and provides the mechanisms for configuring each:

Loggers

Loggers are named objects that a developer can use to output contextual logging information from within an application. The loggers are in a hierarchy based on their names, such that a logger with the name foo is the parent of foo.bar. The most commonly used scheme is to use one logger per type and to name the logger with its namespace and type name. There is always a root logger, which exists at the top of the hierarchy.

Loggers expose an API enabling output at one of the following levels of severity: DEBUG, INFO, WARN, ERROR, or FATAL. Each logger can be configured with a severity level; loggers that are not explicitly configured inherit the level from their closest ancestor. The root logger must be explicitly assigned a severity level.

This structure allows the developer to insert logging code into an application, knowing that he can control the output so that only messages at and above a certain level of severity will be logged. Crucially, he can achieve this without recompiling, or even restarting, the application or component.

Appender

It’s easy to output logging messages from applications and to control which messages are logged, but where do the messages end up, and how can you view them? The purpose of log4net appenders is to handle the outputting of messages. Table 4-1 lists the most commonly used appenders currently included in the standard log4net distribution. Developers can also create their own appenders.

Table 4-1. Popular logging appenders

Appender

Description

AdoNetAppender

Writes logging events to a database using either prepared statements or stored procedures.

ConsoleAppender

Writes logging events to the application’s console. The events can go to either the standard out stream or the standard error stream.

EventLogAppender

Writes logging events to the Windows Event Log.

RemoteSyslogAppender

Writes logging events to a remote syslog service using UDP networking.

RemotingAppender

Writes logging events to a remoting sink using .NET remoting.

RollingFileAppender

Writes logging events to a file in the filesystem. The RollingFileAppender can be configured to log to multiple files based upon date or file-size constraints.

SmtpAppender

Sends logging events to an email address.

A major benefit of using log4net over System.Console.WriteLine( ) is that log4net can output messages to multiple destinations. In combination with message severity levels, logging to multiple destinations can be extremely useful.

Consider an application running in production. Administrators are generally interested only in monitoring errors. It would be ideal if they could be actively notified if something goes very badly wrong, but it would also be nice to have some detailed information about the circumstances causing the failure. To achieve this, you can use a three-appender log4net configuration such as this:

EventLogAppender

Output all messages at ERROR and FATAL levels to the Windows Application Event Log.

RollingFileAppender

Output all messages at INFO, WARN, ERROR, and FATAL levels to a set of rolling files, and set a file-size limit on these files to prevent excessive disk space usage.

SmtpAppender

Output messages at FATAL level for delivery to a notification email address.

This configuration provides notification of fatal conditions by email, stores a persistent record of all errors in the Windows Event Log, and keeps a detailed activity trace for a short period of time to facilitate problem diagnosis.

Finally, the log4net framework can be configured so that loggers output to specific appenders, enabling messages from different aspects of an application to be handled appropriately.

Layout

Appenders use layouts to customize the output format of messages. log4net includes the PatternLayout, which enables the user to specify the message output format according to conversion patterns similar to the printf( ) function in C. For example, the pattern:

%timestamp [%thread] %-5level %logger - %message%newline

outputs messages formatted like this:

234 [main] WARN  story.children.littleredridinghood – There is a wolf in
grandma's bed!

Table 4-2 lists the most popular layouts currently included in the standard log4net distribution. Of course, developers can also create their own layouts.

Table 4-2. Popular layouts

Layout

Description

PatternLayout

Formats the logging event according to a flexible set of formatting flags

SimpleLayout

Formats the logging event very simply ([level] - [message])

XmlLayout

Formats the logging event as an XML element

XmlLayoutSchemaLog4j

Formats the logging event as an XML element that complies with the log4j event DTD

Configuring log4net

The log4net configuration is typically loaded from an XML text file, which may be the application’s .config file or any other file specified in the application. This allows the system administrator to modify the logging configuration while the application is running in production with no reduction in the application’s availability.

log4net can be instructed to monitor the configuration file for changes and to reload the configuration at runtime. This allows the logging configuration (levels/appenders) to be modified while the application is still running.

You can also specify the logging configuration programmatically, instead of using a configuration file. This is less typical than loading the configuration from an XML file, but it does allow the application to control its own logging.

Managing performance

The performance overhead of logging statements must be considered in two scenarios: when logging is disabled and when logging is enabled. log4net checks the severity as the first part of a logging call. This check must be made for each call to allow the logging configuration to be changed at runtime.

When logging is disabled, this is the only overhead for each logging call, so the performance is very good. When logging is enabled, the cost of logging depends on the appenders specified in the configuration. The FileAppender has low latency and high throughput characteristics; however, the SmtpAppender has higher latency. The impact of the selection of appender on the performance of the logging subsystem must be considered when specifying the logging options.

Managing context

One of the most important tasks for the developer is to ensure that relevant contextual information describing the state of the application at the time of the logging call is provided. Contextual data is captured for each logging call; this includes the time of the event, the thread on which it occurred, and the Windows identity associated with that thread at the time of the event.

It is often necessary for developers to specify their own contextual information. log4net allows contextual data to be attached to a single logging event, to a thread, or globally. Any contextual data attached to the current thread is made available to the events logged within the thread. The following code fragments illustrate how this can be achieved:

[C#]

// Set a global property
GlobalContext.Properties["country"] = "USA";

// Set a thread property
ThreadContext.Properties["action"] = "checkout";

// Push a property onto this thread's "action" property stack
using (ThreadContext.Stacks["actions"].Push("deposit"))
{
    // Perform the deposit action
    // ...
}   // "deposit" is automatically popped off the "actions" stack

Getting Support

Community support for log4net is available through the log4net web site and the mailing list. For details, see http://logging.apache.org/log4net/support.html.

Commercial support is also available from the team that started the project at NeoWorks. Details are available on their web site at http://www.neoworks.com/products/opensource/log4net/.

Get Windows Developer Power Tools now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.