NLog簡易入門

NLog簡易入門

NOTE: 本文章由 赤石俊哉 翻譯整理,您可以以學習交流爲目的進行任意使用。如需商用請徵得原作者以及譯者的同意。

安裝NLog

NLog可以從Nuget上下載。
你只需要安裝NLog.Config包,它將會同時安裝NLogNLog.Schema包。
最後將會爲工程添加一個初級的設置和智能補全(Intellisense)。
使用GUI或者在程序包管理命令行中輸入:

Install-Package NLog.Config

你現在就可以編譯你的程序然後開始使用NLog了。

創建Log信息

NOTE【譯者注】
Log就是常說的日誌信息。

爲了從你的程序中創建你所需要的日誌消息你需要使用日誌記錄API。LoggerLogManager這兩個類將會很經常的被使用到,它們都在NLog命名空間裏面。
Logger代表了一些被命名的日誌源,而且他們有可以發出日誌消息的成員方法。
LogManager則是用於創建和管理Logger對象的實例。

有一點你必須要理解的很重要的是,Logger並不代表任何特定的日誌輸出(因此,它並不與任何特定的日誌文件等相關聯),它只是一個源,它通常對應你代碼中的一個類。
從日誌源到輸出型式的映射通過配置文件配置API分開定義。
保持這樣的分離是爲了讓你可以在代碼中繼續寫日誌聲明,通過更新一處的設置可以簡單地變換日誌的輸出型式和輸出位置。

創建Logger對象

建議爲每一個類單獨創建一個(private static)Logger對象。就如我們之前所說的,你需要使用LogManager去創建Logger的實例。
下面的代碼將會創建一個和class有着相同名字的Logger

namespace MyNamespace
{
  public class MyClass
  {
    private static Logger logger = LogManager.GetCurrentClassLogger();
  }
}

管理Logger的名字也是可以的:

using NLog;

Logger logger = LogManager.GetLogger("MyClassName");

因爲Logger對象是線程安全的,所以你可以簡單地創建它並存放在一個static變量中。

日誌級別

每一個日誌消息都用一個日誌級別來修飾,它們用來識別消息的重要性和具體細節。NLog可以以Logger對象的名稱和日誌級別爲主,路由日誌消息。

NLog支持下面的日誌級別:

  • Trace - 特別細節的日誌,可能包含大量的信息,比如說協議的負載。這個日誌級別通常只會在開發期間被啓用。
  • Debug - Debug信息,比Trace的信息量要少一些,通常不會在生產環境下使用。
  • Info - 信息消息,這個是在生產環境下經常使用到的。
  • Warn - 警告消息,通常用來指示非關鍵性的問題,這些問題可以被恢復或者只是臨時錯誤。
  • Error - 錯誤消息 - 大多數時候,他們都是Exception(異常)。
  • Fatal - 特別嚴重的錯誤!

書寫日誌消息

你可以簡單地通過調用Logger對象的其中一個成員方法來書寫日誌消息。Logger類有六個成員函數,和它們的日誌級別相符合:Trace(),Debug(),Info(),Warn(),Error(),Fatal()
當然,也有一個成員函數叫Log(),你可以將日誌級別作爲參數來調用這個方法。

using NLog;

public class MyClass
{
  private static Logger logger = LogManager.GetCurrentClassLogger();

  public void MyMethod1()
  {
    logger.Trace("Sample trace message");
    logger.Debug("Sample debug message");
    logger.Info("Sample informational message");
    logger.Warn("Sample warning message");
    logger.Error("Sample error message");
    logger.Fatal("Sample fatal error message");

    // alternatively you can call the Log() method 
    // and pass log level as the parameter.
    logger.Log(LogLevel.Info, "Sample informational message");
  }
}

日誌消息也可以被參數化 - 你可以使用字符串格式,就像你在Console.WriteLine()String.Format()中一樣:

using NLog;

public class MyClass
{
  private static Logger logger = LogManager.GetCurrentClassLogger();

  public void MyMethod1()
  {
    int k = 42;
    int l = 100;

    logger.Trace("Sample trace message, k={0}, l={1}", k, l);
    logger.Debug("Sample debug message, k={0}, l={1}", k, l);
    logger.Info("Sample informational message, k={0}, l={1}", k, l);
    logger.Warn("Sample warning message, k={0}, l={1}", k, l);
    logger.Error("Sample error message, k={0}, l={1}", k, l);
    logger.Fatal("Sample fatal error message, k={0}, l={1}", k, l);
    logger.Log(LogLevel.Info, "Sample informational message, k={0}, l={1}", k, l);
  }
}

TIP: 你應當儘量避免自己進行字符串格式化來替代使用NLog中內建的格式化方法(比如:連接,以及自行調用String.Format())。具體原因表現在:
格式化日誌消息需要花費很長時間,所以NLog嘗試將格式化操作推遲到了當日志消息需要被輸出的時候。如果消息的最後處理被跳過了,由於日誌記錄配置,你將不需要花費時間在String.Format()上。具體參見日誌記錄性能最優化。

配置

雖然到現在爲止我們已經學習瞭如何從代碼中創建日誌消息,但是我們還沒有對我們的日誌進行任何的配置輸出。所以,當你運行你的測試應用程序時,你將會看到……好吧,啥都沒有。現在我們打開NLog.config文件然後添加一些日誌規則:

  1. <targets>部分中,添加:
