使用 NLog Layout Renders 将数值记录为数字
Logging numeric values as numbers using NLog Layout Renders
我们可以使用 NLog Layout Renders 在我们的日志中添加自定义字段。这是我的配置文件:
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
</configSections>
<nlog>
<targets async="true">
<target
name="clp"
type="Console">
<layout type="JsonLayout">
<attribute name="duration" layout="${aspnet-item:variable=RequestDuration}" />
</layout>
</target>
</targets>
<rules>
<logger name="*" writeTo="clp" minlevel="Trace" />
</rules>
</nlog>
</configuration>
aspnet-item:variable=RequestDuration
的值是在我的日志中间件中计算出来的:
public class RequestLoggingMiddleware
{
public async Task Invoke(HttpContext context)
{
var startTime = this.clock.UtcNow;
await this.next.Invoke(context);
var endTime = this.clock.UtcNow;
var requestDuration = (long)(endTime - startTime).TotalMilliseconds;
context.Items["RequestDuration"] = requestDuration;
}
}
在我的 Startup
中注册的喜欢:
app.UseMiddleware<RequestLoggingMiddleware>();
这是我配置 NLog 的方式:
public static IWebHostBuilder CreateHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args).UseStructureMap().UseStartup<Startup>().ConfigureAppConfiguration(AppConfig)
.ConfigureLogging(
(context, logging) =>
{
LogManager.LoadConfiguration($"nlog.{context.HostingEnvironment.EnvironmentName}.config");
logging.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
}).UseNLog();
}
如果我记录如下内容:
Logger.Info("this is just a test");
它将在控制台输出中显示如下:
{ "duration": "123"}
即虽然 aspnet-item:variable=RequestDuration
的值很长,但持续时间将呈现为字符串。但是,我希望它被记录为一个数字。 (我们使用 ELK 堆栈,并且能够将自定义值记录为数字将允许我们添加过滤器,例如,在 Kibana 中此类字段的值范围)
应用程序和包版本
- .NET 核心 3.1
- NLog 4.7.4
- NLog.Extensions.Logging1.6.5
- NLog.Web.AspNetCore 4.9.3
对于普通文件日志,没有类型,因此 My custom string
和 42
将被打印为那些值:My custom string
和 42
(不要不要对文档中的引号感到困惑)
一些布局支持类型,例如 JSON 布局。
例如:
<nlog>
<targets>
<target name='jsonFile' type='File' fileName='log.json'>
<layout type='JsonLayout'>
<attribute name='time' layout='${longdate}' />
<attribute name='level' layout='${level:upperCase=true}'/>
<attribute name='answer' layout='${event-properties:item=TheAnswer}'/>
</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="jsonFile" />
</rules>
</nlog>
会导致这个 JSON:
{ "time": "2021-02-11 01:04:55.0000", "level": "INFO", "answer": 42 }
旁注,记录器调用
logger调用现在推荐这样写:
Logger logger = LogManager.GetCurrentClassLogger(); // static field recommend
logger.Info("The real answer is {TheAnswer}", 42);
或者如果您不需要消息中的 42 (${message}
) - NLog 4.6.3+
logger.WithProperty("TheAnswer", 42).Info("Hello There");
JsonLayout属性有个小技巧,一次可以指定encode="false"
。通常在Attribute-Layout使用JsonLayout时使用。
<layout type="JsonLayout">
<attribute name="duration" layout="${aspnet-item:variable=RequestDuration}" encode="false" />
</layout>
如果项目 RequestDuration
保证为整数或空,则它将生成不带引号的 json-属性。它将被解析为整数,而不是字符串。
NLog 5.0 将对此进行改进,因为属性将获得 ValueType
-属性,因此可以指定字符串类型以外的其他类型(并且还可以验证值类型)。而不是使用 encode="False"
.
的技巧
我们可以使用 NLog Layout Renders 在我们的日志中添加自定义字段。这是我的配置文件:
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
</configSections>
<nlog>
<targets async="true">
<target
name="clp"
type="Console">
<layout type="JsonLayout">
<attribute name="duration" layout="${aspnet-item:variable=RequestDuration}" />
</layout>
</target>
</targets>
<rules>
<logger name="*" writeTo="clp" minlevel="Trace" />
</rules>
</nlog>
</configuration>
aspnet-item:variable=RequestDuration
的值是在我的日志中间件中计算出来的:
public class RequestLoggingMiddleware
{
public async Task Invoke(HttpContext context)
{
var startTime = this.clock.UtcNow;
await this.next.Invoke(context);
var endTime = this.clock.UtcNow;
var requestDuration = (long)(endTime - startTime).TotalMilliseconds;
context.Items["RequestDuration"] = requestDuration;
}
}
在我的 Startup
中注册的喜欢:
app.UseMiddleware<RequestLoggingMiddleware>();
这是我配置 NLog 的方式:
public static IWebHostBuilder CreateHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args).UseStructureMap().UseStartup<Startup>().ConfigureAppConfiguration(AppConfig)
.ConfigureLogging(
(context, logging) =>
{
LogManager.LoadConfiguration($"nlog.{context.HostingEnvironment.EnvironmentName}.config");
logging.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
}).UseNLog();
}
如果我记录如下内容:
Logger.Info("this is just a test");
它将在控制台输出中显示如下:
{ "duration": "123"}
即虽然 aspnet-item:variable=RequestDuration
的值很长,但持续时间将呈现为字符串。但是,我希望它被记录为一个数字。 (我们使用 ELK 堆栈,并且能够将自定义值记录为数字将允许我们添加过滤器,例如,在 Kibana 中此类字段的值范围)
应用程序和包版本
- .NET 核心 3.1
- NLog 4.7.4
- NLog.Extensions.Logging1.6.5
- NLog.Web.AspNetCore 4.9.3
对于普通文件日志,没有类型,因此 My custom string
和 42
将被打印为那些值:My custom string
和 42
(不要不要对文档中的引号感到困惑)
一些布局支持类型,例如 JSON 布局。
例如:
<nlog>
<targets>
<target name='jsonFile' type='File' fileName='log.json'>
<layout type='JsonLayout'>
<attribute name='time' layout='${longdate}' />
<attribute name='level' layout='${level:upperCase=true}'/>
<attribute name='answer' layout='${event-properties:item=TheAnswer}'/>
</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="jsonFile" />
</rules>
</nlog>
会导致这个 JSON:
{ "time": "2021-02-11 01:04:55.0000", "level": "INFO", "answer": 42 }
旁注,记录器调用
logger调用现在推荐这样写:
Logger logger = LogManager.GetCurrentClassLogger(); // static field recommend
logger.Info("The real answer is {TheAnswer}", 42);
或者如果您不需要消息中的 42 (${message}
) - NLog 4.6.3+
logger.WithProperty("TheAnswer", 42).Info("Hello There");
JsonLayout属性有个小技巧,一次可以指定encode="false"
。通常在Attribute-Layout使用JsonLayout时使用。
<layout type="JsonLayout">
<attribute name="duration" layout="${aspnet-item:variable=RequestDuration}" encode="false" />
</layout>
如果项目 RequestDuration
保证为整数或空,则它将生成不带引号的 json-属性。它将被解析为整数,而不是字符串。
NLog 5.0 将对此进行改进,因为属性将获得 ValueType
-属性,因此可以指定字符串类型以外的其他类型(并且还可以验证值类型)。而不是使用 encode="False"
.