Configure log4net to log to two different log files

Last updated on 17th October 2022

Consider you have an app that uses socket communication to send and receive data from a server. In this case you may want to split the logs to two different files, say for example, app.log and comms.log. All logs are written to the app.log file except for the logs related to socket communication which are written to the comms.log file. There are two ways to achieve this.

  1. Create two named loggers, one logger will be used in the socket communication class and related classes and another logger that will be used elsewhere in the app.
  2. Second method is to configure the root logger and one additional named logger.

Before we go in to the details lets look at how loggers work.

Loggers and Appenders are the two main components of log4net. Loggers are organized hierarchically and at the root of this hierarchy is the root logger. The root logger is defined using the <root> element in the log4net configuration. You can add additional loggers in your application using the <logger> element.

Method 1: Using two named loggers

If you follow the first method then you should configure two loggers as below.

<log4net>

   <logger name="AppLogger">
       <level value="ALL" />
     <appender-ref ref="AppLogFileAppender" />
   </logger>
    
    <appender name="AppLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="app.log" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>

    <logger name="CommsLogger">
       <level value="ALL" />
       <appender-ref ref="CommsLogFileAppender" />
    </logger>
    <appender name="CommsLogFileAppender" type="log4net.Appender.RollingFileAppender">
	 <param name="File" value="comms.log" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline"/>
     </layout>
   </appender>
    
</log4net>

You can then access either of these loggers in your class files by passing the logger name to the GetLogger() method.

  private static readonly ILog _logger = LogManager.GetLogger("AppLogger");
   // or 
  private static readonly ILog _logger = LogManager.GetLogger("CommsLogger");

Method 2: Using root logger and one named loggers

In the second method, you configure the root logger and use this for majority of the logging and use a named logger in just a few classes for which you want the separate log.

The log4net config file will be as below.

<log4net>
   <root>
      <level value="ALL" />
      <appender-ref ref="AppLogFileAppender" />
   </root>
    
    <appender name="AppLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="app.log" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
      </layout>
    </appender>

    <logger name="CommsLogger">
       <level value="ALL" />
       <appender-ref ref="CommsLogFileAppender" />
    </logger>
    <appender name="CommsLogFileAppender" type="log4net.Appender.RollingFileAppender">
	 <param name="File" value="comms.log" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline"/>
     </layout>
   </appender>
    
</log4net>

The loggers can be accessed using the GetLogger method as below.

// Access Root logger which writes to app.log file using class name
private static readonly ILog _logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

// Access logger using logger name
private static readonly ILog _logger = LogManager.GetLogger("CommsLogger");

The main advantage of using this method is that you can call the root logger using class name as the name of the logger. The log messages can show which class that log message came from.

Here is an example of a log message written using first method. All messages will have the logger name as App logger so you won't where it came from.

2022-10-15 09:30:39,262 [1] INFO AppLogger - Logging from Main method

With the second method you can have the class name in the log message as shown in the example below.

2022-10-15 09:34:12,416 [1] INFO ConsoleApp1.Program - Logging from Main method

Preventing duplicate logging with aditivity property

Child loggers in log4net inherit all the appenders of their parent logger. When you use root logger and a named child logger like in Method 2 explained above, all log messages are send to the appenders of the root logger irrespective of which logger is being used. This means some messages will be duplicated. All log messages that are written on comms.log file will be also written on app.log file. To prevent this, you can set the Additivity property to false. By default additivity flag is true. When set to false, the child loggers will not inherit the appenders of its parent. Here is an example.

  <logger name="CommsLogger" additivity="false">
       <level value="ALL" />
       <appender-ref ref="CommsLogFileAppender" />
    </logger>
    <appender name="CommsLogFileAppender" type="log4net.Appender.RollingFileAppender">
	 <param name="File" value="comms.log" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline"/>
     </layout>
   </appender>

Post a comment

Comments

Nothing yet..be the first to share wisdom.