C# 我可以将自定义属性传递到NLOG并输出到文件吗?

C# 我可以将自定义属性传递到NLOG并输出到文件吗?,c#,nlog,C#,Nlog,编辑4:“From”在NLog中似乎是一个保留字。将其更改为“FromID”有效。这是一种将变量传递给NLog并保持代码整洁的好方法!!!!谢谢迈克 编辑3。我真的很喜欢这个主意 按照Mike的建议实现了一个助手类: public class NLogHelper { // // Class Properties // private Logger m_logger; private Dictionary<string, object> m_p

编辑4:“From”在NLog中似乎是一个保留字。将其更改为“FromID”有效。这是一种将变量传递给NLog并保持代码整洁的好方法!!!!谢谢迈克

编辑3。我真的很喜欢这个主意

按照Mike的建议实现了一个助手类:

public class NLogHelper
{
    //
    // Class Properties
    //
    private Logger m_logger;
    private Dictionary<string, object> m_properties;


    //
    // Constructor
    //
    public NLogHelper(Logger logger)
    {
        m_logger = logger;
        m_properties = new Dictionary<string, object>();
    }

    //
    // Setting Logger properties per instancce
    //
    public void Set(string key, object value)
    {
        m_properties.Add(key, value);
    }

    //
    // Loggers
    //
    public void Debug(string format, params object[] args)
    {
        m_logger.Debug()
            .Message(format, args)
            .Properties(m_properties)
            .Write();
    }
以及在配置文件中设置的目标,如下所示:

<target xsi:type="File"
    name ="LogFile" fileName="C:\QRT\Logs\QRTLog-${shortdate}.log"
    layout ="${date}|${level}|${event-properties:item=From}|${message} "/>
问题是我必须为调用格式化字符串(但这是一笔巨大的性能交易)。。。但这看起来像是一个黑客

理想情况下,我会在自定义布局渲染器中声明属性,而不是在配置文件中设置这些属性,我的类的每个实例都会设置属性。。。类似于整个班级的
[ID=muid]
。这样,每当从该类调用NLog时,都会设置ID属性,并且NLog的自定义布局渲染器可以使用该属性输出它。我说得通吗

我是NLog新手,一直在寻找自定义渲染器。 基本上,我的目标是让我的日志语句:
\u logger.Debug(“我的名字是{0}”,“Ed”,ID=87)

我希望我的渲染是这样的:
layout=${ID}${date}${Level}${Message}

就这样${ID}可以具有默认值0。好的但理想情况下,我希望每次调用都能够指定一个ID,而无需每次登录都有3行代码

我见过自定义渲染器允许我自定义输出,但我不确定如何自定义传递给它的属性

演示如何添加属性,但我不知道如何调用它们

此外,还显示了如何设置自定义属性,但这涉及到每次要记录某个内容时创建LogEventInfo对象

显示如何自定义输出。。再一次。。。而不是如何定制输入

这是针对C#targeting.NET4.0中使用VS2013的控制台应用程序

谢谢 -Ed

事件属性(过去被称为事件上下文)将是实现所需功能的内置方式。如果您使用的是NLog 3.2+,那么可以使用fluent api,这可能比创建
LogEventInfo
对象更有吸引力。您可以使用名称空间
NLog.Fluent
访问此api

然后,您的布局将被定义为:

${event-properties:item=ID} ${date} ${Level} ${Message}
_logger.Debug()
    .Message("My name is {0}", "Ed")
    .Property("ID", 87)
    .Write();
// Example of a class that needs to use logging
public class MyClass
{
    private LoggerHelper _logger;

    public MyClass(int id)
    {
        _logger = new LoggerHelper(LogManager.GetCurrentClassLogger());

        // Per-instance values
        _logger.Set("ID", id);
    }

    public void DoStuff()
    {
        _logger.Debug("My name is {0}", "Ed");
    }
}


// Example of a "stateful" logger
public class LoggerHelper
{
    private Logger _logger;
    private Dictionary<string, object> _properties;


    public LoggerHelper(Logger logger)
    {
        _logger = logger;
        _properties = new Dictionary<string, object>();
    }

    public void Set(string key, object value)
    {
        _properties.Add(key, value);
    }

    public void Debug(string format, params object[] args)
    {
        _logger.Debug()
            .Message(format, args)
            .Properties(_properties)
            .Write();
    }
}
然后使用fluent api,记录如下:

${event-properties:item=ID} ${date} ${Level} ${Message}
_logger.Debug()
    .Message("My name is {0}", "Ed")
    .Property("ID", 87)
    .Write();
// Example of a class that needs to use logging
public class MyClass
{
    private LoggerHelper _logger;

    public MyClass(int id)
    {
        _logger = new LoggerHelper(LogManager.GetCurrentClassLogger());

        // Per-instance values
        _logger.Set("ID", id);
    }

    public void DoStuff()
    {
        _logger.Debug("My name is {0}", "Ed");
    }
}


// Example of a "stateful" logger
public class LoggerHelper
{
    private Logger _logger;
    private Dictionary<string, object> _properties;


    public LoggerHelper(Logger logger)
    {
        _logger = logger;
        _properties = new Dictionary<string, object>();
    }

    public void Set(string key, object value)
    {
        _properties.Add(key, value);
    }

    public void Debug(string format, params object[] args)
    {
        _logger.Debug()
            .Message(format, args)
            .Properties(_properties)
            .Write();
    }
}
除了如上所述设置每个事件的属性外,唯一的其他选项是使用或设置每个线程的属性

NLog没有(我发现的)设置每个记录器属性的方法。在内部,NLog按记录器名称缓存
Logger
实例,但不保证总是为给定记录器名称返回相同的
Logger
实例。因此,例如,如果您在类的构造函数中调用
LogManager.GetCurrentClassLogger()
大多数时候,您将为类的所有实例返回相同的Logger实例。在这种情况下,您将无法在记录器上为类的每个实例指定单独的值

也许您可以创建一个可以在类中实例化的日志帮助器类。可以使用每个消息记录的每个实例属性值初始化helper类。helper类还将提供方便的方法来记录上述消息,但只需一行代码。大概是这样的:

${event-properties:item=ID} ${date} ${Level} ${Message}
_logger.Debug()
    .Message("My name is {0}", "Ed")
    .Property("ID", 87)
    .Write();
// Example of a class that needs to use logging
public class MyClass
{
    private LoggerHelper _logger;

    public MyClass(int id)
    {
        _logger = new LoggerHelper(LogManager.GetCurrentClassLogger());

        // Per-instance values
        _logger.Set("ID", id);
    }

    public void DoStuff()
    {
        _logger.Debug("My name is {0}", "Ed");
    }
}


// Example of a "stateful" logger
public class LoggerHelper
{
    private Logger _logger;
    private Dictionary<string, object> _properties;


    public LoggerHelper(Logger logger)
    {
        _logger = logger;
        _properties = new Dictionary<string, object>();
    }

    public void Set(string key, object value)
    {
        _properties.Add(key, value);
    }

    public void Debug(string format, params object[] args)
    {
        _logger.Debug()
            .Message(format, args)
            .Properties(_properties)
            .Write();
    }
}
//需要使用日志记录的类的示例
公共类MyClass
{
私人记录器助手(记录器);
公共MyClass(内部id)
{
_logger=新的LoggerHelper(LogManager.GetCurrentClassLogger());
//每实例值
_logger.Set(“ID”,ID);
}
公共空间
{
_Debug(“我的名字是{0}”,“Ed”);
}
}
//“有状态”记录器示例
公共类LoggerHelper
{
私人记录器;
私有字典属性;
公用记录器帮助程序(记录器)
{
_记录器=记录器;
_属性=新字典();
}
公共无效集(字符串键、对象值)
{
_属性。添加(键、值);
}
公共void调试(字符串格式,参数对象[]args)
{
_logger.Debug()
.消息(格式,args)
.Properties(_Properties)
.Write();
}
}

这将与上面的布局相同。

这可能不是实现这一点的最佳方法,甚至不是线程安全的,而是一个快速而肮脏的解决方案:您可以使用环境变量:

Environment.SetEnvironmentVariable("NLogOptionID", "87");
logger.Debug("My Name id Ed");
Environment.SetEnvironmentVariable("NLogOptionID", null);
在布局中,可以使用环境变量

${environment:variable=NLogOptionID}

使用MDLC布局渲染器

MappedDiagnosticsLogicalContext.Set(“PropertyName”、“PropertyValue”); MappedDiagnosticsLogicalContext.Set(“PropertyName2”, “其他财产价值”)

在nlog配置中:

${mdlc:item=PropertyName}${mdlc:item=PropertyName2}


NLog 4.5支持使用消息模板进行结构化日志记录:

logger.Info("Logon by {user} from {ip_address}", "Kenny", "127.0.0.1");

另见

Wow。有趣。我喜欢这个想法,因为我可以设置Env变量一次。现在,我正在使用LogEventInfo(我编辑了上面的问题以添加此内容)。。。但这是非常混乱的。。。我需要线程安全虽然…我不知道为什么它被评为低。老实说,nlog无法记录{aspnet user identity},因为它当前记录为空值,在asp.netcore 2.2 web api中,这就是我能够实现的解决方案。我不知道为什么该布局属性没有呈现HttpContext.User.Identity,但这个技巧对我很有效。@Ak777它看起来可能对你有效。但是,由于这会在进程级别上设置变量,因此在调用
Environment.SetEnvironmentVariable
和实际的
logger.Debug(…)
调用另一个已更新该值的线程之间,可能会发生这样的情况,即您记录了错误的用户。对于一个简单的控制台或windows应用程序,这确实很有帮助,但在web项目中使用时要小心。谢谢!我试试看