Search code examples
log4netlog4net-configuration

Configuring Log4Net for specific classes and overreaching error handling


I am using Log4Net within my project, and would like to configure it so that debug/info messages go to files specific to each class, and all error messages go to a central file.

Within my application, I have several "workers". I would like each worker to have its own log file to capture debug messages. If I get a debug message that isn't captured on a specific worker, I would like it to be logged to a central debug file. I would also like to have central error logging, where all errors from any of the workers are logged in the same file.

I am having difficulty figuring out the XML configuration to do this. Here is the closest I have come:

  <log4net>
    <appender name="DebugLog" type="log4net.Appender.RollingFileAppender">
      <file value="logs\debug.log" />
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <datePattern value="ddMMyyyy" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="FATAL" />
      </filter>
    </appender>
    <appender name="ErrorLog" type="log4net.Appender.RollingFileAppender">
      <file value="logs\error.log" />
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <datePattern value="ddMMyyyy" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline%stacktrace{1}%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR" />
        <levelMax value="FATAL" />
      </filter>
    </appender>
    <appender name="Worker1" type="log4net.Appender.RollingFileAppender">
      <file value="logs\Worker1.log" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="ddMMyyyy" />
      <maxSizeRollBackups value="100" />
      <maximumFileSize value="100MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="INFO" />
      </filter>
    </appender>
    <appender name="Worker2" type="log4net.Appender.RollingFileAppender">
      <file value="logs\Worker2.log" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="ddMMyyyy" />
      <maxSizeRollBackups value="100" />
      <maximumFileSize value="100MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="INFO" />
      </filter>
    </appender>
    <appender name="Worker3" type="log4net.Appender.RollingFileAppender">
      <file value="logs\3.log" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <datePattern value="ddMMyyyy" />
      <maxSizeRollBackups value="100" />
      <maximumFileSize value="100MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="DEBUG" />
        <levelMax value="INFO" />
      </filter>
    </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="DebugLog" />
      <appender-ref ref="ErrorLog" />
    </root>
    <logger name="Worker1">
      <level value='DEBUG'/>
      <appender-ref ref="Worker1" />
    </logger>
    <logger name="Worker2">
      <level value='DEBUG'/>
      <appender-ref ref="Worker2" />
    </logger>
    <logger name="Worker3">
      <level value='DEBUG'/>
      <appender-ref ref="Worker3" />
    </logger>
  </log4net>

The first issue I have is that all messages written to Worker1's class, are written to the Debug.log file, and the Worker1.log file. I don't want them written to Debug.log if they are already written to Worker1.log.

I can get around this by changing the section, by adding additivity = false. In this case, it writes to the Worker1.log, and not the Debug.log file.

However, doing this prevents errors from being written to Error.log What happens is that if I set additivity = "false" and log an error, it gets written to Worker1.log, but does not get written to Error.log.

Is there any way to have the additivity apply to just the debug/info messages, so that I can have Debug messages in Worker1.log, Error messages in Error.log, and any debug messages that aren't specific to a logger in the debug.log file?


Solution

  • You are right about setting additivity="false" to isolate the debug messages to Worker1.log.

    To get the error messages of Worker1 back into Error.log you also have to include the ErrorLog appender in the Worker1 logger declaration, as shown below.

    <logger name="Worker1" additivity="false">
        <level value='DEBUG'/>
        <appender-ref ref="Worker1" />
        <appender-ref ref="ErrorLog" />
    </logger>
    

    Via this setup you overrule the rules as defined in root to use a custom Worker1 Appender for debug messages and the same Error Appenderfor error messages.