C# 在运行时更新NLog目标文件名

C# 在运行时更新NLog目标文件名,c#,logging,nlog,C#,Logging,Nlog,在我的应用程序中,我每天处理数千份文档。在某些情况下,我想要一些日志,一个日志一个文档。然后,对于特定目标,我希望在运行时更改输出文件名(并且仅更改文件名) logEvent.Properties["CustomFileName"] = "mycustomfilename"; 在网上,我找到了如何通过编程来创建目标,我想通过编程来更新文件名。我尝试了下面的代码。我收到的错误是“LayoutRender找不到'logDirectory' logEvent.Properties["CustomFi

在我的应用程序中,我每天处理数千份文档。在某些情况下,我想要一些日志,一个日志一个文档。然后,对于特定目标,我希望在运行时更改输出文件名(并且仅更改文件名)

logEvent.Properties["CustomFileName"] = "mycustomfilename";
在网上,我找到了如何通过编程来创建目标,我想通过编程来更新文件名。我尝试了下面的代码。我收到的错误是“LayoutRender找不到'logDirectory'

logEvent.Properties["CustomFileName"] = "mycustomfilename";
有什么想法吗

logEvent.Properties["CustomFileName"] = "mycustomfilename";
谢谢

var target = (FileTarget)LogManager.Configuration.FindTargetByName("logfile");
target.FileName = "${logDirectory}/file2.txt";

LoggingConfiguration config = new LoggingConfiguration();
var asyncFileTarget = new AsyncTargetWrapper(target);
config.AddTarget("logfile", asyncFileTarget);

LogManager.Configuration = config;
logEvent.Properties["CustomFileName"] = "mycustomfilename";
配置文件是:

  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <variable name="logDirectory" value="C:/MyLogs"/>
    <targets>
      <target name="logfile" xsi:type="File" layout="${date:format=dd/MM/yyyy HH\:mm\:ss.fff}|${level}|${stacktrace}|${message}" fileName="${logDirectory}/file.txt" />
    </targets>

    <rules>
      <logger name="*" minlevel="Info" writeTo="logfile" />
    </rules>    
  </nlog>
logEvent.Properties["CustomFileName"] = "mycustomfilename";

尝试
重新配置现有记录器
方法:

var target = (FileTarget)LogManager.Configuration.FindTargetByName("logfile");
target.FileName = "${logDirectory}/file2.txt";
LogManager.ReconfigExistingLoggers();
logEvent.Properties["CustomFileName"] = "mycustomfilename";
如文件中所述:

logEvent.Properties["CustomFileName"] = "mycustomfilename";
循环通过GetLogger先前返回的所有记录器。和 重新计算其目标和筛选器列表。在修改 以编程方式进行配置,以确保所有记录器 配置正确

logEvent.Properties["CustomFileName"] = "mycustomfilename";
编辑

logEvent.Properties["CustomFileName"] = "mycustomfilename";

尝试使用自定义布局渲染器:

出现错误的原因是NLog对“logDirectory”keyname一无所知。您可以自己实现它(阅读说明)或使用来自的预定义说明

logEvent.Properties["CustomFileName"] = "mycustomfilename";
然后,您可以使用中的说明在运行时更改NLog目标。

如果您使用NLog异步(
),解决方案似乎不起作用。我必须使用包装器目标来获取我的FileTarget,否则会出现很多错误。我使用的是NLog 2.1

if (LogManager.Configuration != null && LogManager.Configuration.ConfiguredNamedTargets.Count != 0)
{
    Target target = LogManager.Configuration.FindTargetByName("yourFileName");
    if (target == null)
    {
        throw new Exception("Could not find target named: " + "file");
    }

    FileTarget fileTarget = null;
    WrapperTargetBase wrapperTarget = target as WrapperTargetBase;

    // Unwrap the target if necessary.
    if (wrapperTarget == null)
    {
        fileTarget = target as FileTarget;
    }
    else
    {
        fileTarget = wrapperTarget.WrappedTarget as FileTarget;
    }

    if (fileTarget == null)
    {
        throw new Exception("Could not get a FileTarget from " + target.GetType());
    }

    fileTarget.FileName = "SetFileNameHere";
    LogManager.ReconfigExistingLoggers();
}
logEvent.Properties["CustomFileName"] = "mycustomfilename";
这也不会更改配置文件,只会更改运行时值。因此,我还使用以下代码手动将配置文件编辑为新值:

var nlogConfigFile = "NLog.config";
var xdoc = XDocument.Load(nlogConfigFile);
var ns = xdoc.Root.GetDefaultNamespace();
var fTarget = xdoc.Descendants(ns + "target")
         .FirstOrDefault(t => (string)t.Attribute("name") == "yourFileName");
fTarget.SetAttributeValue("fileName", "SetFileNameHere");
xdoc.Save(nlogConfigFile);
logEvent.Properties["CustomFileName"] = "mycustomfilename";

logEvent.Properties["CustomFileName"] = "mycustomfilename";
本质上,与其试图重写配置,不如简单地创建一个允许您动态选择所需文件名的配置

