[英]How to conditionally render an attribute with NLog and structured logging?
I have inherited an ASP.NET application which is using NLog for logging.我继承了使用 NLog 进行日志记录的 ASP.NET 应用程序。 One of the logged attributes is named module which is hardcoded to "Core".
记录的属性之一是命名模块,它被硬编码为“核心”。 This is not useful at all, because all parts of the application (eg health check, various business contexts) push the same value.
这根本没有用,因为应用程序的所有部分(例如健康检查、各种业务上下文)都推送相同的值。
I am trying to use structured logging to override this value in some cases (I cannot afford to refactor the entire logging now).在某些情况下,我尝试使用结构化日志记录来覆盖此值(我现在无法重构整个日志记录)。
public static void LogInfoWithModule<T>(this ILogger<T> logger, string message, string module)
{
var escapedMessage = message.Replace("{", "{{");
escapedMessage = escapedMessage.Replace("}", "}}");
logger.Log(LogLevel.Information, "[{module}] " + escapedMessage, module);
}
logger.LogInfoWithModule($"Health check response = {response}", Constants.LoggingModules.Health);
<target name="logJson" xsi:type="File">
<layout xsi:type="JsonLayout" includeAllProperties="true">
<attribute name="module" layout="${when:when='${event-properties:item=module}'=='':Core" />
</layout>
</target>
I get want want, that is all existing calls will not provide the module and they will work as before.我得到想要的,那就是所有现有的调用都不会提供模块,它们会像以前一样工作。 Any logging passing through
LogInfoWithModule
will override the default value.通过
LogInfoWithModule
传递的任何日志记录都将覆盖默认值。
However, I find this solution very messy because:但是,我发现这个解决方案非常混乱,因为:
I have tried the solution suggested here (and here ), but ${mdlc:item=module}
does not contain anything.我已经尝试过这里(和这里)建议的解决方案,但
${mdlc:item=module}
不包含任何内容。
The easy way, but will have a performance hit (Notice ${mdlc:item=module}
is case-sensitive)简单的方法,但会影响性能(注意
${mdlc:item=module}
区分大小写)
public static void LogInfoWithModule<T>(this ILogger<T> logger, string message, string module)
{
using (logger.BeginScope(new [] { new KeyValuePair<string,object>("module", module) }))
{
logger.Log(LogLevel.Information, message);
}
}
The advanced way for injecting properties (Notice ${event-properties:module}
is case-sensitive): 注入属性的高级方法(注意
${event-properties:module}
区分大小写):
public static void LogInfoWithModule<T>(this ILogger<T> logger, string message, string module)
{
logger.Log(LogLevel.Information, default(EventId), new ModuleLogEvent(message, module), default(Exception), ModuleLogEvent.Formatter);
}
class ModuleLogEvent : IReadOnlyList<KeyValuePair<string, object>>
{
public static Func<ModuleLogEvent, Exception, string> Formatter { get; } = (l, ex) => l.Message;
public string Message { get; }
public string Module { get; }
public MyLogEvent(string message, string module)
{
Message = message;
Module = module;
}
public override string ToString() => Message;
// IReadOnlyList-interface
public int Count => 1;
public KeyValuePair<string, object> this[int index] => new KeyValuePair<string,object>("module", Module);
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => yield return new KeyValuePair<string,object>("module", Module);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Beware typos and compile-errors might be included in the above example code.请注意上述示例代码中可能包含拼写错误和编译错误。
Alternative you might find happiness here: https://github.com/viktor-nikolaev/XeonApps.Extensions.Logging.WithProperty :或者你可能会在这里找到快乐: https://github.com/viktor-nikolaev/XeonApps.Extensions.Logging.WithProperty :
public static class LoggingExtensions
{
public static NLog.Logger WithModule(this NLog.Logger logger, object propertyValue) =>
logger.WithProperty("module", propertyValue);
public static ILogger WithModule(this ILogger logger, object propertyValue) =>
logger.WithProperty("module", propertyValue);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.