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

时间:2019-02-02 00:02:44

标签: logging serilog structured-logging

当我要存储简短(<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 );
}

但是,我的应用程序还需要记录一些较大的文本blob(2-3KB),这些文本blob由应用程序使用StringBuilder建立,以及第三方生成的类似文本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,其中包含有用的信息,需要单独查看,但不能很好地应用于现有的结构化日志记录工具。

我知道一般的解决方案是为实现ILogger的{​​{1}}写一个包装器-但是这种方法存在一些问题:

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

Serilog或MEL中是否有一种专门处理文本斑点的方法?例如将它们输出到自己的文件中?

1 个答案:

答案 0 :(得分:0)

您可以很容易地实现一个接收器,以按您认为合适的方式解析输出(sorry, don't have this in C#)并适当地渲染,既可以保存为自己的形状的文件,也可以保存为日志。或者,您可以将东西作为属性隔离到日志条目中,然后通常使用那里提供的过滤机制在接收器和/或日志链中进行处理(deeper example

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

    因此,你应该能够提取嵌入的属性和它们向前写入单独的日志(并允许其继续进行之前,从删除的LogEvent它们)。如果这样做的Async水槽链内,它也不会影响PERF的作家。

  • 另一个选择是将其渲染为json using the variety of renditions possible,然后对自己进行带外后处理

  • 最后,如果您很好地标记了内容和/或具有将项目相关联的相关识别标记,则将构建Seq之类的东西来有效地解析此类事物(尽管我不知道一种渲染方式)一些如在有固定宽度格式)(东西也被在商店等压缩和全事件总是保留)