首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >泛型ILogger或通过Serilog添加日志属性

泛型ILogger或通过Serilog添加日志属性
EN

Stack Overflow用户
提问于 2021-01-20 20:18:05
回答 1查看 1.5K关注 0票数 2

是否有方法向给定的ILogger实例添加属性?(来自Microsoft.Extensions.Logging.Abstractions)。我使用的是Serilog,通常将ILogger实例注入构造函数。因此,它也可能是利用一些Serilog API的解决方案。

我知道ILogger.BeginScopeLogContext.PushProperty,但它们只是将信息添加到当前的异步上下文中。我希望将信息添加到记录器本身的实例中,以便该记录器生成的任何日志都具有额外的属性。

我希望达到的目标类似于:

代码语言:javascript
运行
复制
class Foo {
  private ILogger logger;
  public Foo(ILogger logger) {
     logger.AddProperty("Property", "value"); // now every calls using that logger have that extra prop
     _logger = logger;
  }

  public void Dummy() => _logger.LogDebug("logging something..."); // this log event would have the Property=value added to it automatically
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-23 03:01:26

更新2021-08-21:您现在可以使用Serilog.Enrichers.GlobalLogContext了。

Serilog.Enrichers.GlobalLogContext安装NuGet包:

代码语言:javascript
运行
复制
Install-Package Serilog.Enrichers.GlobalLogContext

将Serilog名称空间添加到C#文件中:

代码语言:javascript
运行
复制
using Serilog;
using Serilog.Context;

在记录器配置中包括全局日志上下文丰富器:

代码语言:javascript
运行
复制
Log.Logger = new LoggerConfiguration()
    .Enrich.FromGlobalLogContext()
    // ... other configuration ...
    .CreateLogger();

FromGlobalLogContext()动态地将Serilog.Context.GlobalLogContext中的属性添加到应用程序中的所有生成事件中。

然后,可以使用GlobalLogContext.PushProperty()从全局日志上下文中添加和删除属性。

代码语言:javascript
运行
复制
GlobalLogContext.PushProperty("AppVersion", GetThisAppVersion());
GlobalLogContext.PushProperty("OperatingSystem", GetCurrentOS());

在执行上述代码之后,写入任何Serilog接收器的任何日志事件都将自动携带属性AppVersionOperatingSystem

来源:https://github.com/augustoproiete/serilog-enrichers-globallogcontext

原始答案

实现这一目标的一种方法是创建一个自定义塞里罗格·恩里希,从一开始就连接到Serilog日志记录管道,您还可以访问整个应用程序(最好是通过依赖项注入)。

这将为您提供一种添加新属性的方法,并负责确保将这些属性应用于所有日志事件。

下面的示例是这个想法的简化版本(绝对不推荐作为- is 用于生产,而是作为伪代码来展示主要部分是如何结合在一起的基本知识):

代码语言:javascript
运行
复制
// WARNING: This is *NOT* Production code :)

public sealed class GlobalPropertyEnricher : ILogEventEnricher
{
    // TODO: Make it thread-safe
    private static readonly Dictionary<string, object> _properties =
        new Dictionary<string, object>();

    private static readonly Lazy<GlobalPropertyEnricher> _instance =
        new Lazy<GlobalPropertyEnricher>(() => new GlobalPropertyEnricher());

    public static GlobalPropertyEnricher Instance => _instance.Value;

    private GlobalPropertyEnricher()
    {
    }

    public static void SetProperty(string propertyName, object value)
    {
        // TODO: Make it thread-safe
        _properties[propertyName] = value;
    }

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        // TODO: Make it thread-safe
        // TODO: Properties should be cached (instead of CreateProperty) every time

        foreach (var p in _properties)
        {
            var property = propertyFactory.CreateProperty(p.Key, p.Value);
            logEvent.AddPropertyIfAbsent(property);
        }
    }
}

注意:为了这个例子的目的,我有一个静态类可以通过你的应用程序全局访问,但你的程序。将其注册为DI容器中的辛格尔顿实例。

通过上面丰富的示例,您可以通过GlobalPropertyEnricher.SetProperty从任何地方添加/替换属性。例如:

代码语言:javascript
运行
复制
GlobalPropertyEnricher.SetProperty("Name", "Augusto");
GlobalPropertyEnricher.SetProperty("Year", DateTime.UtcNow.Year);

最后,当您在Serilog管道中包含丰富器时,您设置的所有属性都将添加到应用程序中写入的每个事件日志消息中:

代码语言:javascript
运行
复制
Log.Logger = new LoggerConfiguration()
    .Enrich.With(GlobalPropertyEnricher.Instance)
    .WriteTo.(...)
    .CreateLogger();
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65817012

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档