metrics(alarms): expose provider-switch count in snapshot, bound the reason tag
B1: add AlarmProviderSwitchCount to GatewayMetricsSnapshot so the switch total is readable without scraping the OTEL counter. B2: replace the free-text reason tag on mxgateway.alarms.provider_switches with a bounded AlarmProviderSwitchReason enum (failover/failback/unknown); the human-readable reason stays in the structured log.
This commit is contained in:
@@ -50,6 +50,7 @@ public sealed class GatewayMetrics : IDisposable
|
||||
private long _heartbeatFailures;
|
||||
private long _streamDisconnects;
|
||||
private long _retryAttempts;
|
||||
private long _alarmProviderSwitches;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
@@ -383,25 +384,34 @@ public sealed class GatewayMetrics : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Records that the alarm provider switched modes and updates the current provider mode gauge.
|
||||
/// Records that the alarm provider switched modes, increments the switch count, and updates the
|
||||
/// current provider mode gauge.
|
||||
/// </summary>
|
||||
/// <param name="fromMode">Provider mode before the switch (1=alarmmgr, 2=subtag, 0=unknown).</param>
|
||||
/// <param name="toMode">Provider mode after the switch (1=alarmmgr, 2=subtag, 0=unknown).</param>
|
||||
/// <param name="reason">Human-readable reason for the switch.</param>
|
||||
public void AlarmProviderSwitched(int fromMode, int toMode, string reason)
|
||||
/// <param name="reason">Bounded switch classification used as the counter's <c>reason</c> tag.</param>
|
||||
public void AlarmProviderSwitched(int fromMode, int toMode, AlarmProviderSwitchReason reason)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_alarmProviderMode = toMode;
|
||||
_alarmProviderSwitches++;
|
||||
}
|
||||
|
||||
_alarmProviderSwitchesCounter.Add(
|
||||
1,
|
||||
new KeyValuePair<string, object?>("from", fromMode.ToString(CultureInfo.InvariantCulture)),
|
||||
new KeyValuePair<string, object?>("to", toMode.ToString(CultureInfo.InvariantCulture)),
|
||||
new KeyValuePair<string, object?>("reason", reason));
|
||||
new KeyValuePair<string, object?>("reason", ReasonTag(reason)));
|
||||
}
|
||||
|
||||
private static string ReasonTag(AlarmProviderSwitchReason reason) => reason switch
|
||||
{
|
||||
AlarmProviderSwitchReason.Failover => "failover",
|
||||
AlarmProviderSwitchReason.Failback => "failback",
|
||||
_ => "unknown",
|
||||
};
|
||||
|
||||
/// <summary>Sets the current alarm provider-mode gauge without recording a switch (e.g. startup baseline).</summary>
|
||||
public void SetAlarmProviderMode(int mode)
|
||||
{
|
||||
@@ -433,6 +443,7 @@ public sealed class GatewayMetrics : IDisposable
|
||||
HeartbeatFailures: _heartbeatFailures,
|
||||
StreamDisconnects: _streamDisconnects,
|
||||
RetryAttempts: _retryAttempts,
|
||||
AlarmProviderSwitchCount: _alarmProviderSwitches,
|
||||
CommandFailuresByMethod: new Dictionary<string, long>(_commandFailuresByMethod, StringComparer.OrdinalIgnoreCase),
|
||||
EventsByFamily: new Dictionary<string, long>(_eventsByFamily, StringComparer.OrdinalIgnoreCase),
|
||||
EventsBySession: new Dictionary<string, long>(_eventsBySession, StringComparer.Ordinal),
|
||||
|
||||
Reference in New Issue
Block a user