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:
@@ -97,6 +97,43 @@ public class QueueDepthGaugeTests : IAsyncLifetime, IDisposable
|
||||
return observed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ScadaBridge#81: the service emits <c>scadabridge.store_and_forward.activity</c> for a buffered
|
||||
/// message (Queued) and for a message that exhausts its retries (Parked), through the real service.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ActivityCounter_IsEmitted_ForQueuedAndParked()
|
||||
{
|
||||
var seen = new System.Collections.Concurrent.ConcurrentQueue<string>();
|
||||
using var listener = new MeterListener
|
||||
{
|
||||
InstrumentPublished = (i, l) =>
|
||||
{
|
||||
if (i.Meter.Name == ScadaBridgeTelemetry.MeterName
|
||||
&& i.Name == "scadabridge.store_and_forward.activity")
|
||||
l.EnableMeasurementEvents(i);
|
||||
}
|
||||
};
|
||||
listener.SetMeasurementEventCallback<long>((_, _, tags, _) =>
|
||||
{
|
||||
foreach (var t in tags)
|
||||
if (t.Key == "action" && t.Value is string a) seen.Enqueue(a);
|
||||
});
|
||||
listener.Start();
|
||||
|
||||
_service.RegisterDeliveryHandler(StoreAndForwardCategory.ExternalSystem,
|
||||
_ => throw new HttpRequestException("transient"));
|
||||
|
||||
var r = await _service.EnqueueAsync(
|
||||
StoreAndForwardCategory.ExternalSystem, "api-activity", """{}""", maxRetries: 1);
|
||||
Assert.True(r.WasBuffered);
|
||||
await _service.RetryPendingMessagesAsync();
|
||||
|
||||
Assert.Contains("Queued", seen);
|
||||
Assert.Contains("Parked", seen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Review 2026-10-21 02/C3: rows that arrive without passing through this node's counter
|
||||
/// paths (LocalDb CDC on a standby) are picked up by the sweep's periodic re-seed.
|
||||
|
||||
Reference in New Issue
Block a user