fix(historian): latch the recorder's dropped-kind Debug log per run; pin the outbox.unreadable gauge
The DroppedUnsupportedKind counter still counts every value; only the Debug line is latched (cleared by the next captured value), so a Gateway-backend comms loss no longer logs one line per tag. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
||||
using System.Diagnostics.Metrics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Observability;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Runtime.Historian;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Historian;
|
||||
|
||||
/// <summary>
|
||||
/// The <c>otopcua.historian.outbox.unreadable</c> gauge reports the bound outbox's
|
||||
/// <see cref="IHistorizationOutbox.UnreadableCount"/>. The listener is filtered by the instrument INSTANCE (the
|
||||
/// shared <see cref="OtOpcUaTelemetry.Meter"/> object plus the instrument name), never by meter name alone, so a
|
||||
/// parallel test's measurements on another meter of the same name cannot reach it; and the bound outbox reports a
|
||||
/// distinctive count, so the asserted value can only have come from this test's outbox.
|
||||
/// </summary>
|
||||
public sealed class ContinuousHistorizationMetricsTests
|
||||
{
|
||||
private const string GaugeName = "otopcua.historian.outbox.unreadable";
|
||||
|
||||
[Fact]
|
||||
public void The_unreadable_gauge_reports_the_bound_outboxs_unreadable_count()
|
||||
{
|
||||
const long distinctive = 7_331_919L;
|
||||
ContinuousHistorizationMetrics.BindOutbox(new UnreadableOutbox(distinctive));
|
||||
|
||||
var observed = new List<long>();
|
||||
using var listener = new MeterListener
|
||||
{
|
||||
InstrumentPublished = (instrument, l) =>
|
||||
{
|
||||
if (ReferenceEquals(instrument.Meter, OtOpcUaTelemetry.Meter) && instrument.Name == GaugeName)
|
||||
l.EnableMeasurementEvents(instrument);
|
||||
},
|
||||
};
|
||||
listener.SetMeasurementEventCallback<long>((instrument, value, _, _) =>
|
||||
{
|
||||
if (instrument.Name == GaugeName) observed.Add(value);
|
||||
});
|
||||
listener.Start();
|
||||
listener.RecordObservableInstruments();
|
||||
|
||||
observed.ShouldBe([distinctive]);
|
||||
}
|
||||
|
||||
private sealed class UnreadableOutbox(long unreadable) : IHistorizationOutbox
|
||||
{
|
||||
public long DroppedCount => 0;
|
||||
public long UnreadableCount => unreadable;
|
||||
public ValueTask AppendAsync(HistorizationOutboxEntry entry, CancellationToken ct) => ValueTask.CompletedTask;
|
||||
public ValueTask AppendBatchAsync(IReadOnlyList<HistorizationOutboxEntry> entries, CancellationToken ct) => ValueTask.CompletedTask;
|
||||
public ValueTask<IReadOnlyList<HistorizationOutboxEntry>> PeekBatchAsync(int max, CancellationToken ct) =>
|
||||
ValueTask.FromResult<IReadOnlyList<HistorizationOutboxEntry>>([]);
|
||||
public ValueTask RemoveAsync(Guid id, CancellationToken ct) => ValueTask.CompletedTask;
|
||||
public ValueTask<int> CountAsync(CancellationToken ct) => ValueTask.FromResult(0);
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user