Configuration
The recommended way to configure log4net is through a configuration file. This section explains the structure of a configuration file and how log4net processes it.
using Animals.Carnivora;
// Import log4net classes.
using log4net;
using log4net.Config;
namespace SampleApp;
private static class MyApp
{
// Define a static logger variable so that it references the Logger instance named "MyApp".
private static readonly ILog logger = LogManager.GetLogger(typeof(MyApp));
private static void Main(string[] args)
{
// Set up a simple configuration that logs on the console.
BasicConfigurator.Configure();
logger.Info("Entering application.");
Dog dog = new();
bar.Bark();
logger.Info("Exiting application.");
}
}
MyApp starts by importing the necessary log4net namespaces.
It then declares a static logger for the type MyApp
.
MyApp uses the following Dog class:
// Import log4net classes
using log4net;
namespace Animals.Carnivora;
internal sealed class Dog
{
private static readonly ILog logger = LogManager.GetLogger(typeof(Dog));
internal void Bark() => logger.Debug("Woof!");
}
Calling BasicConfigurator.Configure()
sets up a simple log4net configuration.
This method automatically adds a ConsoleAppender
to the root logger,
formatting the output using a PatternLayout
with the following pattern:
%timestamp [%thread] %level %logger - %message%newline
Note that by default, the root logger is assigned to Level.DEBUG.
The output of MyApp is:
2024-12-21 14:07:41,508 [main] INFO SampleApp.MyApp - Entering application.
2024-12-21 14:07:41,517 [main] DEBUG Animals.Carnivora.Dog - Woof!
2024-12-21 14:07:41,529 [main] INFO SampleApp.MyApp - Exiting application.
In log4net, child loggers link only to existing ancestors.
For example, the logger Animals.Carnivora.Dog
is directly linked to the root logger,
bypassing the unused Animals
and Animals.Carnivora
loggers.
This improves performance and reduces log4net’s memory footprint.
The MyApp
class configures log4net by calling BasicConfigurator.Configure()
.
Other classes simply need to import the log4net namespace, retrieve the desired loggers, and start logging.
The previous example always produces the same log output.
However, MyApp
can be modified to allow runtime control over log output.
Here’s an improved version:
using Animals.Carnivora;
// Import log4net classes.
using log4net;
using log4net.Config;
namespace SampleApp;
private static class MyApp
{
private static readonly ILog logger = LogManager.GetLogger(typeof(MyApp));
private static void Main(string[] args)
{
// BasicConfigurator replaced with XmlConfigurator.
XmlConfigurator.Configure();
logger.Info("Entering application.");
Dog dog = new();
bar.Bark();
logger.Info("Exiting application.");
}
}
In this version, MyApp
uses XmlConfigurator
to load a configuration file and set up logging accordingly.
The following sample configuration file produces the same output as the previous BasicConfigurator
example:
<log4net>
<!-- ConsoleAppender is set to be a ConsoleAppender -->
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<!-- ConsoleAppender uses PatternLayout -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-4timestamp [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<!-- Set root logger level to DEBUG and its only appender to ConsoleAppender -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
If we want to suppress logging for all components in the Animals.Carnivora
namespace,
we can achieve this with the following configuration file:
<log4net>
<!-- ConsoleAppender is set to be a ConsoleAppender -->
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<!-- ConsoleAppender uses PatternLayout -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-4timestamp [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<!-- Set root logger level to DEBUG and its only appender to ConsoleAppender -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
<!-- Print only messages of level WARN or above in the namespace Animals.Carnivora -->
<logger name="Animals.Carnivora">
<level value="WARN" />
</logger>
</log4net>
The output of MyApp configured with this file is shown below.
2024-12-21 14:07:41,508 [main] INFO SampleApp.MyApp - Entering application.
2024-12-21 14:07:41,529 [main] INFO SampleApp.MyApp - Exiting application.
Since the Animals.Carnivora.Dog
logger does not have a specific level assigned,
it inherits the WARN
level from Animals.Carnivora
, as set in the configuration file.
The log statement in Dog.Bark()
is at the DEBUG
level, which is lower than WARN
.
As a result, the log request from Bark()
is suppressed.
Below is another configuration file that uses multiple appenders:
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<!-- Pattern to output the caller's file name and line number -->
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="example.log" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level %thread %logger - %message%newline" />
</layout>
</appender>
<!-- Set root logger level to DEBUG and its only appender to ConsoleAppender -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
Calling the enhanced MyApp with the this configuration file will output the following on the console.
INFO [main] (MyApp.cs:17) - Entering application.
DEBUG [main] (Dog.cs:10) - Woof!
INFO [main] (MyApp.cs:20) - Exiting application.
Additionally, since the root logger has a second appender, the output is also written to example.log
.
This file rolls over once it reaches 100KB, moving the old log to example.log.1
.
Notably, achieving these different logging behaviors required no code recompilation.
We could just as easily log to an email address or redirect all Animals.Carnivora
output
to a remote syslog server.
For more examples of configuring appenders with XmlConfigurator
, see
Appenders.
Configuration Attributes
log4net can be configured using assembly-level attributes instead of setting it up programmatically.
XmlConfiguratorAttribute
The log4net.Config.XmlConfiguratorAttribute
allows log4net to be configured using the following properties:
- ConfigFile
-
Specifies the filename of the configuration file to use with the
XmlConfigurator
. The file path is relative to the application base directory (AppDomain.CurrentDomain.BaseDirectory
). This property cannot be used with theConfigFileExtension
property. - ConfigFileExtension
-
Specifies the extension for the configuration file. The assembly filename is used as the base name, with this extension appended. For example, if the assembly is
TestApp.exe
and theConfigFileExtension
is set tolog4net
, the configuration file will beTestApp.dll.log4net
. This is equivalent to setting theConfigFile
property toTestApp.dll.log4net
. The path to the configuration file is built using the application base directory (AppDomain.CurrentDomain.BaseDirectory
), the assembly file name, and the configuration file extension. This property cannot be used with theConfigFile
property. - Watch
-
If set to
true
, this flag will enable the framework to monitor the configuration file and automatically reload it when the file is modified.
If neither the ConfigFile
nor the ConfigFileExtension
properties are specified, the application configuration file (e.g., TestApp.dll.config
) will be used as the log4net configuration file.
Example usage:
// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
// This will cause log4net to look for a configuration file
// called TestApp.dll.config in the application base
// directory (i.e. the directory containing TestApp.exe)
// The config file will be watched for changes.
// Configure log4net using the .log4net file
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
// This will cause log4net to look for a configuration file
// called TestApp.dll.log4net in the application base
// directory (i.e. the directory containing TestApp.exe)
// The config file will be watched for changes.
This attribute may only be used once per assembly.
Using attributes can be a clearer method for defining where the application’s configuration will be loaded from.
However, note that attributes are passive — they only provide information.
Therefore, to trigger log4net to read and process the attributes, you must invoke log4net.
A simple call to LogManager.GetLogger
will cause the attributes on the calling assembly to be processed.
It is crucial to make a logging call as early as possible during the application startup, and certainly before any external assemblies are loaded and invoked.
AppSettings
If you use attributes to configure log4net, two settings in the appSettings section of your application’s configuration file can override the values specified in your assembly’s attributes.
The setting with the key log4net.Config
overrides the configuration file name (relative to your application’s base directory), while the setting with the key log4net.Config.Watch
determines whether the configuration file should be monitored for changes.
For example, even though the assembly attribute:
[assembly: log4net.Config.XmlConfigurator(Watch = false)]
configures your application to use the "TestApp.dll.config" file and not monitor it for changes, you can override this to use the "log4net.config" file and monitor it for changes by adding the following to your application’s configuration file:
<appSettings>
<add key="log4net.Config" value="log4net.config"/>
<add key="log4net.Config.Watch" value="True"/>
</appSettings>
to your application’s configuration file.
Configuration Files
Typically the log4net configuration is specified using a file. This file can be read in one of two ways:
-
Using the System.Configuration API
-
Reading the file contents directly
.config Files
The System.Configuration
API can only be used if the configuration data is stored in the application’s config file (e.g. MyApp.dll.config
, MyApp.exe.config
, or Web.config
).
The System.Configuration
API does not support reloading the config file.
This means that the configuration settings cannot be watched using the log4net.Config.XmlConfigurator.ConfigureAndWatch
methods.
To configure an application using the System.Configuration
API, you must call one of the following methods:
* log4net.Config.XmlConfigurator.Configure()
* log4net.Config.XmlConfigurator.Configure(ILoggerRepository)
To embed the configuration data in the .config
file, you must define the log4net
section in the configSections
element.
The section must specify the log4net.Config.Log4NetConfigurationSectionHandler, log4net
type.
The following is a simple example configuration file that specifies the correct section handler to use for the log4net
section.
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>
Reading Files Directly
The XmlConfigurator
can directly read any XML file and use it to configure log4net.
This includes the application’s .config
file (e.g. MyApp.dll.config
, MyApp.exe.config
, or Web.config
).
You can specify the configuration file using log4net.Config.XmlConfigurator
methods that accept a System.IO.FileInfo
object.
To auto-reconfigure on changes, use ConfigureAndWatch
, which monitors the file for updates.
Additionally, the log4net.Config.XmlConfiguratorAttribute
can be used to specify the file to read the configuration from.
The configuration is read from the log4net
element in the file.
Only one log4net
element can be specified in the file, but it may be located anywhere in the XML
hierarchy.
For example, it may be the root element:
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
Or it may be nested within other elements:
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>
The example shows how to embed configuration data in a .config file while allowing log4net to read it directly.
Since the .NET config parser throws errors for unregistered elements, the log4net
section is registered using System.Configuration.IgnoreSectionHandler
.
This tells .NET to ignore the section, as it will be processed by log4net instead.
Android
Android does not support .config
files.
Instead, you can set AppSettings
values as environment variables for your process — this works only on Android.
You must also load the log4net
configuration manually, for example by reading it from an XML file at runtime.
Configuration Syntax
log4net provides an XML-based configuration reader, log4net.Config.XmlConfigurator
.
This section outlines the syntax accepted by the configurator.
A valid XML configuration must have <log4net>
as the root element.
However, this element can be embedded in another XML document.
For details on embedding XML configurations in a file, see the section on .config Files.
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
The <log4net>
element supports the following attributes:
Attribute | Required | Allowed values | Default | Description |
---|---|---|---|---|
debug |
no |
true or false |
false |
Set this attribute to true to enable internal log4net debugging for this configuration. |
update |
no |
Merge or Overwrite |
Merge |
Set this attribute to |
threshold |
no |
Level (e.g. DEBUG, INFO, WARN, ERROR) |
ALL |
Set this attribute to limit the messages that are logged across the whole repository, regardless of the logger that the message is logged to. |
The <log4net>
element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
appender |
0..* |
Defines an appender. |
logger |
0..* |
Defines the configuration of a logger. |
renderer |
0..* |
Defines an object renderer. |
root |
0..1 |
Defines the configuration of the root logger. |
param |
0..* |
Repository-specific parameters. |
Appenders
Appenders must be defined as child elements of the <log4net>
element.
Each appender requires a unique name and a specified implementing type.
The following example defines an appender of type log4net.Appender.ConsoleAppender
, named ConsoleAppender
.
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
The <appender>
element supports the following attributes:
Attribute | Required | Allowed values | Description |
---|---|---|---|
name |
yes |
A unique string name |
Used by the |
type |
yes |
A fully qualified type name |
If the appender is not in the log4net assembly, the type name must be fully assembly qualified. |
The <appender>
element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
appender-ref |
0..* |
Allows the appender to reference other appenders. Not supported by all appenders. |
filter |
0..* |
Defines the filters used by this appender. |
layout |
0..1 |
Defines the layout used by this appender. |
param |
0..* |
Appender-specific parameters. |
For examples of configuring appenders see Example Appender Configuration.
Filters
Filter elements may only be defined as children of <appender>
elements.
The <filter>
element supports the following attributes:
Attribute | Required | Allowed values | Description |
---|---|---|---|
type |
yes |
Value must be the type name for this filter. |
If the filter is not defined in the log4net assembly, this type name must be fully assembly qualified. |
The <filter>
element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
param |
0..* |
Filter-specific parameters. |
Filters form a chain that the event must pass through. Each filter can either:
-
Accept the event and stop processing.
-
Deny the event and stop processing.
-
Pass the event to the next filter.
If no filter denies the event, it is implicitly accepted and logged.
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
This filter denies events with a level lower than INFO or higher than FATAL. Only events between INFO and FATAL are logged.
To allow only messages containing a specific substring (e.g., 'database'), the following filters must be specified:
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="database" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
The first filter checks if the message text contains the substring 'database'. * If found, the filter accepts the message, stops processing, and logs the event. * If not found, the event moves to the next filter.
If there is no next filter, the event would be implicitly accepted and logged.
To prevent logging non-matching events, a log4net.Filter.DenyAllFilter
must be used at the end of the filter chain.
This filter ensures that all unmatched events are denied.
To allow events containing either 'database' or 'ldap', use the following filters:
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="database" />
</filter>
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="ldap" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
Layouts
Layout elements may only be defined as children of <appender>
elements.
The <layout>
element supports the following attributes:
Attribute | Required | Allowed values | Description |
---|---|---|---|
type |
yes |
Value must be the type name for this layout. |
If the layout is not defined in the log4net assembly, this type name must be fully assembly qualified. |
The <layout>
element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
param |
0..* |
Layout-specific parameters. |
This example shows how to configure a layout using log4net.Layout.PatternLayout
.
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
Root Logger
Only one root
logger element may be defined, and it must be a child of the log4net
element.
The root logger is the root of the logger hierarchy.
All loggers ultimately inherit from this logger.
An example root logger:
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
The <root> element supports no attributes.
The <root> element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
appender-ref |
0..* |
Allows the logger to reference appenders by name. |
level |
0..1 |
Defines the logging level for this logger. This logger will only accept event that are at this level or above. |
param |
0..* |
Logger specific parameters |
Loggers
Logger elements may only be defined as children of the <log4net> element.
An example logger:
<logger name="MyLogger">
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</logger>
The <logger> element supports the following attributes.
Attribute | Required | Allowed values | Default | Description |
---|---|---|---|---|
name |
yes |
any logger name |
Value must be the name of the logger. |
|
additivity |
no |
true or false |
true |
Set this attribute to false to prevent this logger from inheriting the appenders defined on parent loggers. |
The <logger> element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
appender-ref |
0..* |
Allows the logger to reference appenders by name. |
level |
0..1 |
Defines the logging level for this logger. This logger will only accept events that are at this level or above. |
param |
0..* |
Logger specific parameters |
Renderers
Renderer elements may only be defined as children of the <log4net> element.
An example renderer:
<renderer renderingClass="Animals.Carnivora.Renderers.DogRenderer" renderedClass="Animals.Carnivora.Dog" />
The <renderer> element supports the following attributes.
Attribute | Required | Allowed values | Description |
---|---|---|---|
renderingClass |
yes |
Value must be the type name for this renderer. If the type is not defined in the log4net assembly this type name must be fully assembly qualified. |
This is the type of the object that will take responsibility for rendering the renderedClass. |
renderedClass |
yes |
Value must be the type name for the target type for this renderer. If the type is not defined in the log4net assembly this type name must be fully assembly qualified. |
This is the name of the type that this renderer will render. |
The <renderer> element supports no child elements.
Parameters
Parameter elements may be children of many elements. See the specific elements above for details.
An example param:
<param name="ConversionPattern" value="%date [%thread] %-5level %logger - %message%newline" />
The <param> element supports the following attributes.
Attribute | Required | Allowed values | Description |
---|---|---|---|
name |
yes |
Value must be the name of the parameter to set on the parent object. |
|
value |
no |
The value of this attribute is a string that can be converted to the value of the parameter. |
|
type |
no |
The value of this attribute is a type name to create and set as the value of the parameter. |
If the type is not defined in the log4net assembly this type name must be fully assembly qualified. |
The <param> element supports the following child elements:
Element | Cardinality | Description |
---|---|---|
param |
0..* |
Parameter specific parameters |
An example param that uses nested param elements:
<param name="evaluator" type="log4net.Core.LevelEvaluator">
<param name="Threshold" value="WARN"/>
<param>
Extension Parameters
Configuration parameters map directly to writable properties on an object. The properties available depend on the actual type of the object being configured.
For 3rd party components please see their relevant API reference for details of the properties available.
Compact Parameter Syntax
All parameters may alternately be specified using the parameter name as the element name rather than using the param element and name attribute.
For example a param:
<param name="evaluator" type="log4net.Core.LevelEvaluator">
<param name="Threshold" value="WARN"/>
<param>
may be written as:
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="WARN"/>
<evaluator>