log4netlog4net-configurationlog4net-appender

log4net configure same appender for two dll namespaces


I would like to understand how can I configure the same appender for two different namesapaces.

I have:

WPF.Client.Foo class in first dll

WPF.Server.Foo class in second dll

I want all logs in both classes to be traced with same appender to the same file.

Currently I passed the same string to the ILog in both classes but I don't like it because in the future maybe I will need to change this name or add additional dlls. I can't use a constant because every dll is independent and do not have references to any other dll.

I don't want to configure two loggers with same appender (and different name/namespase) in the Logger.config file because if the logs are enabled, it should be always enabled for both Dlls and I don't want to update two thresholds in the config file.

Merging the code to one dll is not an option.

Am I wondering if there is an easy way to configure many namespaces to same appender when the namesapaces are completely different and not a child of each other.

Thank you.


Solution

  • You can set up an appender linked to the root logger, and let the appender do the filtering upon the loggers using two LoggerMatchFilter rules.

    The last DenyAllFilter filter in below configuration ensures that anything that doesn't match the expected logger names doesn't appear in the output.

    <log4net>
      <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
    
        <filter type="log4net.Filter.LevelRangeFilter">
          <levelMin value="INFO" />
          <levelMax value="FATAL" />
          <acceptOnMatch value="false" />
        </filter>
    
        <filter type="log4net.Filter.LoggerMatchFilter">
          <loggerToMatch value="WPF.Server.Foo" />
        </filter>
        
        <filter type="log4net.Filter.LoggerMatchFilter">
          <loggerToMatch value="WPF.Client.Foo" />
        </filter>
        
        <filter type="log4net.Filter.DenyAllFilter" />
        
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%date{HH:mm:ss.ffff} Thread: [%thread] %level %logger%exception - %message%newline" />
        </layout>
      </appender>
      
      <root>
        <level value="INFO" />
        <appender-ref ref="ConsoleAppender" />
      </root>  
    </log4net>
    
    namespace WPF.Server
    {
        public class Foo
        { }
    }
    
    namespace WPF.Client
    {
        public class Foo
        { }
    }
    
    public class Program
    {
        public static void Main()
        {
            // Logger configuration left out for brevity.
            
            var logger1 = LogManager.GetLogger(typeof(WPF.Server.Foo));
            logger1.Error("Hello from WPF.Server.Foo"); // Will appear in the log.
    
            var logger2 = LogManager.GetLogger(typeof(WPF.Client.Foo));
            logger2.Error("Hello from WPF.Client.Foo"); // Will appear in the log.
    
            var logger3 = LogManager.GetLogger("WPF.Other"); // Will not appear in the log.
            logger3.Error("Hello from other");
        }
    }