[C#] Output NLog to RichTextBox and dynamically modify log level filtering at runtime

Author: zyl910

1. Reason

NLog is a very useful logging library. Using it, you can easily output logs to targets such as debuggers and files, and also support targets such as RichTextBox in the form interface.
And it also supports modifying the configuration at runtime, for example, it can be used to achieve such a requirement - a drop-down box on the interface can dynamically adjust the log level filtering of RichTextBox.

2. Output to RichTextBox

2.1 Methods

First, the NLog package needs to be added to the project. Download these packages with NuGet -

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

Then you can modify the NLog.config file to add the RichTextBox target.
There are 2 points to note at this time -

  1. In the target configuration of RichTextBox, formName is "the class name of the form where the RichTextBox is located", and controlName is "the RichTextBox control name in this form". It is case sensitive and needs to be exactly the same.
  2. Before NLog loads the configuration, you need to make sure that the RichTextBox already exists.

If any of the above 2 items do not match, NLog will automatically pop up a small window with RichTextBox to display the log instead of the RichTextBox you specified.
Of these 2, the first item is easy to implement, but the second item is a little more troublesome. The trick is to not do static initialization, but to initialize the Logger object until the Load event of the form, and ensure that the form is the first class to use NLog. This is because NLog loads the configuration file when it is first used.

That is, it cannot be written like this-

private static Logger logger = LogManager.GetCurrentClassLogger();

Instead, write it like this-

private static Logger logger = null;

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

2.2 Examples

Suppose the form name (formName) is MainForm, and the name of the RichTextBox control is rtbLog. Then the NLog.config configuration file can be written like this -

<?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>

The above configuration file also demonstrates these features -

  • Output logs to the debugger (Debugger).
  • Output the log to a file (File). And it is a file ( ) per day in the log subdirectory fileName="${basedir}/logs/${shortdate}.log", and the encoding is specified as utf-8 ( encoding="utf-8") to avoid garbled characters outside gbk.
  • Use a different log string format (layout). The RichTextBox only displays the exception message (Message), not the exception details (tostring) containing the error stack.
  • The targets are all in async mode ( <targets async="true">).
  • Supports automatic reload configuration ( autoReload="true").

3. Dynamically modify the log level

3.1 Requirements

First of all, NLog supports the mechanism of automatically reloading the configuration, you can refer to the configuration above autoReload="true". That is, modifying the configuration of NLog.config will also take effect on the running program, so there is no need to restart the program.

But for the logs output by RichTextBox, the above mechanism is not convenient enough. It is best to provide some functions to directly adjust the log configuration on the interface. For example, the initial minimum log level of RichTextBox is Info level. When you want to see detailed logs, you can click the drop-down box on the interface to change the minimum log level to Debug level.

3.2 Methods

NLog provides an interface to dynamically modify the configuration.

Call LogManager.Configuration to get the LoggingConfiguration object. It is the current configuration data. Logging rules collection (ie )
can then be obtained through LoggingConfiguration.LoggingRules . <rules>This will allow you to modify the corresponding configuration.
Finally, don't forget to tune LogManager.ReconfigExistingLoggersto make the modified configuration take effect.

3.3 Examples

The function of drop-down selection of RichTextBox log level filtering can be realized in this way - put a drop-down box named cboLogLevelMin in the form, match the properties, and then handle its SelectedIndexChanged event.

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();    // 使配置生效.
}

references

(over)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324589403&siteId=291194637