[C#] 將NLog輸出到RichTextBox,並在運行時動態修改日志級別過濾


作者: zyl910

一、緣由

NLog是一個很好用的日志類庫。利用它,可以很方便的將日志輸出到 調試器、文件 等目標,還支持輸出到窗體界面中的RichTextBox等目標。
而且它還支持在運行時修改配置,例如可用於實現這樣的需求——在界面上做個下拉框,可動態調整RichTextBox的日志級別過濾。

二、輸出到RichTextBox

2.1 辦法

首先,項目中需要加入NLog的程序包。既用 NuGet 下載這些包——

  • NLog
  • NLog.Config
  • NLog.Windows.Forms

隨后便可修改 NLog.config 文件,增加RichTextBox目標了。
這時有2點需注意——

  1. RichTextBox的target配置中,formName是“RichTextBox所在窗體的類名”,controlName是“該窗體中的RichTextBox控件名”。區分大小寫,需要完全一致。
  2. 在NLog加載配置前,需要確保該RichTextBox已存在。

若以上2條中有任意一條不符時,NLog會自動彈出一個含RichTextBox的小窗口來顯示日志,而不是你所指定的RichTextBox。
這2中,第1條是很容易實現的,就是第2條稍微麻煩一點。它的處理訣竅是,不要做靜態初始化,而是要等到窗體的Load事件時才初始化Logger對象,且保證該窗體是首個使用NLog的類。這是因為NLog是在首次被使用時,才加載配置文件的。

即不能這樣寫——

private static Logger logger = LogManager.GetCurrentClassLogger();

而是要這樣寫——

private static Logger logger = null;

private void MainForm_Load(object sender, EventArgs e) {
    if (null == logger) {
        logger = LogManager.GetCurrentClassLogger();
    }
}

2.2 范例

假設窗體名(formName)為MainForm,RichTextBox控件名為rtbLog。那么 NLog.config 配置文件可寫成這樣——

<?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"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">

    <targets async="true">
        <target xsi:type="Debugger" name="debugger" layout="${longdate} ${level:uppercase=true} [${threadname}] ${message} ${onexception:${exception:format=tostring} ${newline}}" />
        <target xsi:type="File" name="f"
                fileName="${basedir}/logs/${shortdate}.log"
                layout="${longdate} ${level:uppercase=true} [${threadname}] ${message} ${onexception:${exception:format=tostring} ${newline}}"
                encoding="utf-8" />
        <target xsi:type="RichTextBox" name="richTextBox"
          layout="${longdate} ${level:uppercase=true} [${threadname}] ${message} ${onexception:${exception:format=Message}}"
          autoScroll="true"
          maxLines="1000"
          formName="MainForm"
          controlName="rtbLog"
          useDefaultRowColoringRules="false" />
    </targets>

    <rules>
        <logger name="*" minlevel="Debug" writeTo="debugger" />
        <logger name="*" minlevel="Info" writeTo="f" />
        <logger name="*" minlevel="Info" writeTo="richTextBox" />
    </rules>
</nlog>

上面的配置文件還演示了這些功能——

  • 將日志輸出到調試器(Debugger)。
  • 將日志輸出到文件(File)。且是log子目錄下每天一個文件(fileName="${basedir}/logs/${shortdate}.log"),編碼指明為utf-8(encoding="utf-8")避免gbk外字符亂碼。
  • 采用不同的日志字符串格式(layout)。RichTextBox只顯示異常消息(Message),而不顯示包含錯誤棧的異常詳情(tostring)。
  • 目標都是異步模式(<targets async="true">)。
  • 支持自動重新加載配置(autoReload="true")。

三、動態修改日志級別

3.1 需求

首先,NLog支持自動重新加載配置的機制,可參考上面配置的 autoReload="true"。即修改NLog.config的配置,會對運行中的程序也是生效的,這樣便無需重啟程序了。

但對於RichTextBox輸出的日志來說,上述機制還不夠方便。最好是界面上提供一些直接調整日志配置的功能。例如——RichTextBox最初的最小日志級別為Info級,當想看詳細日志時,可點界面的下拉框,便可將最小日志級別改為Debug級。

3.2 辦法

NLog提供了動態修改配置的接口。

調用 LogManager.Configuration ,可得到 LoggingConfiguration 對象。它就是當前的配置數據。
然后可通過 LoggingConfiguration.LoggingRules,獲取日志規則集合(即 <rules>)。這樣便能就行修改對應的配置了。
最后別忘了調 LogManager.ReconfigExistingLoggers,使修改的配置生效。

3.3 范例

可這樣實現下拉選擇RichTextBox日志級別過濾的功能——在窗體放一個名為 cboLogLevelMin 的下拉框,配好屬性,然后處理它的 SelectedIndexChanged 事件。

private void cboLogLevelMin_SelectedIndexChanged(object sender, EventArgs e) {
    if (null == cboLogLevelMin.SelectedItem) return;
    String str = cboLogLevelMin.SelectedItem.ToString();    // 獲取日志級別.
    LogLevel lv = LogLevel.Info;    // 若選擇的值無效, 則當作 Info級.
    try {
        lv = LogLevel.FromString(str);
    } catch (Exception ex) {
        if (null == logger) return;
        logger.Debug(ex, "LogLevel.FromString fail!");
    }
    LoggingConfiguration lc = LogManager.Configuration;    // 取得 NLog 配置.
    LoggingRule lr = lc.LoggingRules.FirstOrDefault(
        r => r.Targets.Any(
            t => "richTextBox" == t.Name
        )
    );    // 查找 RichTextBox 所用的 LoggingRule .
    if (null != lr) {
        lc.LoggingRules.Remove(lr);    // 刪除舊的 LoggingRule .
    }
    lc.AddRule(lv, LogLevel.Fatal, "richTextBox");    // 新增 LoggingRule .
    LogManager.ReconfigExistingLoggers();    // 使配置生效.
}

參考文獻

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM