Serilog 日志格式模板

2024年12月30日 62点热度 0人点赞 0条评论
内容目录

通用模板如下:

Serilog:
  Using:
    - "Serilog.Sinks.Console"
  MinimumLevel:
    Default: Information
    Override:
      Microsoft.AspNetCore.HttpLogging: Information
      ProtoBuf.Grpc.Server.ServicesExtensions.CodeFirstServiceMethodProvider: Warning
      Microsoft.EntityFrameworkCore: Information
      Microsoft.AspNetCore: Warning
      System.Net.Http.HttpClient.TenantManagerClient.LogicalHandler: Warning
      Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted: Warning
      System: Information
      Microsoft: Information
      Grpc: Information
      MySqlConnector: Information
  WriteTo:
    - Name: Console
      Args:
        outputTemplate: "{SourceContext} {Scope} {Timestamp:HH:mm} [{Level}]{NewLine}    {Properties:j}{NewLine}    {Message:lj} {Exception} {NewLine}"
  Enrich:
    - FromLogContext
    - WithMachineName
    - WithThreadId

json:

{
  "Serilog": {
    "Using": [
      "Serilog.Sinks.Console"
    ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft.AspNetCore.HttpLogging": "Information",
        "ProtoBuf.Grpc.Server.ServicesExtensions.CodeFirstServiceMethodProvider": "Warning",
        "Microsoft.EntityFrameworkCore": "Information",
        "Microsoft.AspNetCore": "Warning",
        "System.Net.Http.HttpClient.TenantManagerClient.LogicalHandler": "Warning",
        "Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted": "Warning",
        "System": "Information",
        "Microsoft": "Information",
        "Grpc": "Information",
        "MySqlConnector": "Information"
      }
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{SourceContext} {Scope} {Timestamp:HH:mm} [{Level}]{NewLine}    {Properties:j}{NewLine}    {Message:lj} {Exception} {NewLine}"
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      "WithMachineName",
      "WithThreadId"
    ]
  }
}

在代码中使用,如在 ASP.NET Core 使用时:

        // 配置日志.
        builder.Logging.ClearProviders();

        builder.Host.UseSerilog((ctx, services, configuration) =>
        {
            configuration.ReadFrom.Services(services);
#if DEBUG
            // 在本地不需要特定格式化
            configuration.ReadFrom.Configuration(ctx.Configuration)

            // 自定义部分日志的格式
            .Enrich.With(new MyLogEnricher());
#else
            // 使用 json 收集时,忽略日志模板
            ctx.Configuration["Serilog:WriteTo:0:Args:outputTemplate"] = "";

            // 以 json 格式化输出
            configuration.WriteTo.Console(new RenderedCompactJsonFormatter())
            .ReadFrom.Configuration(ctx.Configuration)

            // 自定义部分日志的格式
            .Enrich.With(new MyLogEnricher());
#endif
        });

默认情况下使用 configuration.ReadFrom.Configuration(ctx.Configuration) 时,日志就是正常人类方便阅读的格式。

file

如果我们需要重定向输出,可以使用:

.WriteTo.Console(new RenderedCompactJsonFormatter())

对比:

configuration
.ReadFrom.Configuration(ctx.Configuration)
↓ ↓ ↓
configuration
.WriteTo.Console(new RenderedCompactJsonFormatter())   // 多了这一句
.ReadFrom.Configuration(ctx.Configuration)

Serilog 提供了四种 json 格式化器。

下面是四种格式化器的性能测试:

Formatter Median StdDev Scaled
JsonFormatter 11.2775 µs 0.0682 µs 1.00
CompactJsonFormatter 6.0315 µs 0.0429 µs 0.53
JsonFormatter(renderMessage: true) 13.7585 µs 0.1194 µs 1.22
RenderedCompactJsonFormatter 7.0680 µs 0.0605 µs 0.63

建议大家使用 RenderedCompactJsonFormatter。

对于 JsonFormatter 和 CompactJsonFormatter ,只在长度上差一点,CompactJsonFormatter 的压缩性比较好,但是阅读起来不方便,这两者都是将参数模板和参数值分开存储的。

以该日志为例:

_logger.Information("Hello, {@User}, {N:x8} at {Now}", new { Name = "nblumhardt", Tags = new[] { 1, 2, 3 } }, 123, DateTime.Now);

JsonFormatter 的格式:

{
    "Timestamp": "2016-06-07T13:44:57.8532799+10:00",
    "Level": "Information",
    "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
    "Properties": {
        "User": {
            "Name": "nblumhardt",
            "Tags": [1, 2, 3]
        },
        "N": 123,
        "Now": "2016-06-07T13:44:57.8532799+10:00"
    },
    "Renderings": {
        "N": [{
            "Format": "x8",
            "Rendering": "0000007b"
        }]
    }
}

CompactJsonFormatter 的格式:

{
    "@t": "2016-06-07T03:44:57.8532799Z",
    "@mt": "Hello, {@User}, {N:x8} at {Now}",
    "@r": ["0000007b"],
    "User": {
        "Name": "nblumhardt",
        "Tags": [1, 2, 3]
    },
    "N": 123,
    "Now": "2016-06-07T13:44:57.8532799+10:00"
}

两者都是记录日志原本的字符串 "Hello, {@User}, {N:x8} at {Now}",但是不在字符串里面重定向输出结果(格式化),而是单独使用别的属性分开存储 UserNNow 的值。

那么对于 JsonFormatter(renderMessage: true)RenderedCompactJsonFormatter 则是上面两者的重定向(格式化)版本,会直接在原字符串里面格式化。

JsonFormatter(renderMessage: true) 格式:

{
    "Timestamp": "2024-12-30T08:54:32.2909994+08:00",
    "Level": "Information",
    "MessageTemplate": "Hello, {@User}, {N:x8} at {Now}",
    "RenderedMessage": "Hello, { Name: \"nblumhardt\", Tags: [1, 2, 3] }, 0000007b at 12/30/2024 08:54:32",
    "Properties": {
        "User": {
            "Name": "nblumhardt",
            "Tags": [1, 2, 3]
        },
        "N": 123,
        "Now": "2024-12-30T08:54:32.2886810+08:00",
        "SourceContext": "BSI.SDMS.Api.Program"
    },
    "Renderings": {
        "N": [{
            "Format": "x8",
            "Rendering": "0000007b"
        }]
    }
}

RenderedCompactJsonFormatter 格式:

{
    "@t": "2024-12-30T00:53:09.8507927Z",
    "@m": "Hello, { Name: \"nblumhardt\", Tags: [1, 2, 3] }, 0000007b at 12/30/2024 08:53:09",
    "@i": "4e2159b8",
    "User": {
        "Name": "nblumhardt",
        "Tags": [1, 2, 3]
    },
    "N": 123,
    "Now": "2024-12-30T08:53:09.8484345+08:00",
    "SourceContext": "BSI.SDMS.Api.Program"
}

痴者工良

高级程序员劝退师

文章评论