【问题标题】:How to use Serilog enrichers with log context如何使用带有日志上下文的 Serilog 丰富器
【发布时间】:2021-06-10 23:49:36
【问题描述】:

是否希望 Serilog 丰富器(尤其是 LogEvent)知道推送到 LogContext 上的属性?

我有一个属性被推送到 Serilog 上下文中:

using (LogContext.PushProperty(LoggingConstants.MyProperty, _myValue))
{
   // ...
}

我还注册了一个自定义浓缩器,如果它不存在,它会添加一个属性,并将其填充到指定的长度:

public class PaddedPropertyEnricher : ILogEventEnricher
{
    private readonly string _propertyName;
    private readonly int _maxLength;

    public PaddedPropertyEnricher(string propertyName, int maxLength)
    {
      _propertyName = propertyName;
      _maxLength = maxLength;
    }

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
      var property = propertyFactory.CreateProperty(_propertyName, new string(' ', _maxLength));
      logEvent.AddPropertyIfAbsent(property);
    }
}

和:

Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .Enrich.With(new PaddedPropertyEnricher(LoggingConstants.MyProperty, 3))
                 // etc.

此扩充器的目的是使不包含自定义属性的日志条目不会导致日志条目中的列不对齐。

例如,它打算转换这个:

2021-06-10 12:23:33.676 +12:00 [INF] [] First message without MyProperty
2021-06-10 12:23:33.677 +12:00 [DBG] [123] Second message with MyProperty

进入这个:

2021-06-10 12:23:33.676 +12:00 [INF] [   ] First message without MyProperty
2021-06-10 12:23:33.677 +12:00 [DBG] [123] Second message with MyProperty

但是,这个浓缩器不起作用。当针对我推送到上下文的属性注册丰富器时,从LogEvent 检索到的值始终为null - 除非MyProperty 明确显示在日志消息本身中。

这是一个已知的限制,还是我滥用了浓缩器?

这可能与Always log context data using serilog遇到的问题有关。

【问题讨论】:

  • Log.Logger = ...直到最后一个serilog链init CreateLogger的完整代码是什么?
  • 感谢您提示我查看此内容 - 我忘记了使用 LogContext 本身需要丰富器!

标签: c# serilog


【解决方案1】:

我是否在滥用浓缩器?

我相信你就是这种情况。

TL;DR; 丰富器在所有接收器之间共享,因此如果您只想针对一个特定接收器的输出格式,它们不是最佳选择。控制 sink 的输出,应该使用 sink 提供的机制,可以是输出模板,也可以是自定义的IFormatProvider


您似乎正在创建一个带有空格的属性,只是为了影响 特定 接收器的格式化输出。这不是格式化接收器输出的“Serilog 方式”。

当您通过 Enricher 创建属性时,它们可供所有接收器使用,并且每个接收器都有责任根据它们写入的位置来决定如何最好地序列化属性。

通过使用填充创建属性,您假设所有接收器都希望该属性的格式与此完全相同,但将来可能不会出现这种情况。

如果您只想在控制台接收器或任何其他使用标准 Serilog 输出模板的接收器中添加一些填充,那么您可以使用填充语法:

.WriteTo.Console(outputTemplate: "{Message}[{MyProperty,3}]")

这将确保在渲染属性时填充 3 空格(如果属性不存在,则填充 3 个空格)。

如果您需要对接收器的输出进行更多控制,则可以提供自定义 IFormatProvider


您可以在Formatting-Output 上的文档中查看更多详细信息。

【讨论】:

  • 谢谢;这很有意义。不幸的是,当属性不存在时,似乎没有应用 C# 格式说明符,这就是我首先走这条路的原因。
【解决方案2】:

问题是由于我的自定义浓缩器在Enrich.FromLogContext() 之前注册的;例如:

// Bad configuration
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .Enrich.With(new PaddedPropertyEnricher(LoggingConstants.MyProperty, 3))
    .WriteTo.Console(minimumLogLevels.Console, LogFormat)

     // Other sink configuration here

    .Enrich.FromLogContext()
    .CreateLogger();

通过确保Enrich.FromLogContext() 出现在任何依赖它的浓缩器之前,问题已得到解决;即:

// Good configuration
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Console(minimumLogLevels.Console, LogFormat)

     // Other sink configuration here

    .Enrich.FromLogContext()
    .Enrich.With(new PaddedPropertyEnricher(LoggingConstants.MyProperty, 3))
    .CreateLogger();

感谢Olivier Roger 提示我查看完整的Log.Logger 链。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多