要说 .NET 生态里最受欢迎的日志库,Serilog 绝对排得上号。它设计得相当精巧——API 丰富、架构灵活,输出端和格式化器都是可插拔的,开发者几乎可以按需定制。下面就从基础概念开始,一步步把它拆开看看。

1. 日志级别

Serilog 按严重程度把日志分为六个级别,从高到低排列:

2. 日志输出

Serilog 原生支持多种输出目标(也就是 Sink),用得比较多的有:

当然,如果这些都不够用,还可以自己写一个自定义输出器。

3. 日志格式

Serilog 提供了几种格式化日志消息的方式:

4. 安装

通过 NuGet 直接安装就行:

Install-Package Serilog

5. 基础使用示例

用 Serilog 写日志其实很简单。下面是一个最基础的控制台输出例子:

using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .CreateLogger();

        Log.Information("Hello, Serilog!");

        Log.CloseAndFlush();
    }
}

运行之后,控制台就会打印出 Hello, Serilog! 这条信息。

6. 日志级别示例

设置不同的最小级别,就能控制哪些日志会被输出。下面的例子把级别降到 Verbose,然后依次记录了各个级别的消息:

using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Verbose()
            .WriteTo.Console()
            .CreateLogger();

        Log.Verbose("This is a verbose log message.");
        Log.Debug("This is a debug log message.");
        Log.Information("This is an informational log message.");
        Log.Warning("This is a warning log message.");
        Log.Error("This is an error log message.");
        Log.Fatal("This is a fatal log message.");

        Log.CloseAndFlush();
    }
}

7. 消息模板

消息模板是 Serilog 的一大亮点。你可以在日志中插入 {Name} 这样的占位符,运行时会被实际值替换:

using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
            .CreateLogger();

        Log.Information("Hello, {Name}!", "Serilog");

        Log.CloseAndFlush();
    }
}

输出效果类似这样:

2023-09-15 22:23:54.576 +08:00 [INF] Hello, Serilog!

8. 日志属性

除了简单的占位符,你还可以在日志里附加更复杂的属性——比如用匿名对象:

using Serilog;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .CreateLogger();

        Log.Information("Processed {@Count} records in {Time} ms.", new { Count = 10, Time = 123 });

        Log.CloseAndFlush();
    }
}

输出会把这个匿名对象的字段展开:

Processed { Count: 10, Time: 123 } records in 0 ms.

9. 文件输出配置

把日志写到文件里也很常见。通过 rollingInterval 可以控制文件按天滚动:

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(
        $"logs\\log-.txt", 
        rollingInterval: RollingInterval.Day, 
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
    .CreateLogger();

Log.Information("This is a log message!");
Log.CloseAndFlush();

这样每天会生成一个类似 log-20230914.txt 的文件,非常便于按日期归档。

10. 结构化日志记录

Serilog 支持真正的结构化日志——你可以直接把一个对象整体写进去,它会自动序列化并保留结构:

using Serilog;

class Program
{
    static void Main()
    {
        var weather = new WeatherForecast
        {
            Date = DateTime.Now,
            TemperatureC = 22,
            Summary = "Sunny"
        };

        Log.Information("Weather forecast: {@Weather}", weather);

        Log.CloseAndFlush();
    }
}

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public string Summary { get; set; }
}

输出结果会是一个 JSON 风格的字符串,保留所有属性和类型:

Weather forecast: {"Date":"2023-09-15T22:39:53.8634787+08:00","TemperatureC":22,"Summary":"Sunny","$type":"WeatherForecast"}

11. 日志过滤

有时候只想输出特定级别的日志,Serilog 的过滤器可以帮上忙。比如只保留 Error 及以上的消息:

using Serilog;
using Serilog.Events;

class Program
{
    static void Main()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .Filter.ByIncludingOnly(logEvent => logEvent.Level >= LogEventLevel.Error)
            .CreateLogger();

        Log.Verbose("This is a verbose log message.");
        Log.Error("This is an error log message.");

        Log.CloseAndFlush();
    }
}

运行后,控制台只会输出 Error 级别的消息,其他级别的都被过滤掉了。

12. 扩展与自定义输出器

如果内置的 Sink 不够用,完全可以自己写一个。下面是一个自定义控制台输出器的例子:

using Serilog;
using Serilog.Configuration;
using Serilog.Events;

public static class CustomConsoleSinkExtensions
{
    public static LoggerConfiguration CustomConsole(
        this LoggerSinkConfiguration sinkConfiguration,
        ITextFormatter formatter = null,
        LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
    {
        return sinkConfiguration.Sink(
            new CustomConsoleSink(formatter),
            restrictedToMinimumLevel);
    }
}

public class CustomConsoleSink : ILogEventSink
{
    private readonly ITextFormatter _formatter;

    public CustomConsoleSink(ITextFormatter formatter)
    {
        _formatter = formatter ?? throw new ArgumentNullException(nameof(formatter));
    }

    public void Emit(LogEvent logEvent)
    {
        var message = new StringWriter();
        _formatter.Format(logEvent, message);
        Console.WriteLine(message.ToString());
    }
}

然后通过扩展方法加入到配置链中:

Log.Logger = new LoggerConfiguration()
    .WriteTo.CustomConsole()
    .CreateLogger();

这样一来,日志输出的目的地、格式都可以完全由你掌控。

13. 总结

Serilog 在 .NET 日志领域能做到如此受欢迎,不是没有道理的。它提供了丰富的输出方式、灵活的格式化选项,以及强大的可扩展性。无论是简单的控制台输出,还是复杂的结构化日志和自定义 Sink,它都能轻松应对。希望这篇文章能帮你更顺畅地用好这个库。

本文转载于:https://www.jb51.net/aspnet/337030b64.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。