LoggersA log message in your code using Log4Net all begins with the Logger class. The Logger is the portal into your code. While all of the five main objects can be configured from code, most often you will only need to use the Logger class. Because the LogManager class implements the ILog interface, there is a well-defined strong contract between Log4Net and your code. The ILog interface simply implements the following methods: Debug, Info, Warn, Error, and Fatal. The first set of methods corresponds to the available Levels covered in the next portion of the chapter. All of this makes logging in your program very simple, as shown in Listing 8.1. Listing 8.1. A Simple Log4NET Log Message_logger.Error("This is an error message.", exception);Well, if using a Logger to log is so easy, then how is a Logger instantiated? A Logger is created one of two different ways. The first way to obtain a Logger is by passing in a string to associate with the Logger (see Listing 8.2). Listing 8.2. Creating a LoggerLogger _logger = LogManager.GetLogger("MyLogger");The second way to obtain a Logger is to associate the Logger to the type of the class, as in Listing 8.3. This way, once a Logger is instantiated, you are essentially linking that instance of the Logger with that class. Listing 8.3. The Recommended Way of Getting a LoggerLogger _logger = LogManager.GetLogger(typeof(namespace.class));Whatever messages are logged will be flagged as coming from this class. The reason for the functionality differences in Listing 8.2 and Listing 8.3 is found in Logger Hierarchy and inheritance. HierarchyLoggers are by default hierarchical and based on a named hierarchy. This allows for powerful inheritance of Loggers and ease of use from multiple assemblies. Named hierarchy should be familiar to .NET developers because it is used in namespaces and fully qualified class names in .NET development. Listing 8.4 is an example of Loggers that are related in a parent-child relationship. Listing 8.4. Hierarchical LoggersParent Logger LogManager.GetLogger(typeof(foo)); Child Logger LogManager.GetLogger(typeof(foo.bar));If foo.bar is not assigned a Logging Level, it will inherit it from the parent Logger foo. Also, any log messages for foo.bar will be forwarded to any Appenders in foo.bar as well as up the hierarchy to foo's Appenders. Consequently, there is a Logger that exists as the base or root for all Loggers. This Logger always exists and cannot be retrieved by name. Therefore, you must use the getRootLogger static method of the Logger class to retrieve it. This functionality is due to the fact that every child Logger has a reference to its parent, but the parent Logger knows nothing about the child. Fortunately, this allows for child Loggers to be created before parent Logger, and the hierarchy will all work out in the end. This inheritance and hierarchy functionality can be turned off via the additivity method on the Logger: _logger.setAdditivity(false);Alternatively, this functionality can be achieved by using the following code under the Logger section of the Log4Net config file: <additivity value="false" />Looking at this hierarchy from a different angle, Listing 8.5 shows two Loggers that refer to the exact same instance of a Logger object. Listing 8.5. Identical Logger ReferencesLogger a = LogManager.GetLogger(typeof(foo)); Logger b = LogManager.GetLogger(typeof(foo));This greatly reduces the amount of code needed to use Log4Net by eliminating the need to pass around a reference to a particular instance of the object throughout all the code. This can be useful when using multiple assemblies and should be very useful for Partial Types in .NET 2.0. LogManagerThe LogManager class works with the Hierarchy class to manage all the Loggers for a given instance of Log4Net. LogManager allows for greater runtime control, as seen in Table 8.1. Using the static methods in Table 8.1 can allow your logging code to be very dynamic at runtime as well as give a great deal of information on the current status of your logging system. |