如何在Serilog中完全自定义日志级别显示名称?
嘿,这个需求完全可以搞定!Serilog本身就提供了足够灵活的扩展能力,让你完全自定义日志级别的显示名称——不管是换成其他语言,还是像你想要的VERBOSE、DBG、*EXCEPTION*、**FATAL**这种带特殊标记的格式,都能轻松实现。下面给你两种常用的方案,选适合你的就行:
方案一:通过自定义格式化器直接转换级别名称
这种方式适合需要在输出模板里直接控制级别显示的场景,核心是实现一个自定义的格式化器,把原生的LogEventLevel映射成你想要的名称。
- 首先定义级别名称映射字典:
var levelNameMap = new Dictionary<LogEventLevel, string> { { LogEventLevel.Verbose, "VERBOSE" }, { LogEventLevel.Debug, "DBG" }, { LogEventLevel.Information, "INFO" }, { LogEventLevel.Warning, "WARNING" }, { LogEventLevel.Error, "*EXCEPTION*" }, { LogEventLevel.Fatal, "**FATAL**" } };
- 实现自定义的级别格式化器:
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; } }
- 在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),然后直接在输出模板里使用这个属性,实现起来更简单,推荐大多数场景使用。
- 实现自定义的日志增强器(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)); } } }
- 在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设置的,也能轻松适配:
- 在
appsettings.json里配置输出模板和Enrich:
{ "Serilog": { "MinimumLevel": "Verbose", "Enrich": [ "WithCustomLevel" ], "WriteTo": [ { "Name": "Console", "Args": { "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{CustomLevel}] {Message}{NewLine}{Exception}" } } ] } }
- 在代码里注册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




