| | | 1 | | using System.Collections.Concurrent; |
| | | 2 | | using System.Diagnostics.Metrics; |
| | | 3 | | |
| | | 4 | | namespace ArturRios.Heimdall.WebApi.Retention; |
| | | 5 | | |
| | | 6 | | /// <summary> |
| | | 7 | | /// The instruments every scheduled pass reports through, labelled by <c>pass</c>, so an operator can |
| | | 8 | | /// alert on "no successful run in N hours" instead of relying on a log line being noticed (#214). |
| | | 9 | | /// </summary> |
| | | 10 | | /// <remarks> |
| | | 11 | | /// Registered on the meter <see cref="MeterName" />, which <c>MetricsConfiguration</c> subscribes the |
| | | 12 | | /// exporter to. The instruments exist whether or not metrics are enabled; with nothing listening |
| | | 13 | | /// they cost a branch. |
| | | 14 | | /// </remarks> |
| | | 15 | | public static class ScheduledPassMetrics |
| | | 16 | | { |
| | | 17 | | /// <summary>The meter the exporter is told to collect.</summary> |
| | | 18 | | public const string MeterName = "ArturRios.Heimdall.ScheduledPasses"; |
| | | 19 | | |
| | 1 | 20 | | private static readonly Meter Meter = new(MeterName); |
| | | 21 | | |
| | 1 | 22 | | private static readonly Counter<long> Rows = Meter.CreateCounter<long>( |
| | 1 | 23 | | "heimdall.scheduled_pass.rows_processed", |
| | 1 | 24 | | description: "Rows a scheduled pass has changed, by pass."); |
| | | 25 | | |
| | 1 | 26 | | private static readonly ConcurrentDictionary<string, long> LastSuccess = new(); |
| | | 27 | | |
| | | 28 | | // Held only so the instrument is not collected; the callback reads LastSuccess. |
| | 1 | 29 | | private static readonly ObservableGauge<long> LastSuccessGauge = Meter.CreateObservableGauge( |
| | 1 | 30 | | "heimdall.scheduled_pass.last_success_timestamp", |
| | 5 | 31 | | () => LastSuccess.Select(entry => new Measurement<long>(entry.Value, new KeyValuePair<string, object?>("pass", e |
| | 1 | 32 | | description: "Unix time in seconds of the last run of a scheduled pass that completed without failure, by pass." |
| | | 33 | | |
| | | 34 | | /// <summary>Adds the rows a run reported to the pass's counter.</summary> |
| | | 35 | | public static void RowsProcessed(string pass, long rows) |
| | | 36 | | { |
| | 12 | 37 | | if (rows > 0) |
| | | 38 | | { |
| | 6 | 39 | | Rows.Add(rows, new KeyValuePair<string, object?>("pass", pass)); |
| | | 40 | | } |
| | 12 | 41 | | } |
| | | 42 | | |
| | | 43 | | /// <summary>Records now as the pass's last successful run.</summary> |
| | 9 | 44 | | public static void Succeeded(string pass) => LastSuccess[pass] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); |
| | | 45 | | |
| | | 46 | | /// <summary>The pass's last successful run as unix seconds, or <c>null</c> if it has not succeeded.</summary> |
| | 3 | 47 | | public static long? LastSuccessOf(string pass) => LastSuccess.TryGetValue(pass, out var at) ? at : null; |
| | | 48 | | } |