feat(telemetry): deploy-failure, S&F activity, script-run and DCL-transition instruments (ScadaBridge#81)
Adds four instruments on the already-allow-listed ZB.MOM.WW.ScadaBridge meter:
scadabridge.deployments.failed{reason}, scadabridge.store_and_forward.activity{action,category},
scadabridge.site.script.runs{outcome} + scadabridge.site.script.duration{outcome} (ms),
scadabridge.site.data_connections.transitions{state}. Queue depth, DCL connection state and
deploy-applied already existed. No new Meter, so ZbTelemetryOptions.Meters needs no change.
Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
+42
@@ -12,6 +12,48 @@ namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.Scripts;
|
||||
/// </summary>
|
||||
public class ScriptRunSummaryRecorderTests
|
||||
{
|
||||
/// <summary>Verifies each finished run emits the script runs counter and duration histogram with its outcome (ScadaBridge#81).</summary>
|
||||
[Fact]
|
||||
public void FinishedRuns_EmitRunCounterAndDurationHistogram_TaggedByOutcome()
|
||||
{
|
||||
// MeterListener callbacks run synchronously on the emitting thread, so filtering on the
|
||||
// test thread isolates this test from other tests emitting on the same process-wide meter.
|
||||
var tid = Environment.CurrentManagedThreadId;
|
||||
var runs = new List<string?>();
|
||||
var durations = new List<(string? Outcome, long Ms)>();
|
||||
using var listener = new System.Diagnostics.Metrics.MeterListener
|
||||
{
|
||||
InstrumentPublished = (i, l) =>
|
||||
{
|
||||
if (i.Meter.Name == Commons.Observability.ScadaBridgeTelemetry.MeterName
|
||||
&& (i.Name == "scadabridge.site.script.runs" || i.Name == "scadabridge.site.script.duration"))
|
||||
l.EnableMeasurementEvents(i);
|
||||
}
|
||||
};
|
||||
static string? Outcome(ReadOnlySpan<KeyValuePair<string, object?>> tags)
|
||||
{
|
||||
foreach (var t in tags) if (t.Key == "outcome") return t.Value as string;
|
||||
return null;
|
||||
}
|
||||
listener.SetMeasurementEventCallback<long>((inst, m, tags, _) =>
|
||||
{
|
||||
if (Environment.CurrentManagedThreadId != tid) return;
|
||||
if (inst.Name == "scadabridge.site.script.runs") runs.Add(Outcome(tags));
|
||||
else durations.Add((Outcome(tags), m));
|
||||
});
|
||||
listener.Start();
|
||||
|
||||
var recorder = new ScriptRunSummaryRecorder();
|
||||
recorder.RecordCompleted("i", "s", 10);
|
||||
recorder.RecordFailed("i", "s", 20);
|
||||
recorder.RecordTimedOut("i", "s", 30);
|
||||
|
||||
Assert.Equal(new string?[] { "completed", "failed", "timed_out" }, runs);
|
||||
Assert.Equal(
|
||||
new (string?, long)[] { ("completed", 10), ("failed", 20), ("timed_out", 30) },
|
||||
durations);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that flushing with no activity emits no row.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user