[.NET][log4net]ConsoleAppender Failed in DoAppend

最近為了加快寫log速度於是使用了log4net中的BufferingForwarder:她可以將log訊息寫入Buffer,等到Buffer滿到指定數目或是Process結束後再將log輸出到到檔案!

這兩天又有需求想在執行過程即時看到log訊息,於是在log4net訂了第兩組輸出媒體: ConsoleAppender

 

 

加上Console 這組設定後,BufferingForwarder繼續正確的寫出log,但程式執行時,在ConsoleAppender吐出以下的訊息:

log4net:ERROR [ConsoleAppender] Failed in DoAppend

System.NullReferenceException: 並未將物件參考設定為物件的執行個體。

神奇的是,如果停用BufferingForwarder,ConsoleAppender就可以正常運作,兩個人好像不能和平共處,就像磁鐵的同性互斥。

 

模擬程式碼

1.程式碼先參考這篇引用log4net BufferForwarder

新增Console專案,然後在program.cs加入以下程式碼

private static readonly ILog Logger = LogManager.GetLogger("Test");
static void Main(string[] args)
{
    XmlConfigurator.Configure(new FileInfo(string.Format(@"{0}\{1}",
       Directory.GetParent(Directory.GetParent(Environment.CurrentDirectory).FullName),
       "log4net.config")));
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < 10; i++)
    {
        Logger.Debug(string.Format("this is no{0} log", i + 1));
    }
    sw.Stop();
    Console.WriteLine($"總耗時(ElapsedMilliseconds) = {sw.ElapsedMilliseconds}");

}

2.log4net.config輸入以下內容

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

  <root>
    <level value="All"/>
    <appender-ref ref="BufferingForwarder" />
    <appender-ref ref="ConsoleAppender"/>
  </root>

 <appender name="BufferingForwarder" type="log4net.Appender.BufferingForwardingAppender">
    <bufferSize value="512" />
    <lossy value="false" />
    <Fix value="8" />
    <appender-ref ref="RollingFile" />
  </appender>
  
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file type="log4net.Util.PatternString" value="Log/Log-%date{yyyyMMdd}/Debug.log" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 
    <appendToFile value="true"/>
    <rollingStyle value="Composite"/>
    <maxSizeRollBackups value="-1"/>
    <maximumFileSize value="50MB"/>
    <staticLogFileName value="true"/>
    <datePattern value="yyyy-MM-dd"/>
    <countDirection value="1"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date{ISO8601} [%2thread] - %message%newline%exception"/>
    </layout>
  </appender>

  <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%d{yyyy/MM/dd HH:mm:ss.fff} %m  %C %l %exception %n" />
    </layout>
  </appender>

</log4net>

專案檔結構:

 

3.執行結果:

檔案輸出的部分:

但console就沒有把log輸出了!而且出現了Failed in DoAppend

System.NullReferenceException: 並未將物件參考設定為物件的執行個體。

 

 

Try了幾種組合,找到臨時解決的辦法1: 

改變config順序

把ConsoleAppender往前移到第一組config,兩個輸出Appender都正常寫出了!

修改前

  <root>

    <level value="All"/>

    <appender-ref ref="BufferingForwarder" />

    <appender-ref ref="ConsoleAppender"/>

  </root>

 

改好之後

  <root>

    <level value="All"/>

    <appender-ref ref="ConsoleAppender"/>

    <appender-ref ref="BufferingForwarder" />

  </root>

 

重新執行測試!log就有寫出到console了

 

conversionPattern value

仔細比較兩組config發現conversionPattern value 不太相同!

config conversionPattern
BufferingForwarder

%date{ISO8601} [%2thread] - %message%newline%exception

ConsoleAppender

%d{yyyy/MM/dd HH:mm:ss.fff} %m  %C %l %exception %n

 

臨時解決辦法2:

試著把ConsoleAppender改成與BufferingForwarder相同的conversionPattern value,問題也可以排除。

 

小結:

  • 猜測log4net載入第一組BufferingForwarder的conversionPattern可能有出現問題或是這組太客製,因此就跳過ConsoleAppender的conversionPattern,當log4net要輸出log到console時就出現了NullReferenceException。
  • 之後再來深入研究

 

參考:

log4net PatternLayout Class