【问题标题】:serilog format SourceContext for showing only assembly nameserilog 格式 SourceContext 用于仅显示程序集名称
【发布时间】:2018-07-06 07:24:27
【问题描述】:

我将我的项目配置为使用 Serilog 通过依赖注入进行日志记录。 我在类构造函数中使用以下模式:

namespace FlickPopper.API.Controllers {

    public class ValuesController : Controller {
        private ILogger<ValuesController> _logger;
        public MyClass(ILogger<ValuesController> logger) {
           _logger = logger;
        }
    }
}

通过这种方式,serilog 创建调用Log.ForContext&lt;classname&gt;的记录器

我的设置是:

  "Serilog": {
      "WriteTo": [
        {
          "Name": "RollingFile",
          "Args": {
            "pathFormat": "Logs\\log-{Date}.txt",
            "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] {Message}{NewLine}{Exception}"
          }
        }
      ],
      "Enrich": [ "FromLogContext" ]
    }

所以,日志看起来像这样:

2018-01-26 22:20:08 [INF] [FlickPopper.API.Controllers.ValuesController] Get all values

有什么方法可以格式化 SourceContext 属性以在日志中只显示程序集名称,像这样?

2018-01-26 22:20:08 [INF] [FlickPopper.API] Get all values

【问题讨论】:

    标签: c# .net-core asp.net-core-2.0 serilog


    【解决方案1】:

    当您使用注入的ILogger&lt;T&gt; 时,Serilog 记录器是由实现ILoggerProvider 接口的SerilogLoggerProvider 创建的。这个接口只有一个方法:

    public interface ILoggerProvider : IDisposable
    {
        ILogger CreateLogger(string categoryName);
    }
    

    传递的categoryName 用作消息格式中{SourceContext} 属性的值。并且 ASP.NET Core 将其作为完全限定名称传递(例如 FlickPopper.API.Controllers.ValuesController)。

    所以这个字符串值不应该在 Serilog 代码或配置中固定,而是在 ASP.NET Core 日志记录基础架构中。

    首先负责创建该值的类是Logger&lt;T&gt; 类。 Logger&lt;T&gt; 的实例在您将 ILogger&lt;T&gt; 注入类时被实例化。这是其构造函数的source code

    public class Logger<T> : ILogger<T>
    {
        public Logger(ILoggerFactory factory)
        {
            if (factory == null)
            {
                throw new ArgumentNullException(nameof(factory));
            }
    
            _logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T)));
        }
    
        //  ...
    }
    

    TypeNameHelper.GetTypeDisplayName(typeof(T)) 的调用返回完全限定名称,然后将其传递给ILoggerFactory 并最终传递给SerilogLoggerProvider

    因此,如果您想更改该行为并调整传递给ILoggerFactorycategoryName,您应该拥有自己的ILogger&lt;T&gt; 实现,它需要调用ILoggerFactory.CreateLogger()。这并不难,因为Logger&lt;T&gt; 类非常薄并且基于Microsoft.Extensions.Logging.Logger 实现。这是Logger&lt;T&gt; 的副本的类,除了一行生成记录器类别名称:

    public class LoggerEx<T> : ILogger<T>
    {
        private readonly ILogger _logger;
    
        public LoggerEx(ILoggerFactory factory)
        {
            if (factory == null)
            {
                throw new ArgumentNullException(nameof(factory));
            }
    
            _logger = factory.CreateLogger(typeof(T).Assembly.GetName().Name);
        }
    
        IDisposable ILogger.BeginScope<TState>(TState state)
        {
            return _logger.BeginScope(state);
        }
    
        bool ILogger.IsEnabled(LogLevel logLevel)
        {
            return _logger.IsEnabled(logLevel);
        }
    
        void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            _logger.Log(logLevel, eventId, state, exception, formatter);
        }
    }
    

    您还应该在服务注册中将ILogger&lt;T&gt; 的标准实现替换为这个:

    services.AddSingleton(typeof(ILogger&lt;&gt;), typeof(LoggerEx&lt;&gt;));

    现在LoggerEx&lt;T&gt; 的实例将被注入到控制器中,{SourceContext} 将具有您构建的值:

    2018-01-27 09:54:21 [INF] [TestProject.TestApplication] 你好!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-15
      相关资源
      最近更新 更多