【发布时间】:2019-06-18 08:44:01
【问题描述】:
直到今天,我们一直在使用 NLog 版本 4.4.12(没有结构化日志记录)。但是,我们使用 https://www.nuget.org/packages/NLog.StructuredLogging.Json/ 进行结构化日志记录。
使用这个扩展的好处是你不需要模板化的消息(包含索引或占位符,用于记录其他参数/对象)。该消息不包含任何索引或占位符供您记录的其他对象(即匿名类型)。
切换到支持开箱即用结构化日志记录的 NLog 4.6.5,我们希望摆脱额外的 NuGet 包。但是,只有在使用带有实际索引/命名占位符的 模板化 消息时,才会记录我们的附加参数。
我们的消息中没有索引或占位符确实会导致我们的其他参数/对象无法通过 JSON 呈现。
是否可以有非模板化的消息,但仍使用 NLog 的结构化日志记录我们传递给它们以添加到 JSON 中的附加参数?
以下是一个示例(请注意,我们在 nlog 周围使用了额外的包装器)
NLog 版本:4.6.5
平台:.Net 4.5
当前的 NLog 配置
// Arrange
var typeUsingLogger = typeof(NLogWrapperTest);
var nLogWrapper = new NLogWrapper(typeof(NLogWrapper));
var level = (LogLevel)Enum.Parse(typeof(LogLevel), nLevel.Name);
var message = $"{Guid.NewGuid()}"; // {{extendedLogProperties}} {{@extendedLogProperties}} {{@purchase}} {{badplaceholder}}
var innerException = new DivideByZeroException("bla inner exception");
var exception = new ArgumentNullException("bla out exception", innerException);
var extendedLogProperties = new
{
ClientID = 8,
MyOtherProp = "abc",
MySubObject = new
{
//nested object although not recommended
A = 123,
B = "yep"
}
};
//log configuration
var logConfig = new LoggingConfiguration();
var memoryTarget = new MemoryTarget("MemoryTarget");
var jsonLayout = new JsonLayout
{
IncludeAllProperties = true,
Attributes =
{
new JsonAttribute("dateTime", "${date:universalTime=true:format=o}" ),
new JsonAttribute("level", "${level:uppercase=true}" ),
new JsonAttribute("logger", "${logger}" ),
new JsonAttribute("message", "${message}" ),
new JsonAttribute("callsite", "${callsite:className=true:methodName=true:skipFrame=0}" ),
new JsonAttribute("exception", "${exception:format=ToString:innerFormat=ToString}" ),
new JsonAttribute("machinename", "${machinename}" ),
new JsonAttribute("processid", "${processid}" ),
new JsonAttribute("threadid", "${threadid}" ),
new JsonAttribute("threadname", "${threadname}" ),
new JsonAttribute("application", "${application}" ),
new JsonAttribute("aspnetSessionId", "${aspnet-sessionid}" ),
new JsonAttribute("iisSiteName", "${iis-site-name}" ),
new JsonAttribute("stage", "${stage}" ),
}
};
memoryTarget.Layout = jsonLayout;
logConfig.AddTarget("memoryTarget", memoryTarget);
var memoryTargetLoggingRule = new LoggingRule("*", nLevel, memoryTarget);
logConfig.LoggingRules.Add(memoryTargetLoggingRule);
LogManager.Configuration = logConfig;
// Act
nLogWrapper.Log(level, message, typeUsingLogger, exception, extendedLogProperties);
var jsonLogMsg = memoryTarget.Logs[0];
Assert.Matches("ClientID", jsonLogMsg);
我们为什么需要它?
如果不使用任何替换的索引或占位符来保持消息不变,这样我们就可以在日志中搜索完全相同的消息,这真是太好了。 (不能使用
new JsonAttribute("message", "${message:raw=true}")-
同样这样,我们最终不会在日志消息中包含 JSON 序列化对象(替换模板化消息的占位符/索引)以及这些附加参数的附加 JSON 字段。
李>
请查看其最佳实践:https://github.com/justeat/NLog.StructuredLogging.Json/blob/master/README.md#best-practices
如果您问:“为什么不继续使用 NuGet NLog 扩展?” 答案是,在嵌套对象的模板化消息中使用 {@placeholder} 时,NLog 的结构化日志可以更好地呈现附加参数。
编辑 1: 我想让我的匿名对象的所有属性都呈现在 json 的根目录中。如:
{
...
"ClientID": 8,
"MyOtherProp": "abc",
"MySubObject": {
"A": 123,
"B": "yep"
},
...
}
【问题讨论】:
-
我对你的(长)“当前 NLog 配置”有点困惑。不是配置吗?如果您可以显示记录器调用(单行,而不是
nLogWrapper.Log(level, message, typeUsingLogger, exception, extendedLogProperties))和所需的输出,我会很有帮助。
标签: json nlog structured-logging