【问题标题】:Enrich Serlilogs with unique value per hangfire job为每个 hangfire 作业丰富 Serlilogs 的独特价值
【发布时间】:2017-10-16 13:25:47
【问题描述】:

我将 Hangfire 用于后台作业,将 Serilog 用于日志记录。我正在尝试使用 TrackingId 丰富我的 serilog,以便来自特定 Hangfire 作业的所有日志都将具有相同的 TrackingId,我可以过滤。

我在Startup.cs中这样配置Serilog:

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(Configuration)
    .WriteTo.Seq(serverUrl: serverUrl, apiKey: apiKey)

    // Enrich the logs with a tracking id. Will be a new value per request
    .Enrich.WithProperty("TrackingId", Guid.NewGuid())

    .CreateLogger();

然后我将这样的工作排入队列:

BackgroundJob.Enqueue<MyService>(myService => myService.DoIt(someParameter));

但这样做不会为每个 Hangfire 作业设置单独的 TrackingId。有什么方法可以实现吗?

【问题讨论】:

  • 我已经查看了 Hangfire API,但找不到轻松实现此目的的方法;添加“服务器过滤器”似乎可行。 HTH。

标签: asp.net-core .net-core hangfire serilog


【解决方案1】:

为了它的价值,我最终使用服务器/客户端过滤器和GlobalJobFilters 注册来完成它,如下所示。我遇到的一个烦人的问题是AutomaticRetryAttribute 默认添加到GlobalJobFilters 集合中,并且该类will log errors for failed jobs 不知道在我们的自定义JobLoggerAttribute 中创建的Serilog LogContext。就个人而言,我知道我只会允许手动重试,所以我只是删除了该属性并在IServerFilter.OnPerformed 方法中处理了错误。检查我帖子的结尾,看看如果这对你有用,如何删除它。

如果您要允许自动重试,那么您需要:1) 创建一个自定义属性来装饰 AutomaticRetryAttribute 并使其知道自定义 LogContext,2) 再次从GlobalJobFilters 集合,以及 3) 将您的装饰器属性添加到集合中。

public class JobLoggerAttribute : JobFilterAttribute, IClientFilter, IServerFilter
{
    private ILogger _log;

    public void OnCreating(CreatingContext filterContext)
    {
        _log = GetLogger();

        _log.Information("Job is being created for {JobType} with arguments {JobArguments}", filterContext.Job.Type.Name, filterContext.Job.Args);
    }

    public void OnCreated(CreatedContext filterContext)
    {
        _log.Information("Job {JobId} has been created.", filterContext.BackgroundJob.Id);
    }

    public void OnPerforming(PerformingContext filterContext)
    {
        if (_log == null)
            _log = GetLogger();

        _log.Information("Job {JobId} is performing.", filterContext.BackgroundJob.Id);
    }

    public void OnPerformed(PerformedContext filterContext)
    {
        _log.Information("Job {JobId} has performed.", filterContext.BackgroundJob.Id);

        if (filterContext.Exception != null)
        {
            _log.Error(
                filterContext.Exception,
                "Job {JobId} failed due to an exception.",
                filterContext.BackgroundJob.Id);
        }

        _log = null;
    }

    private ILogger GetLogger()
    {
        return Log.ForContext(GetType()).ForContext("HangfireRequestId", Guid.NewGuid());
    }
}

还有注册...

GlobalJobFilters.Filters.Add(new JobLoggerAttribute());

正在删除AutomaticRetryAttribute...

var automaticRetryFilter = GlobalJobFilters.Filters.Where(x => x.Instance is AutomaticRetryAttribute).Single();
GlobalJobFilters.Filters.Remove(automaticRetryFilter.Instance);

【讨论】:

  • 这实际上是线程安全的吗? _log 字段在工作线程之间共享。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
相关资源
最近更新 更多