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

如何让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

火山引擎 最新活动