Search code examples
wpflogginglog4netclass-library

log4net logger logging unexpected levels based on config


I have been trying to understand the config of the log4net library and I think I have it except for some unexpected behavior.

I have a root logger that has a level set to INFO and another logger for a specific class that has level set to ERROR.

What I expected from this was that the class logger would only log at error and ignore the roots level since I had additivity set to false for the class logger. Here is the log4net.config I have at the moment:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>

    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>

    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="log.txt" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="100KB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>

    <logger name="EveStatic.Config.ViewModel" additivity="false">
      <level value="error"/>
      <appender-ref ref="ConsoleAppender"/>
      <appender-ref ref="RollingFileAppender"/>
    </logger>

    <root>
      <level value="debug" />
      <appender-ref ref="ConsoleAppender" />
      <appender-ref ref="RollingFileAppender" />
    </root>

  </log4net>
</configuration>

In my AssemblyInfo.cs:

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

And in the class that loads the configuration:

log4net.Config.XmlConfigurator.Configure(new FileInfo("log4net.config"));

These two seem redundant but the configuration wont load unless I have the code part. Everything here is in a class library being used by another project.

Is this behavior expected and I don't understand the configuration and level overrides or am I forgetting something?

EDIT: Here is how I instantiate and call the ILog. The the full class name is the name of the logger in the config plus the ConfiInfoViewModel:

private static readonly ILog LOG = LogManager.GetLogger(typeof(ConfigInfoViewModel));
...
LOG.Debug("Something buggy");

Also note that when testing the logging levels I had a log statement for each level in a series.


Solution

  • Your problem lays here

    LogManager.GetLogger(typeof(ConfigInfoViewModel));
    

    Internally this get resolved to

    LogManager.GetLogger(typeof(ConfigInfoViewModel).FullName);
    

    Now log4net is looking for a Logger named "EveStatic.Config.ConfigInfoViewModel" (result of typeof(ConfigInfoViewModel).FullName)

    Because no Logger with that name is specified a new one with your default settings is used.

    Also note that level specify a threshold, not a single level.
    Example: level=warn means log warn an all levels above (error and fatal)