C# - Serilog - Enrichers 留下空白条目
C# - Serilog - Enrichers leaving blank entries
了解了 Serilog 的基础知识。现在尝试添加一些增强器,以便我可以在每个日志行中打印用户名或机器名或 class 名称等。
这是我目前的代码,
using System;
using Serilog;
using Serilog.Sinks.SystemConsole;
using Serilog.Sinks.File;
using Serilog.Enrichers;
using Serilog.Core;
using Serilog.Events;
using System.Threading;
using Serilog.Context;
var outputTemplate = "{MachineName} | {UserName} | {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u4}] | {ClassName} | {Message:l}{NewLine}{Exception}";
var Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.File("logFile-.log",
outputTemplate: outputTemplate)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserName()
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
Logger.Information("Hello, Serilog!");
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 35;
for (int i = 0; i < 5; i++)
{
Logger.Information("Processed {@position} in {elapsed} ms.", position, elapsedMs);
Logger.Information("");
}
using (LogContext.PushProperty("SourceContext", "TestClass"))
{
for (int i = 0; i < 5; i++)
{
Logger.Information("Processed {@position} in {elapsed} ms.", position, elapsedMs);
Logger.Information("");
}
}
输出
| | 2018-03-03 19:02:56.247 -05:00 [INFO] | | Hello, Serilog!
| | 2018-03-03 19:02:56.287 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.295 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.295 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.296 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.297 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.298 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.298 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.299 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.300 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.301 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.302 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.307 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.308 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.310 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.310 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.311 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.312 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.313 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.316 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.317 -05:00 [INFO] | TestClass |
Press any key to continue . . .
根据我的理解,我必须在创建 [=] 时在 outputTemplate
中手动定义 "placeholders"(MachineName
或 UserName
或 ClassName
) 16=] 对象。如果我不需要使用它们,我不确定如何使这些占位符可选(即不在日志行中打印空白 space)。 (例如,我不想打印几行 class 名称)。或者我可能没有正确理解 Enrichers 的概念。
非常感谢任何帮助!!
如果我没理解错的话,你有 2 个问题:
- 为什么机器名和用户名没有出现在日志中?
- 如何使 enricher 占位符可选?
- Why Machine name and User name do not appear in logs?
机器名称未出现在日志中,因为您没有添加适当的增强器 - WithMachineName()
。
将以下调用添加到配置中:
var Logger = new LoggerConfiguration()
// ...
.Enrich.WithMachineName()
// ...
用户名没有出现在日志中,因为您使用了不正确的占位符 {UserName}
而它应该是 {EnvironmentUserName}
.
这是解决这两个问题的记录器配置:
var outputTemplate = "{MachineName} | {EnvironmentUserName} | {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u4}] | {ClassNameDelimited} | {Message:l}{NewLine}{Exception}";
var Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.File("logFile-.log",
outputTemplate: outputTemplate)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserName()
.Enrich.WithMachineName()
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
- How to make enricher placeholder optional?
{MachineName}
等占位符仅替换为 属性 值。如果缺少值,它将替换为空字符串。所以实际上占位符是可选的。
但是对于像 "{MachineName} | Something"
这样的输出模板,这将导致 " | Something"
日志条目。当您定义这样的输出模板时,不会从结果条目中删除常量字符串 " | "
。
这个问题有一个解决方案,但是需要一些努力。计划如下:
- 将分隔符作为替换的 属性 值的一部分。
- 编写检查基础值是否存在的自定义增强器。如果是,enricher 将使用与分隔符连接的原始值来丰富日志条目。如果值不存在,enricher 不会添加任何东西,这样可以防止日志中出现没有值的分隔符。
以下是此类浓缩剂的样本:
public class DelimitedEnricher : ILogEventEnricher
{
private readonly ILogEventEnricher innerEnricher;
private readonly string innerPropertyName;
private readonly string delimiter;
public DelimitedEnricher(string innerPropertyName, string delimiter)
{
this.innerPropertyName = innerPropertyName;
this.delimiter = delimiter;
}
public DelimitedEnricher(ILogEventEnricher innerEnricher, string innerPropertyName, string delimiter) : this(innerPropertyName, delimiter)
{
this.innerEnricher = innerEnricher;
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
innerEnricher?.Enrich(logEvent, propertyFactory);
LogEventPropertyValue eventPropertyValue;
if (logEvent.Properties.TryGetValue(innerPropertyName, out eventPropertyValue))
{
var value = (eventPropertyValue as ScalarValue)?.Value as string;
if (!String.IsNullOrEmpty(value))
{
logEvent.AddPropertyIfAbsent(new LogEventProperty(innerPropertyName + "Delimited", new ScalarValue(value + delimiter)));
}
}
}
}
以下是配置 enricher 的扩展方法:
public static class DelimitedEnrichersExtensions
{
public const string Delimiter = " | ";
public static LoggerConfiguration WithEnvironmentUserNameDelimited(this LoggerEnrichmentConfiguration enrichmentConfiguration)
{
return enrichmentConfiguration.With(new DelimitedEnricher(new EnvironmentUserNameEnricher(), EnvironmentUserNameEnricher.EnvironmentUserNamePropertyName, Delimiter));
}
public static LoggerConfiguration WithMachineNameDelimited(this LoggerEnrichmentConfiguration enrichmentConfiguration)
{
return enrichmentConfiguration.With(new DelimitedEnricher(new MachineNameEnricher(), MachineNameEnricher.MachineNamePropertyName, Delimiter));
}
public static LoggerConfiguration WithPropertyDelimited(this LoggerEnrichmentConfiguration enrichmentConfiguration, string propertyName)
{
return enrichmentConfiguration.With(new DelimitedEnricher(propertyName, Delimiter));
}
}
最后是使用此自定义增强器的配置:
var outputTemplate = "{MachineNameDelimited}{EnvironmentUserNameDelimited}{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u4}] | {ClassNameDelimited}{Message:l}{NewLine}{Exception}";
var Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.File("logFile-.log",
outputTemplate: outputTemplate)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserNameDelimited()
.Enrich.WithMachineNameDelimited()
.Enrich.WithPropertyDelimited("ClassName")
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
了解了 Serilog 的基础知识。现在尝试添加一些增强器,以便我可以在每个日志行中打印用户名或机器名或 class 名称等。
这是我目前的代码,
using System;
using Serilog;
using Serilog.Sinks.SystemConsole;
using Serilog.Sinks.File;
using Serilog.Enrichers;
using Serilog.Core;
using Serilog.Events;
using System.Threading;
using Serilog.Context;
var outputTemplate = "{MachineName} | {UserName} | {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u4}] | {ClassName} | {Message:l}{NewLine}{Exception}";
var Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.File("logFile-.log",
outputTemplate: outputTemplate)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserName()
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
Logger.Information("Hello, Serilog!");
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 35;
for (int i = 0; i < 5; i++)
{
Logger.Information("Processed {@position} in {elapsed} ms.", position, elapsedMs);
Logger.Information("");
}
using (LogContext.PushProperty("SourceContext", "TestClass"))
{
for (int i = 0; i < 5; i++)
{
Logger.Information("Processed {@position} in {elapsed} ms.", position, elapsedMs);
Logger.Information("");
}
}
输出
| | 2018-03-03 19:02:56.247 -05:00 [INFO] | | Hello, Serilog!
| | 2018-03-03 19:02:56.287 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.295 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.295 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.296 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.297 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.298 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.298 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.299 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.300 -05:00 [INFO] | | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.301 -05:00 [INFO] | |
| | 2018-03-03 19:02:56.302 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.307 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.308 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.310 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.310 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.311 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.312 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.313 -05:00 [INFO] | TestClass |
| | 2018-03-03 19:02:56.316 -05:00 [INFO] | TestClass | Processed {Latitude=25, Longitude=134} in 35 ms.
| | 2018-03-03 19:02:56.317 -05:00 [INFO] | TestClass |
Press any key to continue . . .
根据我的理解,我必须在创建 [=] 时在 outputTemplate
中手动定义 "placeholders"(MachineName
或 UserName
或 ClassName
) 16=] 对象。如果我不需要使用它们,我不确定如何使这些占位符可选(即不在日志行中打印空白 space)。 (例如,我不想打印几行 class 名称)。或者我可能没有正确理解 Enrichers 的概念。
非常感谢任何帮助!!
如果我没理解错的话,你有 2 个问题:
- 为什么机器名和用户名没有出现在日志中?
- 如何使 enricher 占位符可选?
- Why Machine name and User name do not appear in logs?
机器名称未出现在日志中,因为您没有添加适当的增强器 - WithMachineName()
。
将以下调用添加到配置中:
var Logger = new LoggerConfiguration()
// ...
.Enrich.WithMachineName()
// ...
用户名没有出现在日志中,因为您使用了不正确的占位符 {UserName}
而它应该是 {EnvironmentUserName}
.
这是解决这两个问题的记录器配置:
var outputTemplate = "{MachineName} | {EnvironmentUserName} | {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u4}] | {ClassNameDelimited} | {Message:l}{NewLine}{Exception}";
var Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.File("logFile-.log",
outputTemplate: outputTemplate)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserName()
.Enrich.WithMachineName()
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();
- How to make enricher placeholder optional?
{MachineName}
等占位符仅替换为 属性 值。如果缺少值,它将替换为空字符串。所以实际上占位符是可选的。
但是对于像 "{MachineName} | Something"
这样的输出模板,这将导致 " | Something"
日志条目。当您定义这样的输出模板时,不会从结果条目中删除常量字符串 " | "
。
这个问题有一个解决方案,但是需要一些努力。计划如下:
- 将分隔符作为替换的 属性 值的一部分。
- 编写检查基础值是否存在的自定义增强器。如果是,enricher 将使用与分隔符连接的原始值来丰富日志条目。如果值不存在,enricher 不会添加任何东西,这样可以防止日志中出现没有值的分隔符。
以下是此类浓缩剂的样本:
public class DelimitedEnricher : ILogEventEnricher
{
private readonly ILogEventEnricher innerEnricher;
private readonly string innerPropertyName;
private readonly string delimiter;
public DelimitedEnricher(string innerPropertyName, string delimiter)
{
this.innerPropertyName = innerPropertyName;
this.delimiter = delimiter;
}
public DelimitedEnricher(ILogEventEnricher innerEnricher, string innerPropertyName, string delimiter) : this(innerPropertyName, delimiter)
{
this.innerEnricher = innerEnricher;
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
innerEnricher?.Enrich(logEvent, propertyFactory);
LogEventPropertyValue eventPropertyValue;
if (logEvent.Properties.TryGetValue(innerPropertyName, out eventPropertyValue))
{
var value = (eventPropertyValue as ScalarValue)?.Value as string;
if (!String.IsNullOrEmpty(value))
{
logEvent.AddPropertyIfAbsent(new LogEventProperty(innerPropertyName + "Delimited", new ScalarValue(value + delimiter)));
}
}
}
}
以下是配置 enricher 的扩展方法:
public static class DelimitedEnrichersExtensions
{
public const string Delimiter = " | ";
public static LoggerConfiguration WithEnvironmentUserNameDelimited(this LoggerEnrichmentConfiguration enrichmentConfiguration)
{
return enrichmentConfiguration.With(new DelimitedEnricher(new EnvironmentUserNameEnricher(), EnvironmentUserNameEnricher.EnvironmentUserNamePropertyName, Delimiter));
}
public static LoggerConfiguration WithMachineNameDelimited(this LoggerEnrichmentConfiguration enrichmentConfiguration)
{
return enrichmentConfiguration.With(new DelimitedEnricher(new MachineNameEnricher(), MachineNameEnricher.MachineNamePropertyName, Delimiter));
}
public static LoggerConfiguration WithPropertyDelimited(this LoggerEnrichmentConfiguration enrichmentConfiguration, string propertyName)
{
return enrichmentConfiguration.With(new DelimitedEnricher(propertyName, Delimiter));
}
}
最后是使用此自定义增强器的配置:
var outputTemplate = "{MachineNameDelimited}{EnvironmentUserNameDelimited}{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u4}] | {ClassNameDelimited}{Message:l}{NewLine}{Exception}";
var Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: outputTemplate)
.WriteTo.File("logFile-.log",
outputTemplate: outputTemplate)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentUserNameDelimited()
.Enrich.WithMachineNameDelimited()
.Enrich.WithPropertyDelimited("ClassName")
.Enrich.WithProperty("Version", "1.0.0")
.CreateLogger();