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

时间:2013-12-24 07:32:06

标签: c# logging nlog

在我的应用程序中,我每天处理数千个文档。我想,在某些情况下,一些日志,一个按文档记录。然后我想要一个特定的目标在运行时更改输出文件名(和只有文件名)。

在网络上我发现如何通过编程来创建目标我只想通过编程更新文件名。我试过下面的代码。我收到的错误是“无法找到LayoutRender'logDirectory'。

有什么想法吗?

谢谢,

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;

配置文件是:

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

7 个答案:

答案 0 :(得分:20)

尝试ReconfigExistingLoggers方法:

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

如文档中所述:

  

循环播放GetLogger先前返回的所有记录器。和   重新计算其目标和筛选器列表。修改后有用   以编程方式配置以确保所有记录器都已存在   正确配置。

修改

尝试使用自定义布局渲染器:NLog config file to get configuration setting values from a web.config

答案 1 :(得分:4)

如果您使用NLog Async(<targets async="true">),

Tony's解决方案似乎无法运行。我不得不使用包装器目标来获取我的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();
}

这也不会更改配置文件,只是更改运行时值。所以我也使用下面的代码手动编辑配置文件到我的新值:

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);

答案 2 :(得分:4)

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

target.FileName = "${var:logDirectory}\\file2.txt");

如果需要在运行时修改logDirectory,请使用GDC:

https://github.com/NLog/NLog/wiki/Gdc-layout-renderer

NLog.GlobalDiagnosticsContext.Set("logDirectory","C:\Temp\");

然后您可以使用以下布局:

target.FileName = "${gdc:item=logDirectory}\\file2.txt";

答案 3 :(得分:1)

您收到错误的原因是 NLog对“logDirectory”键名一无所知。您可以自己实施(阅读说明here)或使用here中预定义的内容。

然后,您可以使用here中的指令在运行时更改NLog目标。

答案 4 :(得分:0)

I happen to have written an answer that fits your question as well

从本质上讲,与其尝试尝试重写,不如创建一个允许您动态选择所需文件名的配置,否则会更好。


适合您的用例的示例:

Logger myLog = LogManager.GetLogger(name);
LogLevel level = LogLevel.Error;
string message = "This is an error message!";

您将此信息转换为LogEventInfo对象:

LogEventInfo logEvent = new LogEventInfo(level , myLog.Name, message);

然后可以向该事件添加属性(可以自由选择字符串索引):

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

然后您写入日志:

myLog.Log(logEvent);

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

您在布局中使用${event-properties:item=CustomFileName}来访问属性。例如:

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

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

请注意,您可以对此进行进一步优化,例如只能选择部分文件名。

另一个好处是,您只需在配置文件中一个目标和一个规则即可完成这项工作。

答案 5 :(得分:0)

对于任何坚持这一点的人,我终于找到了解决方案。我试图在运行时更新一些系统日志目标设置,但没有任何反应。仅仅更新配置是行不通的,您需要重置Configuration对象,这很简单:

LogManager.Configuration = LogManager.Configuration;

这会导致内部事件触发并实际使用更新后的配置。

答案 6 :(得分:0)

这对我有用。

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('\'')来删除转换为字符串时添加的多余单引号。