serilog格式SourceContext,仅显示程序集名称

mni*_*eto 4 c# serilog .net-core asp.net-core-2.0

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

namespace FlickPopper.API.Controllers {

    public class ValuesController : Controller {
        private ILogger<ValuesController> _logger;
        public MyClass(ILogger<ValuesController> logger) {
           _logger = logger;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,serilog创建了记录器调用 Log.ForContext<classname>

我的设置是:

  "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" ]
    }
Run Code Online (Sandbox Code Playgroud)

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

2018-01-26 22:20:08 [INF] [FlickPopper.API.Controllers.ValuesController] Get all values
Run Code Online (Sandbox Code Playgroud)

格式化SourceContext属性以仅显示日志中的程序集名称,这是什么方式?

2018-01-26 22:20:08 [INF] [FlickPopper.API] Get all values
Run Code Online (Sandbox Code Playgroud)

Cod*_*ler 7

当您使用注入时ILogger<T>,引擎盖下的Serilog记录器由实现接口的SerilogLoggerProvider创建ILoggerProvider.这个接口有唯一的方法:

public interface ILoggerProvider : IDisposable
{
    ILogger CreateLogger(string categoryName);
}
Run Code Online (Sandbox Code Playgroud)

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

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

首先创建该值的负责类是Logger<T>class.的情况下,Logger<T>当你注入被实例化ILogger<T>到您的类.这是它的构造函数的源代码:

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)));
    }

    //  ...
}
Run Code Online (Sandbox Code Playgroud)

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

因此,如果您想要更改该行为并调整categoryName传递给ILoggerFactory,那么您应该拥有自己的实现,ILogger<T>从而进行必要的调用ILoggerFactory.CreateLogger().这并不困难,因为Logger<T>课程非常薄,并且基于Microsoft.Extensions.Logging.Logger实施.这是Logger<T>除了生成记录器类别名称的一行之外的类的副本:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

您还应该ILogger<T>在服务注册中替换此标准实现:

services.AddSingleton(typeof(ILogger<>), typeof(LoggerEx<>));

现在,实例LoggerEx<T>将注入控制器并{SourceContext}具有您构建的值:

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


Ste*_*ter 6

我遇到了类似的问题,但我只想包含类/接口名称。

我通过创建自定义丰富器解决了这个问题。

// Create logger
var logger = new LoggerConfiguration()
  // ...
  .Enrich.With(new SourceContextEnricher())
  // ...
  .CreateLogger();

public class SourceContextEnricher : ILogEventEnricher {

  public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) {
    if (logEvent.Properties.TryGetValue("SourceContext", out var property)) {
      var scalarValue = property as ScalarValue;
      var value = scalarValue?.Value as string;

      if (value?.StartsWith("FlickPopper.API.") ?? false) {
        var lastElement = value.Split(".").LastOrDefault();
        if (!string.IsNullOrWhiteSpace(lastElement)) {
          logEvent.AddOrUpdateProperty(new LogEventProperty("SourceContext", new ScalarValue(lastElement)));
        }
      }

    }
  }
}
Run Code Online (Sandbox Code Playgroud)