Обогатите Serlilogs уникальной ценностью за каждое задание Hangfire

Я использую Hangfire для фоновых заданий и Serilog для ведения журнала. Я пытаюсь обогатить свои серилоги знаком TrackingId, чтобы все журналы определенного задания Hangfire имели одинаковые TrackingId, которые я могу фильтровать.

Я настраиваю Serilog так в Startup.cs:

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

Но это не приведет к установке отдельного TrackingId для каждого задания Hangfire. Есть ли способ добиться этого?


person Joel    schedule 16.10.2017    source источник
comment
Я просмотрел API Hangfire и не могу найти способ сделать это легко; добавление серверного фильтра кажется, что это может сработать. HTH.   -  person Nicholas Blumhardt    schedule 17.10.2017


Ответы (1)


Как бы то ни было, в итоге я добился этого, используя фильтр сервер / клиент и GlobalJobFilters регистрацию, показанную ниже. Одна неприятная проблема, с которой я столкнулся, заключается в том, что AutomaticRetryAttribute добавляется по умолчанию в коллекцию GlobalJobFilters, и этот класс будет регистрировать ошибки для невыполненных заданий без информации о Serilog LogContext, созданном в нашем пользовательском JobLoggerAttribute. Лично я знаю, что разрешу только повторную попытку вручную, поэтому я просто удалил этот атрибут и обработал ошибку в методе IServerFilter.OnPerformed. Проверьте конец моего сообщения, чтобы узнать, как удалить его, если это сработает для вас.

Если вы собираетесь разрешить автоматическую повторную попытку, вам необходимо: 1) создать настраиваемый атрибут, который украшает AutomaticRetryAttribute и информирует его о настраиваемом LogContext, 2) снова удалить значение по умолчанию AutomaticRetryAttribute из коллекции 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());

Удаление _11 _...

var automaticRetryFilter = GlobalJobFilters.Filters.Where(x => x.Instance is AutomaticRetryAttribute).Single();
GlobalJobFilters.Filters.Remove(automaticRetryFilter.Instance);
person ryanulit    schedule 27.12.2017
comment
Как это на самом деле потокобезопасно? Поле _log используется всеми рабочими потоками. - person Bryan Crosby; 26.01.2018