[英]Programmatically switch NLog targets to/from async
很長一段時間以來,我一直試圖以編程方式打開和關閉 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();
我認為不需要最后兩行,但我嘗試了它們,因為沒有其他任何工作。
必須有正確的方法來翻轉異步標志,但我不知道它是什么。 誰能告訴我怎么做?
我發現了問題。 我過去有一個有效的實現,所以這對我來說非常混亂。 我的舊實現有問題,所以我決定重構它,但在新實現中犯了錯誤。 我遺漏了關鍵的代碼行! 新的日志規則必須在創建后添加到配置中:
LogManager.Configuration.LoggingRules.Add(syncRule);
現在它完全按照我的意願工作。 哇!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.