如何使用 Serilog 在 Json 中获取日志级别 - .NET Core 3.1

How To Get Log Level in Json with Serilog - .NET Core 3.1

我是 Serilog 的新手,我正在尝试确定如何使用 log leveldate time 将序列化的 json 发送到 console场地。 structured data 下的文档中似乎没有任何信息。

这是我在 Startup.cs:

中调用的代码
private void LoggerLoop(ILogger<Startup> logger)
{
    RabbitModel rb = new RabbitModel
    {
        Id = 1,
        DeviceNum = 1,
        DeviceName = "Device 1",
        InputNum = 1,
        InputName = "Input 1",
        InputState = 1,
        OnPhrase = "On",
        OffPhrase = "Off",
        When = "2020-01-01T22:45:00.1124303+00:00"
    };

    while (true)
    {
        logger.LogInformation("{@rb}", rb);
        Thread.Sleep(1000);
    }
}

这是我的输出:

[14:28:22 INF] {"Id": 1, "DeviceNum": 1, "DeviceName": "Device 1", "InputNum": 1, "InputName": "Input 1", "InputState": 1, "OnPhrase": "On", "OffPhrase": "Off", "When": "2020-01-01T22:45:00.1124303+00:00", "$type": "RabbitModel"}

我确实注意到它添加了一个字段 $type,想知道是否可以将 [14:28:22 INF] 添加到 json

根据12 factor app,应用程序应将所有日志写入stdout/stderr

然后您需要将所有日志收集在一起,并为此目的提供到一个或多个最终目的地以供查看(Elasticserach). Open-source log routers (such as FluentBit, Fluentd and Logplex)的路由。

因此,该应用从不关心其日志的路由或存储。在 dotnet 应用程序中,您可以使用 Serilog

轻松实现它

假设我们在 appsettings.json

中有以下记录器设置
"Logging": {
    "OutputFormat": "console",
    "MinimumLevel": "Information"
}

我们可以创建一个扩展方法

private static IWebHostBuilder CreateWebHostBuilder() =>
    WebHost.CreateDefaultBuilder()
        .UseStartup<Startup>()
        .UseLogging();
}

可以以纯文本和elasticsearch 格式将日志写入控制台。纯文本日志对开发很有用,因为它更易于阅读。在生产环境中,我们启用 elasticsearch 格式并仅在 Kibana 中查看所有日志。

带注释的扩展代码:

public static IWebHostBuilder UseLogging(this IWebHostBuilder webHostBuilder, string applicationName = null) =>
    webHostBuilder
        .UseSetting("suppressStatusMessages", "True") // disable startup logs
        .UseSerilog((context, loggerConfiguration) =>
        {
            var logLevel = context.Configuration.GetValue<string>("Logging:MinimumLevel"); // read level from appsettings.json
            if (!Enum.TryParse<LogEventLevel>(logLevel, true, out var level))
            {
                level = LogEventLevel.Information; // or set default value
            }

            // get application name from appsettings.json
            applicationName = string.IsNullOrWhiteSpace(applicationName) ? context.Configuration.GetValue<string>("App:Name") : applicationName;

            loggerConfiguration.Enrich
                .FromLogContext()
                .MinimumLevel.Is(level)
                .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
                .MinimumLevel.Override("System", LogEventLevel.Warning)
                .Enrich.WithProperty("Environment", context.HostingEnvironment.EnvironmentName)
                .Enrich.WithProperty("ApplicationName", applicationName);

            // read other Serilog configuration
            loggerConfiguration.ReadFrom.Configuration(context.Configuration);

            // get output format from appsettings.json. 
            var outputFormat = context.Configuration.GetValue<string>("Logging:OutputFormat");
            switch (outputFormat)
            {
                case "elasticsearch":
                    loggerConfiguration.WriteTo.Console(new ElasticsearchJsonFormatter());
                    break;
                default:
                    loggerConfiguration.WriteTo.Console(
                        theme: AnsiConsoleTheme.Code,
                        outputTemplate: "[{Timestamp:yy-MM-dd HH:mm:ss.sssZ} {Level:u3}] {Message:lj} <s:{Environment}{Application}/{SourceContext}>{NewLine}{Exception}");
                    break;
            }
        });

OutputFormatelasticsearch 时,日志将像

{"@timestamp":"2020-02-07T16:02:03.4329033+02:00","level":"Information","messageTemplate":"Get customer by id: {CustomerId}","message":"Get customer by id: 20","fields":{"CustomerId":20,"SourceContext":"Customers.Api.Controllers.CustomerController","ActionId":"c9d77549-bb25-4f87-8ea8-576dc6aa1c57","ActionName":"Customers.Api.Controllers.CustomerController.Get (Customers.Api)","RequestId":"0HLTBQP5CQHLM:00000004","RequestPath":"/v1/customers","CorrelationId":"daef8849b662117e","ConnectionId":"0HLTBQP5CQHLM","Environment":"Development","ApplicationName":"API","Timestamp":"2020-02-07T14:02:03.4329033Z"}}

其他情况(仅用于调试)

[20-02-07 13:59:16.16Z INF] Get customer by id: 20

然后你应该配置日志路由器从容器中收集日志并将其发送到 Elasticsearch。

如果所有日志都是 structured,它会改进 Kibana 中的搜索和创建索引。