首页 > 解决方案 > 以编程方式将 NLog 目标切换到/从异步

问题描述

很长一段时间以来,我一直在尝试以编程方式打开和关闭 NLog 异步开关。我无处可去。我的代码似乎可以执行我想要的操作,但是在进行更改后,我根本没有记录。这是我到目前为止发现的:

当 NLog 配置文件包含async=true时,在运行时,我将为LogManager.Configuration.AllTargets配置文件中的每个目标设置两个目标 ()。一个是原始目标,最后用“_wrapped”重命名。另一个是包裹在 中的原始(现在重命名)目标AsyncTargetWrapper,并给出了我原始目标的名称。

在做任何事情(打开或关闭异步)之前,我首先清除所有LoggingRules.

要关闭异步,我从 中获取包装的目标AsyncTargetWrapper,将其重命名为原始名称,删除包装器目标(这似乎也删除了原始目标),然后重新添加原始目标(现在已赋予其原始名称再次)。然后我创建一个LoggingRule并设置适当的日志记录级别。最后,我打电话给LogManager.ReconfigExistingLoggers(). 在这一点上,有些东西坏了,因为我不会得到任何日志记录。

打开异步时我遵循类似的过程,除了这一次,我重命名原始目标,为其创建一个AsyncTargetWrapper,然后添加新的包装器目标。LoggingRule同样,我为新目标创建一个并设置日志记录级别。在这一点上,有些东西坏了,因为我不会得到任何日志记录。

代码如下:

LogManager.Configuration.LoggingRules.Clear();

if (async) // turning async ON
{
    foreach (var target in LogManager.Configuration.AllTargets)
    {
        if (!(target is AsyncTargetWrapper))
        {
            string targetName = target.Name;
            // rename the synchronous target to indicate that it is going to be wrapped by another target (an asynchronous wrapper)
            target.Name = $"{target.Name}_wrapped";

            // create an asynchronous target wrpper and give it the name of the synchronous target's original (non-wrapped) name
            AsyncTargetWrapper asyncTarget = new AsyncTargetWrapper(target) { Name = targetName };

            LogManager.Configuration.AddTarget(asyncTarget);

            LoggingRule asyncRule = new LoggingRule("*", asyncTarget);
            if (_minLevel != null && _maxLevel != null)
            {
                asyncRule.EnableLoggingForLevels(_minLevel, _maxLevel);
            }
            else
            {
                foreach (var level in LogLevel.AllLevels.Except(new List<LogLevel>() { LogLevel.Off }))
                {
                    if (Logger.IsEnabled(level)) asyncRule.EnableLoggingForLevel(level);
                }
            }
        }
    }
}
else // turning async OFF
{
    foreach (var target in LogManager.Configuration.AllTargets)
    {
        if (target is AsyncTargetWrapper)
        {
            // get the wrapped (synchronous) target from the wrapper
            Target syncTarget = ((AsyncTargetWrapper)target).WrappedTarget;

            // rename the synchronous target (remove "_wrapped" from the end of its name)
            syncTarget.Name = target.Name.Replace("_wrapped", "");

            // remove the wrapper target
            LogManager.Configuration.RemoveTarget(target.Name);

            LogManager.Configuration.AddTarget(syncTarget);

            // create a rule for the wrapped (synchronous) target
            LoggingRule syncRule = new LoggingRule("*", syncTarget);

            // set the logging level for the synchronous target
            if (_minLevel != null && _maxLevel != null)
            {
                syncRule.EnableLoggingForLevels(_minLevel, _maxLevel);
            }
            else
            {
                foreach (var level in LogLevel.AllLevels.Except(new List<LogLevel>() { LogLevel.Off }))
                {
                    if (Logger.IsEnabled(level)) syncRule.EnableLoggingForLevel(level);
                }
            }
        }
    }
}

LogManager.Configuration.Reload();
LogManager.ReconfigExistingLoggers();

我认为不需要最后两行,但我尝试了它们,因为没有其他方法起作用。

必须有正确的方法来翻转异步标志,但我不知道它是什么。谁能告诉我该怎么做?

标签: c#.netasynchronousnlog

解决方案


我发现了问题。过去我有一个有效的实现,所以这对我来说非常混乱。我的旧实现存在问题,所以我决定重构它,但在新实现中犯了一个错误。我遗漏了关键的代码行!新的日志记录规则必须在创建后添加到配置中:

LogManager.Configuration.LoggingRules.Add(syncRule);

现在它完全按照我的意愿工作。哇!


推荐阅读