用于仅显示程序集名称的 serilog 格式 SourceContext [英] serilog format SourceContext for showing only assembly name

查看:40
本文介绍了用于仅显示程序集名称的 serilog 格式 SourceContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I configured my project to use Serilog for logging using dependecy injection. I use the following schema in the classes constructor:

namespace FlickPopper.API.Controllers {

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

通过这种方式,serilog创建了对Log.ForContext

In this way, serilog creates the logger calling to 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" ]
    }

所以,日志看起来是这样的:

So, the logs seems like this:

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

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

It's any way to format the SourceContext property to show only the assembly name in the logs, somthing like this?

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

推荐答案

当你使用注入的 ILogger 时,在底层 Serilog 记录器是由 SerilogLoggerProvider 实现了 ILoggerProvider界面.这个接口只有一个方法:

When you use injected ILogger<T>, under the hood Serilog logger is created by SerilogLoggerProvider that implements ILoggerProvider interface. This interface has the only method:

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

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

The passed categoryName is used as value for {SourceContext} property in message format. And ASP.NET Core passes it as fully-qualified name (e.g. FlickPopper.API.Controllers.ValuesController).

因此,不应在 Serilog 代码或配置中修复此字符串值,而应在 ASP.NET Core 日志记录基础结构中进行修复.

So this string value should be fixed not in Serilog code or configuration, but in ASP.NET Core logging infrastructure.

首先负责创建该值的类是 Logger 类.Logger 的实例在您将 ILogger 注入您的类时被实例化.这是源代码它的构造函数:

The responsible class for creation of that value in first place is Logger<T> class. Instances of Logger<T> are instantiated when you inject ILogger<T> into your classes. Here is source code of its constructor:

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.

That call to TypeNameHelper.GetTypeDisplayName(typeof(T)) returns fully-qualified name that then is passed to ILoggerFactory and eventually to SerilogLoggerProvider.

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

So if you want to change that behavior and adjust the categoryName passed to ILoggerFactory, you should have your own implementation of ILogger<T> that makes required call to ILoggerFactory.CreateLogger(). It's not that difficult, because Logger<T> class is very thin and is based on Microsoft.Extensions.Logging.Logger implementation. Here is the class that is a copy of Logger<T> except for one line producing logger category name:

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 的标准实现替换为以下实现:

You should also replace the standard implementation of ILogger<T> with this one in your services registration:

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

现在 LoggerEx 的实例将被注入控制器并且 {SourceContext} 将有一个你构建的值:

Now the instances of LoggerEx<T> will be injected to the controllers and {SourceContext} will have a value you built:

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

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

这篇关于用于仅显示程序集名称的 serilog 格式 SourceContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