如何在Serilog中自定义TimeSpan的日志格式化方式?
解决Serilog中TimeSpan类型指标的格式化问题
问题根源
直接使用{Elapsed:ss.fff}报错是因为Serilog默认的消息模板解析逻辑中,格式说明符的语法和.NET原生TimeSpan自定义格式存在冲突,导致解析失败。
解决方案
以下两种方法可以在保留结构化日志原始TimeSpan数据的前提下,优化人类可读的输出格式:
方法一:转义.NET TimeSpan自定义格式字符串
在消息模板中,将TimeSpan自定义格式里的特殊符号(比如冒号、点)进行转义,让Serilog正确识别为.NET原生格式化规则:
// 单次迭代(仅秒和毫秒) Log.Information("单次迭代完成,耗时 {Elapsed:ss\\.fff}", elapsedTime); // 累计时长(分钟+秒+毫秒) Log.Information("累计运行时长 {Total:mm\\:ss\\.fff}", totalTime);
这种方法无需额外代码,适合格式固定的场景。
方法二:自定义TimeSpan格式化器
如果需要根据时长动态调整格式(比如短时长显示秒级,长时长显示分钟级),可以实现一个自定义的ITextFormatter:
public class AdaptiveTimeSpanFormatter : ITextFormatter { public void Format(object value, TextWriter output) { if (value is not TimeSpan ts) { output.Write(value.ToString()); return; } // 根据时长选择对应格式 if (ts.TotalMinutes < 1) { // 小于1分钟,显示秒+毫秒 output.Write(ts.ToString("ss\\.fff")); } else { // 1分钟以上,显示分钟+秒+毫秒 output.Write(ts.ToString("mm\\:ss\\.fff")); } } }
然后在Serilog配置中注册这个格式化器:
Log.Logger = new LoggerConfiguration() .WriteTo.Console( outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}", formatProviders: new[] { new AdaptiveTimeSpanFormatter() }) // 其他配置(如文件输出等) .CreateLogger();
之后在日志调用中直接使用{Elapsed}和{Total}即可,格式化器会自动处理显示逻辑:
Log.Information("单次迭代完成,耗时 {Elapsed}", elapsedTime); Log.Information("累计运行时长 {Total}", totalTime);
核心优势
两种方法都能保证结构化日志中保留原始的TimeSpan类型数据(支持后续的数据分析、统计),仅在人类可读的日志输出中使用简化格式,完全符合结构化日志的设计理念。
内容的提问来源于stack exchange,提问作者Mel
相关产品推荐
相关产品推荐

