簡體   English   中英

如何在適配器類中包裝NLog

[英]How to wrap NLog in an Adapter Class

這里閱讀了史蒂文(Steven)的答案后,我開始思考切換日志系統以及可以使用的PITA。 接口的簡單性是我最喜歡的,它是原始的,沒有其他項目可以引入,除了編寫用於生成事件的代碼外,什么也沒有。 我已經修改了原始代碼,以便可以在LogEntry的context參數中傳遞類名:

public interface ILogger
{
    void Log(LogEntry entry);
}

public enum LoggingEventType { Debug, Information, Warning, Error, Fatal };

public class LogEntry
{
    public readonly LoggingEventType Severity;
    public readonly string Message;
    public readonly Exception Exception;
    public readonly Type Context;

    public LogEntry(LoggingEventType severity, 
                    string message, 
                    Exception exception = null, 
                    Type context = null)
    {
        if (message == null) throw new ArgumentNullException("message");
        if (message == string.Empty) throw new ArgumentException("empty", "message");

        this.Severity = severity;
        this.Message = message;
        this.Exception = exception;
        this.Context = context;
    }
}

問題1:傳遞類型/上下文參數似乎有什么問題嗎?

這篇文章也為基於Log4net的適配器的編寫提供了一些啟發,盡管我不使用ILogger的構造函數注入,但它還是我的NLog適配器的基礎。

class NLogAdapter : ILogger
{
    public void Log(LogEntry entry)
    {
        NLog.Logger log;
        if (entry.Context != null)
        {
            log = NLog.LogManager.GetLogger(entry.Context.GetType().Namespace);
        }
        else
        {
            log = NLog.LogManager.GetLogger("DefaultLogger");
        }
        switch (entry.Severity)
        {
            case LoggingEventType.Debug:
                log.Debug(entry.Exception, entry.Message);
                break;
            case LoggingEventType.Information:
                log.Info(entry.Exception, entry.Message);
                break;
            case LoggingEventType.Warning:
                log.Warn(entry.Exception, entry.Message);
                break;
            case LoggingEventType.Error:
                log.Error(entry.Exception, entry.Message);
                break;
            case LoggingEventType.Fatal:
                log.Fatal(entry.Exception, entry.Message);
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(entry));
        }
    }
}

問題2:對於每次調用都使用日志管理器我還是不太確定,這是獲取NLog Logger實例的最正確方法嗎? 您還有其他建議嗎?

注意:此適配器可以是DI容器中的單例,也可以將其用作靜態類。

謝謝斯蒂芬

我不確定每次調用都使用日志管理器,這是否是獲取NLog Logger實例的最正確方法? 您還有其他建議嗎?

一種更典型的設計(和高性能)設計是在其中創建一個通用實現,並以其通用參數等於其注入到的類的方式注入一個封閉的通用單例實現,如以下答案所示

class NLogAdapter<T> : ILogger
{
    private static readonly NLog.Logger log =
        NLog.LogManager.GetLogger(typeof(T).FullName);
}

這不僅使您不必在每次調用時都解析NLog記錄器,而且還使您不必將上下文傳遞給LogEntry。

將其注入消費者,將如下所示:

new ProductController(new NLogAdapter<ProductController>())

new HomeController(new NLogAdapter<HomeController>())

如果您使用的是DI容器,則取決於您使用的容器以及必須如何配置它。 例如,對於Simple Injector,只需進行如下上下文注冊即可:

container.RegisterConditional(typeof(ILogger),
    c => typeof(NLogAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true); 

當日志適配器為單例時,這意味着開銷減少到最小。

問題1:傳遞類型/上下文參數似乎有什么問題嗎?

使記錄器實現與環境相關時,無需在記錄期間傳遞諸如此類的環境信息。

重要警告:請勿使ILogger抽象通用(如Microsoft在其日志記錄庫中所做的那樣 ),這只會使使用者及其測試復雜化。 那將是一個嚴重的設計缺陷。

暫無
暫無

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

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