using System.Diagnostics; using System.Diagnostics.Metrics; using Jiaowu.Api.Domain.System; namespace Jiaowu.Api.Infrastructure.BackgroundJobs; public sealed class BackgroundJobTelemetry : IDisposable { public const string MeterName = "Jiaowu.BackgroundJobs"; private readonly Meter _meter = new(MeterName, "1.0.0"); private readonly Counter _published; private readonly Counter _processed; private readonly Histogram _publishDuration; private readonly Histogram _processingDuration; private readonly Counter _cleaned; public BackgroundJobTelemetry() { _published = _meter.CreateCounter( "jiaowu.background_jobs.published", unit: "{message}"); _processed = _meter.CreateCounter( "jiaowu.background_jobs.processed", unit: "{job}"); _publishDuration = _meter.CreateHistogram( "jiaowu.background_jobs.publish.duration", unit: "ms"); _processingDuration = _meter.CreateHistogram( "jiaowu.background_jobs.processing.duration", unit: "ms"); _cleaned = _meter.CreateCounter( "jiaowu.background_jobs.outbox.cleaned", unit: "{message}"); } public void RecordPublish( BackgroundJobKind kind, bool durable, string outcome, TimeSpan duration) { var tags = new TagList { { "job.kind", kind.ToString() }, { "messaging.backend", durable ? "rabbitmq" : "memory" }, { "job.outcome", outcome } }; _published.Add(1, tags); _publishDuration.Record(duration.TotalMilliseconds, tags); } public void RecordProcessing( BackgroundJobKind kind, string outcome, TimeSpan duration) { var tags = new TagList { { "job.kind", kind.ToString() }, { "job.outcome", outcome } }; _processed.Add(1, tags); _processingDuration.Record(duration.TotalMilliseconds, tags); } public void RecordCleaned(int count) { if (count > 0) _cleaned.Add(count); } public void Dispose() => _meter.Dispose(); }