You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Serilog中完全自定义日志级别显示名称?

嘿,这个需求完全可以搞定!Serilog本身就提供了足够灵活的扩展能力,让你完全自定义日志级别的显示名称——不管是换成其他语言,还是像你想要的VERBOSEDBG*EXCEPTION***FATAL**这种带特殊标记的格式,都能轻松实现。下面给你两种常用的方案,选适合你的就行:

方案一:通过自定义格式化器直接转换级别名称

这种方式适合需要在输出模板里直接控制级别显示的场景,核心是实现一个自定义的格式化器,把原生的LogEventLevel映射成你想要的名称。

  1. 首先定义级别名称映射字典:
var levelNameMap = new Dictionary<LogEventLevel, string>
{
    { LogEventLevel.Verbose, "VERBOSE" },
    { LogEventLevel.Debug, "DBG" },
    { LogEventLevel.Information, "INFO" },
    { LogEventLevel.Warning, "WARNING" },
    { LogEventLevel.Error, "*EXCEPTION*" },
    { LogEventLevel.Fatal, "**FATAL**" }
};
  1. 实现自定义的级别格式化器:
public class CustomLevelFormatter : IFormatProvider, ICustomFormatter
{
    private readonly Dictionary<LogEventLevel, string> _levelMap;

    public CustomLevelFormatter(Dictionary<LogEventLevel, string> levelMap)
    {
        _levelMap = levelMap;
    }

    public object GetFormat(Type formatType)
    {
        // 告诉Serilog这个类负责处理自定义格式化逻辑
        return formatType == typeof(ICustomFormatter) ? this : null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        // 如果参数是LogEventLevel类型,就用映射字典替换名称
        if (arg is LogEventLevel level)
        {
            return _levelMap.TryGetValue(level, out var customName) ? customName : level.ToString();
        }
        // 其他类型保持默认处理
        return arg?.ToString() ?? string.Empty;
    }
}
  1. 在Serilog配置中使用这个格式化器:
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console(
        new MessageTemplateTextFormatter(
            // 输出模板里用{LevelCustom}来指代自定义级别
            "{Timestamp:yyyy-MM-dd HH:mm:ss} [{LevelCustom}] {Message}{NewLine}{Exception}",
            formatters: new Dictionary<string, IFormatProvider>
            {
                { "LevelCustom", new CustomLevelFormatter(levelNameMap) }
            }))
    .CreateLogger();
方案二:通过Enricher添加自定义级别属性(更简洁)

这种方式是通过给日志事件添加一个自定义属性(比如CustomLevel),然后直接在输出模板里使用这个属性,实现起来更简单,推荐大多数场景使用。

  1. 实现自定义的日志增强器(Enricher):
public class CustomLevelEnricher : ILogEventEnricher
{
    // 直接在类里定义级别映射
    private readonly Dictionary<LogEventLevel, string> _levelMap = new()
    {
        { LogEventLevel.Verbose, "VERBOSE" },
        { LogEventLevel.Debug, "DBG" },
        { LogEventLevel.Information, "INFO" },
        { LogEventLevel.Warning, "WARNING" },
        { LogEventLevel.Error, "*EXCEPTION*" },
        { LogEventLevel.Fatal, "**FATAL**" }
    };

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        // 给当前日志事件添加CustomLevel属性
        if (_levelMap.TryGetValue(logEvent.Level, out var customName))
        {
            logEvent.AddPropertyIfAbsent(
                propertyFactory.CreateProperty("CustomLevel", customName));
        }
    }
}
  1. 在Serilog配置中启用这个Enricher,并在输出模板里使用{CustomLevel}
Log.Logger = new LoggerConfiguration()
    .Enrich.With<CustomLevelEnricher>() // 添加自定义增强器
    .WriteTo.Console(
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{CustomLevel}] {Message}{NewLine}{Exception}")
    .CreateLogger();

补充:用配置文件(appsettings.json)配置的情况

如果你的项目是用配置文件来管理Serilog设置的,也能轻松适配:

  1. appsettings.json里配置输出模板和Enrich:
{
  "Serilog": {
    "MinimumLevel": "Verbose",
    "Enrich": [ "WithCustomLevel" ],
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{CustomLevel}] {Message}{NewLine}{Exception}"
        }
      }
    ]
  }
}
  1. 在代码里注册Enricher(以ASP.NET Core为例):
var builder = WebApplication.CreateBuilder(args);

// 配置Serilog并注册自定义Enricher
builder.Host.UseSerilog((context, config) =>
{
    config.ReadFrom.Configuration(context.Configuration)
          .Enrich.With<CustomLevelEnricher>();
});

// ...其他项目配置
var app = builder.Build();
app.Run();

这样配置后,你的日志输出就会完全按照自定义的级别名称显示,不管是特殊符号还是不同长度的名称都能完美支持,再也不用受固定格式的限制啦!

内容的提问来源于stack exchange,提问作者Asterisk

火山引擎 最新活动