簡體   English   中英

在自定義TraceListener中使用log4net的LogManager.GetLogger()會引發NullReferenceException

[英]log4net's LogManager.GetLogger() throws NullReferenceException when used in custom TraceListener

我正在嘗試將大型應用程序從使用Trace類過渡到通過log4net輸出通知。 這樣,我編寫了一個自定義的TraceListener以將輸出重定向到log4net的消息傳遞中(受本文章的啟發)。

public class Log4netTraceListener : TraceListener
{
    private static readonly ILog logger = LogManager.GetLogger("Log4netTraceListener"); // Line 19

    public Log4netTraceListener() { /* nothing special */ }

    public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
    {
        // some switching based on the TraceLevel, but eventually something like:
        logger.Error(message);
    }
}

控制台應用程序解決方案是三個項目:

  1. RunShipOrder-控制台項目,它是應用程序的入口點
  2. ShipOrderAPI-一個類庫項目,其中包含與此過程相關的所有代碼
  3. CodeLibrary-一個類庫項目,其中包含許多項目之間通用的代碼。
    • Log4netTraceListener在此項目中

RunShipOrder項目中,我可以調用LogManager.GetLogger("Log4netTraceListener") ,它可以按預期工作。 但是,如果我嘗試在Trace上調用方法,則會引發異常。 我已將其追溯到Log4netTraceListener類內部對LogManager.GetLogger("Log4netTraceListener")的初始調用。

引發的異常是ConfigurationErrorsException ,內部異常是TypeInitializationException ,內部異常是NullReferenceException 最里面的異常的堆棧跟蹤是:

   at log4net.Core.LoggerManager.GetLogger(Assembly repositoryAssembly, String name)
   at log4net.LogManager.GetLogger(Assembly repositoryAssembly, String name)
   at log4net.LogManager.GetLogger(String name)
   at CodeLibrary.Diagnostics.Log4netTraceListener..cctor() in Log4netTraceListener.cs:line 19

關於在log4net代碼庫中可能引發此異常的任何想法?

@drovani-出色的描述。 我看到了同樣的症狀。 在我的案例中,問題在於app.config中的System.Diagnostics.Trace輸出配置為自定義System.Diagnostics.TraceListener實現,該實現將跟蹤轉發到log4net,同時通過log4net.Internal啟用了log4net的內部調試。在app.config中Debug = True(或在通過log4net.Util.LogLog.InternalDebugging = true的代碼中)。

可能發生的情況是,您在靜態初始化期間或在登錄之前在自定義System.Diagnostics.TraceListener實現中調用LoggerManager.GetLogger()。這會產生靜態初始化排序問題。 log4net在初始化時但在LoggerManager初始化之前嘗試記錄某些內容。 因此,LoggerManager.GetLogger()引發空引用異常。

在您的自定義TraceListener中,可以通過使用靜態屬性在首次使用時而不是在字段中初始化ILogger來對此加以防范,但是您在這里需要小心。 最好的做法是不記錄日志,或者如果log4net.Util.LogLog.InternalDebugging為true,則使用其他機制記錄日志。 這將是首選的解決方案。

看一下log4net.Util.LogLog類的源代碼。 默認情況下,這會記錄到跟蹤中,如果由此記錄任何內容(例如追加器錯誤),您最終將陷入僵局。 在您的TraceListener的實現中,我將確保在實現的構造函數中設置log4net.Util.LogLog.EmitInternalMessages = false,並可能處理LogLog.LogReceived事件並以其他方式記錄這些消息。 可悲的是,由於此設置,某些追加器錯誤將不會被記錄。 log4net源是您的朋友。

如果您真的很棘手,會對性能產生巨大影響,則需要在記錄消息和創建記錄器之前檢查log4net.Util.LogLog.InternalDebugging的設置。 如果啟用,您可以獲取堆棧跟蹤並遍歷它,以確保在調用log4net之前log4net不在堆棧中。 如果log4net在堆棧跟蹤中,則可以釘住OutputDebugString()或使用其他日志記錄機制來跟蹤log4net內部日志輸出。 您絕對不希望將內部log4net調試消息重定向到log4net,否則會冒一個與該出色站點類似命名的異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM