Log4net was branched from a pre-alpha log4j 1.2, however log4net is not designed to be an identical implementation to log4j. We have not tracked all the changes made by log4j since the branch. We have made design decisions in log4net that are different to some of those in log4j. Now that log4net is at Apache it may be appropriate to discuss some of the differences between the frameworks.
> An example: In the PatternParser class in log4j there are no > private instance fields (all fields are either marked as > protected, or unmarked giving them default package access.) > In the same PatternParser class in log4net all these fields > are marked as private. The PatternParser class has since been redesigned to allow converters to be bound to variable length patterns, e.g. %thread, %logger, %ndc, %property etc... The same change has been made independently in the log4j CVS repository. > Is there any reason why the log4net authors did this? Does this > "redesign" of the log4j architecture show up anywhere else in > the log4net codebase? If so, are the authors interested in fixing this? Other differences include (but not limited to): Log4net exposes an interface (ILog) to clients through the LogManager.GetLogger call rather than the Logger implementation instance. This allows the logger implementation to be changed without impacting clients. The contract is guaranteed by the interface. Log4net does not return the Logger implementation instance from LogManager.GetLogger() but rather a wrapper object. This is a handle body pattern. The body is the Logger implementation. The Logger (ILogger interface) knows how to log any LoggingEvent object. The handle is passed to the client and provides a strongly typed API for the client to call, for example the ILog interface is implemented by the default handle, this translates calls to Error(message) into a call on the logger. This design allows different client contracts to be created and used concurrently even over the same logger. There are some samples of this in the extensions folder in the log4net download. The IRepositorySelector interface is quite different in log4net. It is more complex. Typically components will organise their loggers with hierarchically distinct names, however this is not enforced. Because .net has the concept of an assembly log4net can be configured to create a logger repository for each assembly. This allows the assemblies to have a separate scope for there loggers which is enforced rather than being by convention. Log4net uses attributes defined on the assembly which is logging to control the configuration of the repository selection for that assembly and the configuration of that repository. In both log4j and log4net Levels are mappings between a string name and an integer. The relative position of the levels is defined by the integer value. In log4j Levels are global. In log4net Levels are specific to a Repository. This allows different repositories in memory to define different mappings for levels. While slightly esoteric behaviour this is useful when composing logging from different sources. In log4j the DOMConfigurator has intrinsic knowledge of the Hierarchy object it is configuring. The Hierarchy class is just one possible implementation of the LoggerRepository interface. In log4net the DOMConfigurator delegates the parsing of the XML to the LoggerRepository implementation if it supports the IDOMRepositoryConfigurator interface. This allows different implementations of the ILoggerRepository to support different XML config syntax. In log4net the DOMConfigurator just deals with obtaining the XML DOM from file, stream, .net config section etc... It also can monitor the source for changes. In log4net the config file cannot specify the type of ILoggerRepository to create. Creating the ILoggerRepository of the required type is the responsibility of the RepositorySelector. The log4net configuration parser is able to construct and configure arbitrary objects. The log4j configurator was not able to do this but now is able to do this via the bean api. However these implementations have evolved separately. Log4j is getting a completely new XML configurator called joran. The log4net layout objects (ILayout interface) support formatting to a TextWriter rather than returning a string. This reduces the number of temporary objects created while rendering the message. Log4net supports a different layout interface IRawLayout that renders the LoggingEvent to an object rather than a string. This is used to render the LoggingEvent to native objects. The database appender uses this to optionally render native objects that ADO.NET can consume as parameters to a prepared statement. The log4net IObjectRenderer renders the object passed to a TextWriter for the same reasons as the ILayout. The IObjectRenderer.RenderObject is passed the RendererMap. This allows a renderer to render nested objects using the appropriate renderer. For example an array renderer can render each element in the array using the object renderer from the RendererMap. In log4j the renderer cannot find the RendererMap for the repository. The log4net LoggingEvent provides fine grain control over the volatile content that is fixed. Fixing is required before the LoggingEvent can be used outside of its appending thread context. The above is not meant to be a list of the ways in which log4net is better than log4j, however it is the list of enhancements that I can remember. Of course, to this list of differences you need to add all the cool features added to log4j since the branch in June 2001, most of which I don't know about. Nicko ------------ Nicko Cadell log4net dev
