c# - 有没有办法使用 Serilog 提供自定义属性格式?

标签 c# logging tostring serilog destructuring

我有一个 BackgroundTask 类,我已将其设置为在事情发生时记录事件,例如任务完成时。例如,对于 Success 情况,我调用 Log.Verbose("{Task} completed successfully", this); 我的默认 ToString() 包括进度,但对于已完成的任务,我们知道它是 100%,所以我想忽略它。我知道对于数字类型,您可以传入自定义格式说明符字符串(如 "{IntProperty:p5}",这会将我的 int 呈现为小数点后 5 位的百分比),我想能够做同样的事情,例如 Log.Information("{Task:Name}", this),它会将 "Name" 传递到我的 ToString() 方法。

我已经尝试添加许多不同的方法,例如添加 ToString()(不接受任何内容、一个字符串、一个字符串和 IFormatProvider),实现 IFormattable,强制字符串化等,似乎没有任何效果。我可以看到 Serilog 正在正确解析我的格式字符串:(PropertyBinder.csConstructNamedProperties() 第 111 行) Debug view of serilog code

这会调用 ConstructProperty(),它只是忽略了 token 的 Format 属性,这解释了为什么它被忽略,但我想知道是否有一种方法可以我没有想到的工作。

附言 是的,我知道我有几个可以做的选择,但我不想做这些:

  1. 使用自定义解构器或自己手动将属性提取为匿名类型 - 这实质上会破坏原始对象,这正是我不想要的(我仍然希望将原始值存储为属性)。例如。 Log.Information("{Task}", new {Name = this.Name, Id = this.Id});
  2. 使用我自己的格式字符串手动调用 ToString() - 与 (1) 相同,这会破坏原始字符串,并且意味着它不会与所有信息一起存储。例如。 Log.Information("{Task}", this.ToString("自定义格式"));
  3. 在将对象传递到 Serilog 之前,在我的对象上创建一个属性,如 ToStringFormat - 这似乎是不好的做法,只会增加额外的困惑,更不用说并发问题了。例如。 this.Format = "自定义格式"; Log.Information("{Task}", this);

最佳答案

这是由于 Serilog 管道中捕获格式化 之间的分离。

为了在渲染到接收器时处理像 :X 这样的格式字符串,需要提供实现 IFormattable 的原始对象。

但是,由于接收器通常异步处理事件,Serilog 无法确定任何给定的记录对象都是线程安全的,因此在使用 ToString()< 进行记录的时间/地点捕获任何未知类型.

为了解决这个问题,您需要告诉 Serilog 您的 Point 类是一个(本质上不可变的)值类型:

    .Destructure.AsScalar(typeof(Point))

配置记录器时。然后,您可以在 Point 上实现 IFormattable 并在模板中使用 {Point:X} 等。

关于c# - 有没有办法使用 Serilog 提供自定义属性格式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69654180/

相关文章:

c# - 将字符串分配给 HtmlElement 对象的 InnerHtml

python WatchedFileHandler 旋转后仍在写入旧文件

针对不同模块的 Java 粒度调试消息

javascript - 为什么 String(null) 有效?

c# - 如何在 .NET 4.0 之前将 TimeSpan 格式化为字符串

c# - 无法将 list<T> 传输到 Web 服务?

c# - 关闭 C# Windows 窗体时出现问题

java - 您可以在插件中更改标准 JMeter XML 输出吗?

c# - 添加到字符串字段

c# - 使用 FileSystemWatcher 时 c# GUI 中的内存不足异常 - 多线程