< Summary

Information
Class: OzonOrdersWeb.Observability.HangfireObservabilityFilter
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Observability/HangfireObservabilityFilter.cs
Line coverage
71%
Covered lines: 30
Uncovered lines: 12
Coverable lines: 42
Total lines: 80
Line coverage: 71.4%
Branch coverage
73%
Covered branches: 19
Total branches: 26
Branch coverage: 73%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
OnPerforming(...)100%210%
OnPerformed(...)73.07%312680%
Logger(...)100%11100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Observability/HangfireObservabilityFilter.cs

#LineLine coverage
 1using System.Diagnostics;
 2using Hangfire.Common;
 3using Hangfire.Server;
 4using Serilog;
 5
 6namespace OzonOrdersWeb.Observability;
 7
 58public sealed class HangfireObservabilityFilter(int slowMilliseconds) : JobFilterAttribute, IServerFilter
 9{
 10    private const string StopwatchKey = "Studio2ObservabilityStopwatch";
 11
 12    public void OnPerforming(PerformingContext filterContext)
 13    {
 014        filterContext.Items[StopwatchKey] = Stopwatch.StartNew();
 015        Logger(filterContext.BackgroundJob.Job)
 016            .ForContext("JobId", filterContext.BackgroundJob.Id)
 017            .Information("Hangfire job {JobType}.{JobMethod} начат",
 018                filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name);
 019    }
 20
 21    public void OnPerformed(PerformedContext filterContext)
 22    {
 423        var elapsed = filterContext.Items.TryGetValue(StopwatchKey, out var value) && value is Stopwatch timer
 424            ? timer.ElapsedMilliseconds
 425            : 0;
 426        var logger = Logger(filterContext.BackgroundJob.Job)
 427            .ForContext("JobId", filterContext.BackgroundJob.Id)
 428            .ForContext("ElapsedMilliseconds", elapsed);
 29
 430        var isCanceled = filterContext.Exception is OperationCanceledException ||
 431                         (filterContext.Exception is AggregateException agg && agg.InnerExceptions.All(e => e is Operati
 32
 433        if (isCanceled)
 34        {
 235            var isShutdown = filterContext.Canceled ||
 236                             filterContext.CancellationToken?.ShutdownToken.IsCancellationRequested == true;
 37
 238            if (isShutdown)
 39            {
 140                logger.Information("Hangfire job {JobType}.{JobMethod} прерван остановкой сервера (re-queued) за {Elapse
 141                    filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name, elapsed);
 42            }
 43            else
 44            {
 145                logger.Warning("Hangfire job {JobType}.{JobMethod} отменён за {ElapsedMilliseconds} мс: {Message}",
 146                    filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name, elapsed, fil
 47            }
 148            return;
 49        }
 50
 251        var isLockContention = HangfireDistributedLockContentionFilter.IsDistributedLockContentionException(filterContex
 52
 253        if (filterContext.Exception is not null && !filterContext.ExceptionHandled && !isLockContention)
 54        {
 155            logger.Error(filterContext.Exception, "Hangfire job {JobType}.{JobMethod} завершился ошибкой за {ElapsedMill
 156                filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name, elapsed);
 57        }
 158        else if (filterContext.ExceptionHandled || isLockContention)
 59        {
 160            logger.Information("Hangfire job {JobType}.{JobMethod} завершён (обработан фильтром) за {ElapsedMilliseconds
 161                filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name, elapsed);
 62        }
 063        else if (elapsed >= slowMilliseconds)
 64        {
 065            logger.Warning("Медленный Hangfire job {JobType}.{JobMethod} завершён за {ElapsedMilliseconds} мс",
 066                filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name, elapsed);
 67        }
 68        else
 69        {
 070            logger.Information("Hangfire job {JobType}.{JobMethod} завершён за {ElapsedMilliseconds} мс",
 071                filterContext.BackgroundJob.Job.Type.Name, filterContext.BackgroundJob.Job.Method.Name, elapsed);
 72        }
 073    }
 74
 475    private static Serilog.ILogger Logger(Job job) => Log.ForContext("SourceContext", typeof(HangfireObservabilityFilter
 476        .ForContext("EventKind", "HangfireJob")
 477        .ForContext("EventCategory", "jobs")
 478        .ForContext("JobType", job.Type.FullName)
 479        .ForContext("JobMethod", job.Method.Name);
 80}