<target name="logfile" xsi:type="File" fileName="file.txt" />

這將會定義一個目標,日誌將會被輸出到一個叫做file.txt的文件中。

  1. <rules>部分中,添加:
<logger name="*" minlevel="Info" writeTo="logfile" />

這個片段將會引導Info級別以及更高級別(包括Info,Warn,ErrorFatal)的所有日誌(name="*")輸出到一個已命名爲logfile的目標。

注意,當你將這個在Visual Studio中輸入時,你應該可以看到IntelliSense會建議屬性名並且驗證他們的值。最後的配置文件應該像這樣:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <targets>
        <target name="logfile" xsi:type="File" fileName="file.txt" />
    </targets>

    <rules>
        <logger name="*" minlevel="Info" writeTo="logfile" />
    </rules>
</nlog>

多個目標

讓我們來試試更復雜的東西吧。想象一下你想要將非常細節的日誌發送到一個文件,而且你也希望在控制檯窗口中看到他們,但是在控制檯窗口中細節稍微少一些。下面的配置文件可以實現這樣的需求:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <targets>
        <target name="logfile" xsi:type="File" fileName="file.txt" />
        <target name="console" xsi:type="Console" />
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="logfile" />
        <logger name="*" minlevel="Info" writeTo="console" />
    </rules>
</nlog>

如你所見,我們現在有多個目標,而且有多個規則來路由日誌到目標。

Logger指定的路由

還有一個比較常見的應用場景則是,需要爲當前正在開發的組件提供更多細節的日誌,而其他的組件將會減少輸出。我們就可以用這樣的配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <targets>
        <target name="logfile" xsi:type="File" fileName="file.txt" />
    </targets>

    <rules>
        <logger name="SomeNamespace.Component.*" minlevel="Trace" writeTo="logfile" final="true" />
        <logger name="*" minlevel="Info" writeTo="logfile" />
    </rules>
</nlog>

第一個規則將會將以SomeNamespace.Component開頭的Logger對象的Trace級別及以上級別的日誌發送到日誌文件。屬性final=true將會使得在寫入操作之後停止進一步處理。
第二個規則將會將剩下的日誌發送到同一個日誌文件,但是這些日誌有一個約束,那就是級別需要是Info或更高。

封裝器

NLog支持特殊類型的目標,從而不需要它們自己做任何日誌記錄,而是修改其他Logger的行爲。這些特殊的目標就稱之爲封裝器。最常用的封裝器有:
* ImpersonatingWrapper - 在寫入期間冒充另一個用戶。
* AsyncWrapper - 提供異步操作,目標的寫入的緩衝執行。
* FallbackGroup - 提供錯誤時回滾。
* FilteringWrapper - 用一些條件爲基礎從整體日誌中進行篩選。
還有很多其他的封裝器可以使用,具體列表你可以看這裏

爲了使用封裝器,簡單地使用一對括起來的<target />元素用來表示封裝器,然後在<rules/>部分中使用封裝器的名字,下面是一個例子:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <targets>
        <target name="asyncFile" xsi:type="AsyncWrapper">
            <target name="logfile" xsi:type="File" fileName="file.txt" />
        </target>
    </targets>

    <rules>
        <logger name="*" minlevel="Info" writeTo="asyncFile" />
    </rules>
</nlog>

這樣文件的全部寫入操作都是異步的了,將會提高調用線程的響應速度。

層級

層級提供了一個當日志被寫入文件時,指定日誌內容格式的方法。主要有兩種層級:

  • 簡單層級 - 使用層級渲染器撰寫。
  • 結構層級 - 可以輸出XML、CSV、以及其他複雜的格式。

簡單層級就是一個字符串,在${}中嵌入一些特殊的標記。比如下面的聲明將會使得每一條日誌消息都是用一個格式爲yyyMMddHHmmss:的日期前綴:

<target name="logfile" xsi:type="File" fileName="file.txt" layout="${date:format=yyyyMMddHHmmss} ${message}" />

高級

展開Logger對象到子對象

當我們希望將Logger對象展開到子對象的時候,我們可以使用下面的代碼:

class BaseClass
{      
    protected BaseClass()
    {
        Log = LogManager.GetLogger(GetType().FullName);
    }

    protected Logger Log { get; private set; }
}

class ExactClass : BaseClass
{
    public ExactClass() : base() { }
    ...
}

在父類(BaseClass)的構造函數中,LogManger.GetLogger()方法不應該使用Type參數自變量,也就是:

protected BaseClass()
{
    Log = LogManager.GetLogger(GetType().FullName, GetType());
}

這樣調用會引發一個異常。

萬一ExactClass有一個默認的調用了BaseClass構造函數的構造函數,那麼,System.StackOverflowException就會被引發。這是因爲在異常被引發之前,ExactClass嘗試着調用了BaseClassGetLogger(String, Type)來構造ExactClass

ExactClass => BaseClass => ExactClass => BaseClass => ...

ExactClass不存在默認的構造函數時,GetLogger(String, Type)方法調用不知道如何去構造ExactClass,則引發NLog.NLogConfigurationException

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章