|
|
|
@@ -33,6 +33,45 @@ public static class ScadaBridgeTelemetry
|
|
|
|
|
Meter.CreateCounter<long>("scadabridge.deployments.applied", unit: "1",
|
|
|
|
|
description: "Deployments applied.");
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Incremented for each deployment that ends in a terminal failure (ScadaBridge#81), tagged
|
|
|
|
|
/// <c>reason</c>: <c>timeout</c> (the site round-trip timed out), <c>error</c> (any other fault
|
|
|
|
|
/// in the send or post-send persistence path) or <c>site_failed</c> (the site answered with a
|
|
|
|
|
/// non-Success status). Pairs with <c>scadabridge.deployments.applied</c> to give the deploy
|
|
|
|
|
/// success ratio; the rate-limited log lines cannot be alerted on.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static readonly Counter<long> _deploymentsFailed =
|
|
|
|
|
Meter.CreateCounter<long>("scadabridge.deployments.failed", unit: "1",
|
|
|
|
|
description: "Deployments that ended in a terminal failure, tagged by reason (timeout|error|site_failed).");
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Incremented for each store-and-forward lifecycle event (ScadaBridge#81), tagged <c>action</c>
|
|
|
|
|
/// (<c>Queued</c>, <c>Delivered</c>, <c>Retried</c>, <c>Parked</c>, <c>Retry</c>, <c>Discard</c>)
|
|
|
|
|
/// and <c>category</c>. A sustained <c>Parked</c> rate is the alertable signal that messages are
|
|
|
|
|
/// exhausting retries; the queue-depth gauge alone cannot distinguish a drain from a park.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static readonly Counter<long> _sfActivity =
|
|
|
|
|
Meter.CreateCounter<long>("scadabridge.store_and_forward.activity", unit: "1",
|
|
|
|
|
description: "Store-and-forward lifecycle events, tagged by action and category.");
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Incremented for each finished site script run (ScadaBridge#81), tagged <c>outcome</c>
|
|
|
|
|
/// (<c>completed</c> | <c>failed</c> | <c>timed_out</c>). Deliberately NOT tagged by instance or
|
|
|
|
|
/// script name: that cardinality is unbounded across a site's instances.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static readonly Counter<long> _scriptRuns =
|
|
|
|
|
Meter.CreateCounter<long>("scadabridge.site.script.runs", unit: "1",
|
|
|
|
|
description: "Finished site script runs, tagged by outcome (completed|failed|timed_out).");
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Incremented each time a data connection actually CHANGES state (ScadaBridge#81), tagged
|
|
|
|
|
/// <c>state</c> (the new <see cref="ConnectionHealth"/>). The data_connections gauges show the
|
|
|
|
|
/// current picture; this shows flapping that a scrape interval would otherwise average away.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static readonly Counter<long> _dataConnectionTransitions =
|
|
|
|
|
Meter.CreateCounter<long>("scadabridge.site.data_connections.transitions", unit: "1",
|
|
|
|
|
description: "Data connection state changes, tagged by the new state.");
|
|
|
|
|
|
|
|
|
|
/// <summary>Incremented for each inbound API request, tagged with the API method.</summary>
|
|
|
|
|
private static readonly Counter<long> _inboundApiRequests =
|
|
|
|
|
Meter.CreateCounter<long>("scadabridge.inbound_api.requests", unit: "1",
|
|
|
|
@@ -151,6 +190,11 @@ public static class ScadaBridgeTelemetry
|
|
|
|
|
Meter.CreateHistogram<int>("scadabridge.site.stream.batch_size", unit: "1",
|
|
|
|
|
description: "Events per site gRPC stream frame (1 = unbatched frame), tagged by stream kind.");
|
|
|
|
|
|
|
|
|
|
/// <summary>Duration of finished site script runs in milliseconds (ScadaBridge#81), tagged by outcome.</summary>
|
|
|
|
|
private static readonly Histogram<long> _scriptRunDuration =
|
|
|
|
|
Meter.CreateHistogram<long>("scadabridge.site.script.duration", unit: "ms",
|
|
|
|
|
description: "Site script run duration in milliseconds, tagged by outcome (completed|failed|timed_out).");
|
|
|
|
|
|
|
|
|
|
// ---------------- Observable gauges ----------------
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@@ -271,6 +315,29 @@ public static class ScadaBridgeTelemetry
|
|
|
|
|
/// <summary>Records that a deployment was applied.</summary>
|
|
|
|
|
public static void RecordDeploymentApplied() => _deploymentsApplied.Add(1);
|
|
|
|
|
|
|
|
|
|
/// <summary>Records one deployment that ended in a terminal failure (ScadaBridge#81).</summary>
|
|
|
|
|
/// <param name="reason">One of <c>timeout</c>, <c>error</c>, <c>site_failed</c>.</param>
|
|
|
|
|
public static void RecordDeploymentFailed(string reason) =>
|
|
|
|
|
_deploymentsFailed.Add(1, new KeyValuePair<string, object?>("reason", reason));
|
|
|
|
|
|
|
|
|
|
/// <summary>Records one store-and-forward lifecycle event (ScadaBridge#81).</summary>
|
|
|
|
|
/// <param name="action">The activity action, e.g. <c>Parked</c>.</param>
|
|
|
|
|
/// <param name="category">The message category name.</param>
|
|
|
|
|
public static void RecordStoreAndForwardActivity(string action, string category) =>
|
|
|
|
|
_sfActivity.Add(1,
|
|
|
|
|
new KeyValuePair<string, object?>("action", action),
|
|
|
|
|
new KeyValuePair<string, object?>("category", category));
|
|
|
|
|
|
|
|
|
|
/// <summary>Records one finished site script run and its duration (ScadaBridge#81).</summary>
|
|
|
|
|
/// <param name="outcome">One of <c>completed</c>, <c>failed</c>, <c>timed_out</c>.</param>
|
|
|
|
|
/// <param name="durationMs">The run duration in milliseconds.</param>
|
|
|
|
|
public static void RecordScriptRun(string outcome, long durationMs)
|
|
|
|
|
{
|
|
|
|
|
var tag = new KeyValuePair<string, object?>("outcome", outcome);
|
|
|
|
|
_scriptRuns.Add(1, tag);
|
|
|
|
|
_scriptRunDuration.Record(durationMs < 0 ? 0 : durationMs, tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Records an inbound API request for the given <paramref name="method"/>.</summary>
|
|
|
|
|
/// <param name="method">The API method the request targeted.</param>
|
|
|
|
|
public static void RecordInboundApiRequest(string method) =>
|
|
|
|
@@ -333,7 +400,13 @@ public static class ScadaBridgeTelemetry
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var previous = _dataConnectionStates.TryGetValue(connectionName, out var prior) ? prior : (ConnectionHealth?)null;
|
|
|
|
|
_dataConnectionStates[connectionName] = state;
|
|
|
|
|
|
|
|
|
|
if (previous != state)
|
|
|
|
|
{
|
|
|
|
|
_dataConnectionTransitions.Add(1, new KeyValuePair<string, object?>("state", state.ToString()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|