log4net is a tool to help the programmer output log statements to a variety of output targets.
In case of problems with an application, it is helpful to enable logging so that the problem can be located. With log4net it is possible to enable logging at runtime without modifying the application binary. The log4net package is designed so that log statements can remain in production code without incurring a high performance cost. It follows that the speed of logging (or rather not logging) is crucial.
At the same time, log output can be so voluminous that it quickly becomes overwhelming. One of the distinctive features of log4net (and common to all of the log4x libraries) is the notion of hierarchical loggers. Using these loggers it is possible to selectively control which log statements are output at arbitrary granularity.
log4net is designed with two distinct goals in mind: speed and flexibility. There is a tight balance between these two requirements.
No. log4net is not reliable. It is a best-effort and fail-stop logging system.
By fail-stop, we mean that log4net will not throw unexpected exceptions at run-time potentially causing your application to crash. If for any reason, log4net throws an uncaught exception (except for ArgumentException and ArgumentNullException which may be thrown), please send an email to the log4net-user@logging.apache.org mailing list. Uncaught exceptions are handled as serious bugs requiring immediate attention.
Moreover, log4net will not revert to System.Console.Out or System.Console.Error when its designated output stream is not opened, is not writable or becomes full. This avoids corrupting an otherwise working program by flooding the user's terminal because logging fails. However, log4net will output a single message to System.Console.Error and System.Diagnostics.Trace indicating that logging can not be performed.
log4net runs on many different frameworks and each framework has its own requirements. As a rule of thumb you will need an ECMA-335 compliant CLI runtime, for example, the Microsoft® .NET runtime 1.0 (1.0.3705) or 1.1 (1.1.4322).
Not all frameworks are created equal and some features have been excluded from some of the builds. See the Framework Support document for more information.
There is a directory containing examples in log4net\examples. The examples are broken down by framework.
See the features overview document for more information on the features of log4net.
Yes, log4net is thread-safe.
The log output can be customized in many ways. Moreover, one can completely override the output format by implementing one's own ILayout
Here is an example output using PatternLayout with the conversion pattern %timestamp [%thread] %-5level %logger{2} %ndc - %message%newline
176 [main] INFO examples.Sort - Populating an array of 2 elements in reverse order. 225 [main] INFO examples.SortAlgo - Entered the sort method. 262 [main] DEBUG SortAlgo.OUTER i=1 - Outer loop. 276 [main] DEBUG SortAlgo.SWAP i=1 j=0 - Swapping intArray[0] = 1 and intArray[1] = 0 290 [main] DEBUG SortAlgo.OUTER i=0 - Outer loop. 304 [main] INFO SortAlgo.DUMP - Dump of integer array: 317 [main] INFO SortAlgo.DUMP - Element [0] = 0 331 [main] INFO SortAlgo.DUMP - Element [1] = 1 343 [main] INFO examples.Sort - The next log statement should be an error message. 346 [main] ERROR SortAlgo.DUMP - Tried to dump an uninitialized array. 467 [main] INFO examples.Sort - Exiting main method.
The first field is the number of milliseconds elapsed since the start of the program. The second field is the thread outputting the log statement. The third field is the level of the log statement. The fourth field is the rightmost two components of the name of the logger making the log request. The fifth field (just before the '-') is the nested diagnostic context (NDC). Note the nested diagnostic context may be empty as in the first two statements. The text after the '-' is the message of the statement.
The logger concept lies at the heart of log4net's configuration. Loggers are organized into a hierarchy and give the programmer run-time control on which logging statements are printed or not.
Loggers are assigned levels through the configuration of log4net. A log statement is routed through to the appender depending on its level and its logger.
Contrary to the GNU Public License (GPL) the Apache Software License does not make any claims over your extensions. By extensions, we mean totally new code that invokes existing log4net code. You are free to do whatever you wish with your proprietary log4net extensions. In particular, you may choose to never release your extensions to the wider public. For details see the Apache License, Version 2.0.
We are very careful not to unnecessarily change the log4net client API so that newer log4net releases are backward compatible with previous versions. We are a lot less scrupulous with the internal log4net API. Thus, if your extension is designed to work with the internals of a specific log4net version, then when the next release of log4net comes out, you will probably need to adapt your proprietary extensions to the new release. Thus, you will be forced to spend precious resources in order to keep up with log4net changes. This is commonly referred to as the "stupid-tax". By donating the code and making it part of the standard distribution, you save yourself the unnecessary maintenance work.
If your extensions are useful then someone will eventually write an extension providing the same or very similar functionality. Your development effort will be wasted.
Unless the proprietary log4net extension is business critical, there is little reason for not donating your extensions back to the project.
Alternating between indentation styles makes it hard to understand the source code. Make it hard on yourself but easier on others.
There is nothing more irritating than finding the bugs in debugging (i.e. logging) code.
It's all about the application not about logging.
As fast as they get reported ;-)
log4net is a port of the popular Apache log4j™ logging library. The initial port was done in June 2001, since then we have tried to remain in the spirit of the original log4j. See the log4net history page for more details.
The log4net home page is a good place to start.
Starting with log4net 1.2.11 there are two different binary distributions, oldkey and newkey.
The oldkey distribution contains assemblies signed with the same strong name key that was used to sign the assemblies of log4net 1.2.10 and earlier. This strong name key is only available to log4net developers.
The newkey distribution contains assemblies signed with the strong name key available from log4net's svn area or inside the source distribution. Everybody can create assemblies that have the same strong name.
For open source projects it is important that you can create your own patched version of a product and use it instead of the official release. This is something that is now possible if the newkey is used throughout.
The oldkey distribution is mostly only for people who work with third-party dependencies that require one of the earlier releases of log4net and can't be recompiled to use the new strong name. If you start a new project or can recompile all your dependencies we strongly recommend you use the newkey assemblies.
Note that the "new" strong name no longer provides any kind of authenticity. If you want to be sure you have the "real" Apache log4net, download the binary release from one of the mirrors and verify the PGP signature.
Logging behavior can be set using configuration files which are parsed at runtime. Using configuration files the programmer can define loggers and set their levels.
Configuration files are specified in XML. See log4net.Config.XmlConfigurator for more details.
See the various log4net.Layout and log4net.Appender components for specific configuration options.
Setting the Threshold on the Hierarchy to Level OFF will disable all logging from that Hierarchy. This can be done in the log4net configuration file by setting the "threshold" attribute on the log4net configuration element to "OFF". For example:
<log4net threshold="OFF" />
log4net uses public properties to configure components such as Appenders, Layouts, Loggers etc.
Thus, any writable public property in on the appender corresponds to a configurable option. For example, in RollingFileAppender the public int MaxSizeRollBackups { set; } property corresponds to the MaxSizeRollBackups option.
Layouts options are also defined by their writable properties. Same goes for most other log4net components.
Yes it is. Setting the Threshold option of any appender extending AppenderSkeleton, (most log4net appenders extend AppenderSkeleton) will filter out all log events with a lower level than the value of the threshold option.
For example, setting the threshold of an appender to DEBUG will also allow INFO, WARN, ERROR and FATAL messages to log along with DEBUG messages. (DEBUG is the lowest level). This is usually acceptable as there is little use for DEBUG messages without the surrounding INFO, WARN, ERROR and FATAL messages. Similarly, setting the threshold of an appender to ERROR will filter out DEBUG, INFO and WARN messages but not ERROR or FATAL messages.
This policy usually best encapsulates what the user actually wants to do, as opposed to her mind-projected solution.
If you must filter events by exact level match, then you can attach a LevelMatchFilter to any appender to filter out logging events by exact level match.
Yes. The XmlConfigurator supports automatic reloading through the ConfigureAndWatch APIs. See the API documentation for more details.
Yes. When specifying the type in the configuration file you can give the assembly qualified name of the type. For example:
<appender name="..." type="MyNamespace.MyAppender, MyAssembly">
The .NET runtime will try to locate the assembly called MyAssembly. How .NET locates assemblies is beyond the scope of this FAQ.
When loading an assembly from the GAC the fully qualified assembly name, including the version, culture and public key must be specified. This is in the standard syntax supported by System.Type.GetType. See the next FAQ on how to get the version and public key for an assembly.
The fully qualified name for an assembly includes the version, culture and public key. The public key is derived from the strong name used to identify the publisher. When referencing an assembly from the GAC the fully qualified name must be used. To get the version, culture and public key you can use a tool like the excellent .NET Reflector from Lutz Roeder available from http://www.aisto.com/roeder/dotnet.
Newlines in the config file need to be escaped using an XML numeric character reference. The sequence that represents a CR LF is . The following example adds a header and footer to the output each followed by a newline.
<layout type="log4net.Layout.PatternLayout"> <header value="[Header] " /> <footer value="[Footer] " /> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" /> </layout>
Log4net supports a pattern syntax for setting string properties similar to the PatternLayout used to format the output messages. This pattern syntax can be used by specifying type="log4net.Util.PatternString" on the string property in the config file. This tells the config parser to pass the value to the PatternString type before converting the result to a string. For details on the patterns supported see the PatternString SDK Reference.
The following example sets the file name for a FileAppender to include the current process id by specifying the %processid pattern in the File property.
<appender name="LogFileAppender" type="log4net.Appender.FileAppender"> <file type="log4net.Util.PatternString" value="log-file-[%processid].txt" /> <layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" /> </appender>
Yes, there are.
You can name logging loggers by locality. It turns out that instantiating a logger in each class, with the logger name equal to the fully-qualified name of the class, is a useful and straightforward approach of defining loggers. This approach has many benefits:
However, this is not the only way for naming loggers. A common alternative is to name loggers by functional areas. For example, the "database" logger, "remoting" logger, "security" logger, or the "XML" logger.
You may choose to name loggers by functionality and subcategorize by locality, as in "DATABASE.MyApp.MyClass" or "DATABASE.MyApp.MyModule.MyOtherClass".
You are totally free in choosing the names of your loggers. The log4net package merely allows you to manage your names in a hierarchy. However, it is your responsibility to define this hierarchy.
Note: by naming loggers by locality one tends to name things by functionality, since in most cases the locality relates closely to functionality.
You can easily retrieve the fully-qualified name of a class in a static block for class X, with the statement typeof(X).Name. Note that X is the class name and span an instance. However because the LogManager.GetLogger method is overloaded to take an instance of Type as well as string usually only the type of the class is required.
Here is the suggested usage template:
public class Foo { private static readonly ILog log = LogManager.GetLogger(typeof(Foo)); ... other code }
An equivalent and more portable solution, though slightly longer, is to use the declaring type of the static constructor.
public class Foo { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); ... other code }
Note: the .NET Compact Framework 1.0 does not support System.Reflection.MethodBase.GetCurrentMethod().
Note: the two forms are only equivalent if Foo is not a generic class. For a generic class Foo<T> the variant using typeof generates a different logger for each different type parameter T while the variant using reflection generates the same logger for all Ts.
For some logger log, writing,
log.Debug("Entry number: " + i + " is " + entry[i]);
incurs the cost of constructing the message parameter, that is converting both integer i and entry[i] to a string, and concatenating intermediate strings. This, regardless of whether the message will be logged or not.
If you are worried about speed, then write
if(log.IsDebugEnabled) { log.Debug("Entry number: " + i + " is " + entry[i]); }
This way you will not incur the cost of parameter construction if debugging is disabled for logger log. On the other hand, if the logger is debug enabled, you will incur the cost of evaluating whether the logger is enabled or not, twice: once in IsDebugEnabled and once in Debug. This is an insignificant overhead since evaluating a logger takes less than 1% of the time it takes to actually log a statement.
So you don't think that the previous FAQ is really the fastest way of not logging? Well there is a faster way but it does have some drawbacks. Starting from:
if(log.IsDebugEnabled) { log.Debug("Entry number: " + i + " is " + entry[i]); }
It is possible to further eliminate the calls to IsDebugEnabled so that the call is only made once per logger. If you are using one logger for each class then you can store the enabled state for the logger in a static variable in the class and then test against this variable:
public class FastLogger { private static readonly ILog log = LogManager.GetLogger(typeof(FastLogger)); private static readonly bool isDebugEnabled = log.IsDebugEnabled; public void MyMethod() { if(isDebugEnabled) { log.Debug("Entry number: " + i + " is " + entry[i]); } } }
So why exactly is this faster? Well to start with the IsDebugEnabled is not called for each log statement, it is called once per logger. Furthermore as the isDebugEnabled variable is private static readonly the JIT compiler can at run-time optimize out the if test altogether. This means that at runtime the JIT compiler won't even compile the logging statements into native code, i.e. all the logging just disappears.
So what is the downside to using this? Well one of the clever features of log4net is that you can change the logging configuration while your program is running. If you need to investigate an issue in your application, you don't have to stop the application, setup the logging and restart the application, you can change the logging configuration and the log4net will reload it (see XmlConfigurator.ConfigureAndWatch APIs for more information). However if the JIT has compiled out all of the logging statements then they are gone and you can't get them back by reloading the configuration file. Effectively this means that the logging configuration can only be set when the application loads and it cannot be changed at runtime. It is up to you to decide if you need ultimate speed or need to be able to reload the logging configuration while the application is running.
Many developers are confronted with the problem of distinguishing the log output originating from the same class but different client requests. They come up with ingenious mechanisms to fan out the log output to different files. In most cases, this is not the right approach.
It is simpler to use a context property or stack (ThreadContext). Typically, one would ThreadContext.Properties["ID"] = "XXX" client specific information, such as the client's hostname, ID or any other distinguishing information when starting to handle the client's request. Thereafter, log output will automatically include the context data so that you can distinguish logs from different client requests even if they are output to the same file.
See the ThreadContext and the PatternLayout classes for more information.
It is quite nontrivial to define the semantics of a "removed" logger which is still referenced by the user.
Before you even start trying any of the alternatives provided, ask yourself whether you really need to have multiple processes log to the same file, then don't do it ;-).
FileAppender offers pluggable locking models for this usecase but all existing implementations have issues and drawbacks.
By default the FileAppender holds an exclusive write lock on the log file while it is logging. This prevents other processes from writing to the file. This model is known to break down with (at least on some versions of) Mono on Linux and log files may get corrupted as soon as another process tries to access the log file.
MinimalLock only acquires the write lock while a log is being written. This allows multiple processes to interleave writes to the same file, albeit with a considerable loss in performance.
InterProcessLock doesn't lock the file at all but synchronizes using a system wide Mutex. This will only work if all processes cooperate (and use the same locking model). The acquisition and release of a Mutex for every log entry to be written will result in a loss of performance, but the Mutex is preferable to the use of MinimalLock.
If you use RollingFileAppender things become even worse as several process may try to start rolling the log file concurrently. RollingFileAppender completely ignores the locking model when rolling files, rolling files is simply not compatible with this scenario.
A better alternative is to have your processes log to RemotingAppenders. Using the RemoteLoggingServerPlugin (or IRemoteLoggingSink) a process can receive all the events and log them to a single log file. One of the examples shows how to use the RemoteLoggingServerPlugin.
The timestamp is created when the logging event is created. That is so say, when the Debug, Info, Warn, Error or Fatal method is invoked. This is unaffected by the time at which they may arrive at a remote server. Since the timestamps are transmitted in UTC format by the RemotingAppender, they all appear in the same time zone as the host creating the logfile. Since the clocks of various machines may not be synchronized, this may account for time interval inconsistencies between events generated on different hosts.
The simple answer is as soon as possible. The long answer is more complex.
If you are configuring log4net programmatically, i.e. by calling the XmlConfigurator.Configure method then you should do so before you begin logging and it is reasonable to do this very soon after application start.
If you are configuring log4net by specifying assembly level attributes on your assembly then the configuration will be loaded once the first call to the LogManager.GetLogger is made. It is necessary that the first call to LogManager.GetLogger made during the process (or AppDomain) is made from the assembly that has the configuration attributes. Log4net will look only once and only on the first calling assembly for the configuration attributes.
Yes. You can implement the log4net.Layout.ILayout interface to create you own customized log format, or you can extend the LayoutSkeleton class which provides a default implementation of the ILayout interface. Appenders can be parameterized to use the layout of your choice.
Yes. You can implement the log4net.Appender.IAppender interface to create you own customized appender. We recommend that you extend the log4net.Appender.AppenderSkeleton class rather than starting from scratch. You should implement your custom code in a assembly separate from the log4net assembly. To get started it is worth looking at the source of the log4net.Appender.TraceAppender as an example of the minimum amount of code required to get an appender working.
To configure log4net to use your custom appender you need to specify the assembly qualified name of the appender type in the config file. For example:
<appender name="..." type="MyNamespace.MyAppender, MyAssembly">
The .NET runtime will try to locate the assembly called MyAssembly. How .NET locates assemblies is beyond the scope of this FAQ.
There are 2 different ways to enable internal debugging in log4net. These are listed below. The preferred method is to specify the log4net.Internal.Debug option in the application's config file.
Internal debugging can also be enabled by setting a value in the application's configuration file (not the log4net configuration file, unless the log4net config data is embedded in the application's config file). The log4net.Internal.Debug application setting must be set to the value true. For example:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="log4net.Internal.Debug" value="true"/> </appSettings> </configuration>
This setting is read immediately on startup an will cause all internal debugging messages to be emitted.
To enable log4net's internal debug programmatically you need to set the log4net.Util.LogLog.InternalDebugging property to true. Obviously the sooner this is set the more debug will be produced.
Internal debugging messages are written to the console and to the System.Diagnostics.Trace system. If the application does not have a console the messages logged there will be lost. Note that an application can redirect the console stream by setting the System.Console.Out. The Trace system will by default send the message to an attached debugger (where the messages will appear in the output window). If the process does not have a debugger attached then the messages are sent to the system debugger. A utility like DebugView from http://www.sysinternals.com may be used to capture these messages.
As log4net internal debug messages are written to the System.Diagnostics.Trace system it is possible to redirect those messages to a local file. You can define a trace listener by adding the following to your application's .config file:
<configuration> ... <system.diagnostics> <trace autoflush="true"> <listeners> <add name="textWriterTraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="C:\tmp\log4net.txt" /> </listeners> </trace> </system.diagnostics> ... </configuration>
Make sure that the process running your application has permission to write to this file.
If you are not getting events delivered to the event log this usually indicates a permissions problem. Basically if the event log does not exist the EventLogAppender tries to create it, but you need local administrator permissions to create event logs (just to write into the right bit of the registry). You don't need administrator permissions to log to an existing event log, but it must exist. If you are using the event log from a web application or service using the event log can be a little tricky.
A web application will run as the user account ASPNET. This account deliberately has few permissions to reduce the chances of someone hacking into the web server. While the account has permission to write to the event log it does not have permission to create event sources (registry create and write access), which are needed to write to the event log.
There are a couple of solutions:
Make the ASPNET user a member of the Administrators group. This will work because the user will then have the required permissions. This is not recommended for production use.
As the event source only needs to be created once for the machine, create an installer and configure it to create the event source. The installer will need to be run as Administrator (don't they all). See System.Diagnostics.EventLogInstaller in the Microsoft .NET Framework SDK for an example of how to create a simple event log installer.
There is a Microsoft Knowledge Base article that covers this issue and how to resolve it. PRB: "Requested Registry Access Is Not Allowed" Error Message When ASP.NET Application Tries to Write New EventSource in the EventLog.
The web application runs as a special user account on the web server called ASPNET. This account has restricted permissions to protect the web server from attacks. By default this account may not have permission to write to the file system. Make sure that the ASPNET account has permission to create and write to files in the directory chosen for logging.
A windows service runs as a user account specified in the services control panel. This account may have restricted permissions, make sure that the account has permission to create and write to files in the directory chosen for logging.
A windows service is launched by windows. The current directory in a service is set to the windows system directory (e.g. C:\Windows\System32). If you are loading the configuration file from the current directory then be aware that this path will not be the location of your assemblies. The best way to get the path to your assemblies is to use AppDomain.BaseDirectory. Note that the log4net internals never use the current directory.
For details on the different ways in which ADO.NET can connect to a database see: Connecting to a Data Source Using ADO.NET.
If you need to use ODBC to connect to your database then please note that the ADO.NET ODBC drivers are not included in the standard .NET framework redistributable. You can download the drivers from microsoft download at: ODBC .NET Data Provider.
First make sure it really is a bug and not a usage error. When in doubt, ask on the log4net-user mailing list first.
If you have identified a bug, please report it via our Issue Tracker. You may want to check it hasn't been reported before by searching the existing issues.
If you use attributes to configure log4net then the order by which assemblies are loaded may determine whether you attributes are used or not. Assembly load order may be different in DEBUG and RELEASE mode.
As stated in the manual the attribute will only be read for the first assembly that tries to use log4net. So it is important that you obtain your ILog instance as early as possible.
For a command line application "as early as possible" probably is the class holding the Main method, for a Web-Application it would be your Global.asax class and for a Windows Service it would be the class deriving from ServiceBase.
There is a good discussion of this topic on Robert McLaws blog: Building a Better Server Control Experience, Part 2.