如何让Serilog准确识别抽象基类SourceContext以实现日志级别独立配置?
问题:Serilog中抽象基类日志的SourceContext被错误标记为实现类
场景
我在C#应用中使用Serilog配合自定义Sink将日志写入SEQ服务器,RPC服务依赖公司内部.Tools库。当前遇到的问题是:抽象基类ARpcServer中调用日志方法时,SourceContext被标记为实现类RpcNcCreator,而非实际的基类ARpcServer。
影响
我需要将ARpcServer的最低日志级别设为Warning以屏蔽其Info级日志,但保留RpcNcCreator的Info级日志。如果基于RpcNcCreator的命名空间做级别覆盖,会丢失该类所有Info日志,不符合需求。
需要解决的核心问题:能否通过配置Serilog或修改日志调用方式,让SourceContext准确对应日志调用所在的实际类(如ARpcServer),而非实现类?
应用层代码(RpcNcCreator)
namespace PPS.Kommunikation.Rpc public class RpcNcCreator : ARpcServer<TriggerUebergabeProdDaten, TriggerErgebnisNCDaten> { /// <summary> /// 返回一个已配置完成的<see cref="RpcNcCreator"/>对象。 /// </summary> /// <param name="loggerSingleton">日志对象。</param> /// <param name="iOptions">配置选项对象。</param> public RpcNcCreator(ILogger<RpcNcCreator> loggerSingleton, IOptions<RpcNcCreatorOptions> iOptions) : base(loggerSingleton) { Debug.Assert(iOptions != null); Debug.Assert(iOptions.Value != null); this.AnfrageExchange = iOptions.Value.AnfrageExchange; } // 此处存在调用日志的方法,例如: private void DocumentStatus() => logger.LogInformation("..."); }
内部库代码(ARpcServer)
namespace SpeedMaster.Tools.Kommunikation.RPC.Server; public abstract class ARpcServer<TArbeit, TErgebnis> : ARpcServer<TErgebnis>, IDisposable { public ARpcServer(ILogger<ARpcServer<TArbeit, TErgebnis>> loggerSingleton) { _logger = loggerSingleton; } // 在此基类中同样会输出日志,例如: private Task SendeStatusAnfrage(bool nurWennArbeitDaIst) { this._logger.LogInformation("Sende Status-Anfrage an alle Clients."); }
AppSettings.json配置示例
"Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Seq", "SpeedMaster.Tools", "PPS" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Error", "Microsoft.AspNetCore": "Warning", "System.Net.Http.HttpClient": "Warning", "SpeedMaster.Tools.Kommunikation.RPC.Server.Internal.ClientStatusChecker": "Warning" } }, "WriteTo": [ { "Name": "Seq", "Args": { "restrictedToMinimumLevel": "Information", "serverUrl": "https://at02-logsammler.speed.intern:45341", "apiKey": null } }, { "Name": "Console", "Args": { "theme": "PPS.Models.SerilogThemes.SpeedMasterThemes::Speedy, PPS", "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] ({SourceContext:l}) {Message:lj}{NewLine}{Exception}" } } ] },
补充说明
- 构造函数中,
RpcNcCreator的日志对象会被传入基类。 logger和_logger的命名差异:ARpcServer用传统构造函数赋值字段(下划线前缀),RpcNcCreator用主构造函数,团队规范不建议使用下划线前缀。
解决方案
1. 修正基类日志注入方式(推荐)
问题根源是你将ILogger<RpcNcCreator>传入基类构造函数,而依赖注入容器会隐式转换为兼容的ILogger<>实例,但SourceContext仍绑定到RpcNcCreator。正确做法是让基类直接注入专属的日志实例,不要从子类传递:
// 基类构造函数修改为直接注入自身的日志实例 public abstract class ARpcServer<TArbeit, TErgebnis> : ARpcServer<TErgebnis>, IDisposable { private readonly ILogger<ARpcServer<TArbeit, TErgebnis>> _logger; public ARpcServer(ILogger<ARpcServer<TArbeit, TErgebnis>> logger) { _logger = logger; } // 基类日志调用保持不变 private Task SendeStatusAnfrage(bool nurWennArbeitDaIst) { _logger.LogInformation("Sende Status-Anfrage an alle Clients."); // ... 其他逻辑 } }
子类构造函数移除日志参数,让DI自动处理基类的日志注入:
public RpcNcCreator(ILogger<RpcNcCreator> logger, IOptions<RpcNcCreatorOptions> iOptions) : base() // 不再传递logger参数 { // ... 原有逻辑 }
2. 手动指定SourceContext(无法修改基类时使用)
如果不能修改.Tools库的基类代码,可以在基类日志调用处手动覆盖SourceContext:
// 基类中修改日志调用,强制设置SourceContext为基类名称 _logger .ForContext("SourceContext", typeof(ARpcServer<TArbeit, TErgebnis>).FullName) .LogInformation("Sende Status-Anfrage an alle Clients.");
3. 配置层面临时方案(不推荐)
若上述代码修改不可行,可通过正则匹配区分基类和子类日志,但维护成本高:
"MinimumLevel": { "Default": "Information", "Override": { "^SpeedMaster\\.Tools\\.Kommunikation\\.RPC\\.Server\\.ARpcServer.*": "Warning", // 其他原有配置 "Microsoft": "Error", "Microsoft.AspNetCore": "Warning" } }
最终配置验证
完成代码修改后,在AppSettings.json中添加基类的级别覆盖:
"Override": { // ... 其他配置 "SpeedMaster.Tools.Kommunikation.RPC.Server.ARpcServer": "Warning" }
这样就能屏蔽基类的Info级日志,同时保留子类RpcNcCreator的Info日志。
内容的提问来源于stack exchange,提问作者FlorianD