logEvent.Properties["CustomFileName"] = "mycustomfilename";

适用于您的用例的示例:

Logger myLog = LogManager.GetLogger(name);
LogLevel level = LogLevel.Error;
string message = "This is an error message!";
logEvent.Properties["CustomFileName"] = "mycustomfilename";
将此信息转换为
LogEventInfo
对象:

LogEventInfo logEvent = new LogEventInfo(level , myLog.Name, message);
logEvent.Properties["CustomFileName"] = "mycustomfilename";
然后可以向该事件添加属性(字符串索引可自由选择):

logEvent.Properties["CustomFileName"] = "mycustomfilename";
然后写入日志:

logEvent.Properties["CustomFileName"] = "mycustomfilename";
myLog.Log(logEvent);

有趣的是,在NLog配置中,可以在NLog文档称为“布局”值的任何字段中使用此自定义属性

logEvent.Properties["CustomFileName"] = "mycustomfilename";
在布局中使用
${event properties:item=CustomFileName}
访问属性。例如:

logEvent.Properties["CustomFileName"] = "mycustomfilename";
<target xsi:type="File" 
        name="file" 
        fileName="${basedir}/logs/${event-properties:item=CustomFileName}.log"
        layout="${message}" />

按照发布的示例,此消息将记录在
mycustomfilename.log
文件中。通过将
logEvent.Properties[“CustomFileName”]
值设置为您想要使用的任何文件名,您可以根据自己的喜好动态切换目标文件

logEvent.Properties["CustomFileName"] = "mycustomfilename";
请注意,您可以对此进行进一步优化,例如,只能选择部分文件名

logEvent.Properties["CustomFileName"] = "mycustomfilename";

另一个好处是,您只需要在配置文件中设置一个目标和一条规则即可完成此操作。

对于任何陷入此问题的人,我终于找到了解决方案。我试图在运行时更新一些syslog目标设置,但什么都不起作用。仅更新配置不起作用,您需要重置配置图形对象,它与执行此操作一样简单:

logEvent.Properties["CustomFileName"] = "mycustomfilename";
LogManager.Configuration = LogManager.Configuration;

这会引发内部事件并实际使用更新的配置。

如果运行时不需要更改LogDirectory,则可以执行以下操作:

logEvent.Properties["CustomFileName"] = "mycustomfilename";
target.FileName = "${var:logDirectory}\\file2.txt");
如果需要在运行时修改logDirectory,则使用GDC:

logEvent.Properties["CustomFileName"] = "mycustomfilename";

logEvent.Properties["CustomFileName"] = "mycustomfilename";
然后可以使用以下布局:

logEvent.Properties["CustomFileName"] = "mycustomfilename";
target.FileName = "${gdc:item=logDirectory}\\file2.txt";
这对我有用

logEvent.Properties["CustomFileName"] = "mycustomfilename";
using NLog;
using NLog.Targets;
using NLog.Targets.Wrappers;

var target = LogManager.Configuration.FindTargetByName("logfile");
var asyncTarget = target as AsyncTargetWrapper;
var fileTarget = asyncTarget.WrappedTarget as FileTarget;
var file = fileTarget.FileName;
var archiveFile = fileTarget.ArchiveFileName;

//FileName和ArchiveFileName的类型为Layout。ToString提供了字符串表示形式。我们可以对其进行更改并重新分配。请记住放置.Trim('\'')以删除转换为字符串时添加的额外单引号。

或read(如果可能)NLog.config中的logDirectory值发现:尽可能的解决方法尝试添加您自己的布局renderer:重要的是,如果您试图替换部分文件名,
target.filename.ToString()
可能被单引号括起来,因此您不能直接重新应用它,例如
Path.GetDirectoryName(target.FileName.ToString().Trim('\'')
对我不起作用。你有没有找到解决方案?如果没有,我可以提出一些答案。这里有一个非常清楚的答案:这里有一个非常清楚的答案:我使用的是Visual Studio 2017和.net core 2.2。对于Tony的解决方案,它不会起作用,因为我没有在目标对象之外公开文件名属性。非常感谢你的帮助我们的解决方案。使用
${var:…}
在NLog 4.1之后,在布局中这样做似乎是一种正确的方法,请参阅。但请注意,据说它只在布局中工作,而不是在常规字符串中。@Mikhail在解决此问题之前,我更喜欢GDC:感谢您指出线程安全问题。虽然对我来说这不是一个问题。现在更让我担心的是中提到的性能问题问题。你看到GDC和var的性能比较了吗?我所说的性能影响是将旧式变量如
${myvar}
与新样式
${var:myvar}
${var:myvar}
的开销与
${GDC:myvar}
相同,但
${var:myvar}
与AsyncWrapper一起使用时会受到额外的性能损失,因为NLog引擎无法延迟渲染(因为
${var:myvar}
能够使用需要预先捕获线程上下文的动态布局)。
logEvent.Properties["CustomFileName"] = "mycustomfilename";