在结构化日志记录系统(如 MEL 和 Serilog)中记录长消息的惯用方法是什么?



当我想存储一个简短的(<200个字符)参数化字符串时,我的 ASP.NET Core 2.x Web应用程序习惯性地使用Microsoft.Extensions.Logging来执行"跟踪"式日志记录。这些类型的记录事件可以很好地与围绕结构化日志记录系统(如Serilog)构建的工具和生态系统配合使用。

例如

public IActionResult DisplayCustomers(String customerName, String country)
{
this.logger.LogInformation( "Search performed for customers named {name} in {country}.", customerName, country );
}

但是,我的应用程序还需要记录应用程序使用StringBuilder构建的有点大的文本 blob (2-3KB) 以及第三方组件生成的类似文本 blob,通常这些会消耗输出大量短字符串值的IProgress<String>,其方式类似于临时使用Console.WriteLine

例如

// Backend method (no structured logging available):
public void ProcessData(LotsOfData data, IProgress<String> report)
{
Stopwatch sw = Stopwatch.StartNew();
for( Int32 i = 0; i < data.Records.Count; i++ )
{
if( i % 500 == 0 ) report.Report( String.Format( "{0}ms - Processed {1} records.", sw.ElapsedMilliseconds, i ) );
if( data.Records[i].Foo )
{
// (send job off to SQL Server and get back SPROC output via PRINT and RAISERROR)
String sprocRaiseErrorOutput = ...
report.Report( "Sproc output: " +  sprocRaiseErrorOutput );
}
if( data.Records[i].Bar ) report.Report( "Contents of bar: " +  data.Records[i].Bar.Text );
}
report.Report( "{0}ms - Completed.", sw.ElapsedMilliseconds );
}
class StringBuilderProgress : IProgress<String>
{
private StringBuilder sb;
public StringBuilderProgress(StringBuilder sb) { this.sb = sb; }
public void Report(String value) { this.sb.AppendLine( value ); }
}
// Frontend method:
public IActionResult ProcessData(LotsOfData data)
{
StringBuilder sb = new StringBuilder();
StringBuilderProgress sbp = new StringBuilderProgress( sb );
backendService.ProcessData( data, sbp );
this.logger.LogInformation( "Process data ran: {report}", sb.ToString() );
}

。这会导致一个大型的非结构化文本 blob,其中包含有用的信息,需要单独查看,但不适合现有的结构化日志记录工具。

我认识到一个通用的解决方案是为实现IProgress<String>ILogger编写一个包装器 - 但这种方法存在一些问题:

  • 原始 text-blob 中的每个输出行都成为一个结构化对象,并带有自己的附加属性,这些属性会显著增加日志的大小。
  • 这将导致重复数据,例如,结构化日志记录系统会添加时间戳,但文本也已经包含秒表时间值。
  • 通常,文本 blob 包含用于框的 ACII-art 之类的内容并指示处理区域,并且每行都缩进以表示更深层次的处理 - 如果每行单独存储且独立于其文本上下文,则此信息将丢失。
    • 仅包含 ASCII 艺术矩形框的第一行的日志条目有什么用?

在 Serilog 或 MEL 中是否有办法专门处理文本 blob?比如将它们输出到自己的文件中?

您可以非常轻松地实现一个接收器来解析您认为合适的输出(抱歉,在 C# 中没有这个输出)并适当地呈现,无论是您自己的形状的文件还是日志。或者,您可以将内容作为属性隔离到日志条目中,然后使用那里提供的过滤机制在接收器和/或日志链中处理它们(更深的示例)。

  • 在自定义接收器中,可以访问一个Serilog.Events.LogEvent,该以几乎不可变的形式保存结构,但允许添加/删除属性的可能性。

    因此,您应该能够提取嵌入的属性并将它们写入单独的日志(并在允许它继续之前从 LogEvent 中删除它们)。如果在Async接收器链中执行此操作,也不会影响编写器的性能。

  • 另一种选择是使用各种可能的演绎版渲染为 JSON,然后在带外对自己进行后期处理

  • 最后,如果你标记的东西很好和/或有相关的识别标记来关联项目,像 Seq 这样的东西是为了有效地解析这样的东西而构建的(虽然我不知道在那里将某些东西渲染为固定宽度格式的方法)(东西也会在商店等中被压缩,并且始终保留完整的事件)

最新更新