b350fba233
LocalDbReplicationHealthCheck reports Healthy when replication is default-OFF or LocalDb is absent (admin-only graphs) - so a plain node is never degraded by it - Degraded when configured-but-disconnected, connected-with-unknown-backlog (a failed oplog poll must not read as zero), or connected-with-backlog past the threshold. Never Unhealthy: a replication fault does not stop the node serving its address space. Pure decision core is table-tested; registered unconditionally via a factory so AddOtOpcUaHealth keeps its no-arg signature and resolves ISyncStatus optionally. Adds LocalDbMetrics.MeterName to the observability allowlist. o.Meters is a strict allowlist with no wildcard, so the localdb.sync.* / localdb.oplog.depth series were otherwise silently absent from /metrics - the omission a ScadaBridge live gate caught.
60 lines
3.1 KiB
C#
60 lines
3.1 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using ZB.MOM.WW.LocalDb.Replication;
|
|
using ZB.MOM.WW.OtOpcUa.Commons.Observability;
|
|
using ZB.MOM.WW.Telemetry;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Host.Observability;
|
|
|
|
/// <summary>
|
|
/// Wires the OtOpcUa Meter + ActivitySource into OpenTelemetry and exposes a Prometheus
|
|
/// scrape endpoint at <c>/metrics</c> on the host pipeline. F13d slice — only the meter +
|
|
/// activity source declared in <see cref="OtOpcUaTelemetry"/> are surfaced; per-Akka
|
|
/// internals + ASP.NET request metrics stay off by default to keep the scrape payload
|
|
/// scoped to OtOpcUa-owned signals.
|
|
/// </summary>
|
|
public static class ObservabilityExtensions
|
|
{
|
|
/// <summary>Adds OtOpcUa observability (metrics and tracing) to the service collection.</summary>
|
|
/// <param name="services">The service collection to add observability services to.</param>
|
|
/// <param name="configuration">
|
|
/// Configuration read for the opt-in OTLP exporter. <c>OtOpcUa:Telemetry:Exporter</c>
|
|
/// (parsed case-insensitively to <see cref="ZbExporter"/>) switches to OTLP when set to
|
|
/// <c>Otlp</c>; <c>OtOpcUa:Telemetry:OtlpEndpoint</c> sets the OTLP endpoint. With no
|
|
/// config the exporter stays Prometheus (the default).
|
|
/// </param>
|
|
/// <returns>The service collection, for chaining.</returns>
|
|
public static IServiceCollection AddOtOpcUaObservability(this IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
return services.AddZbTelemetry(o =>
|
|
{
|
|
o.ServiceName = "otopcua";
|
|
// o.Meters is a STRICT allowlist — ZbTelemetry adds only the named meters, with no
|
|
// wildcard. The LocalDb replication engine publishes under its own meter name, so
|
|
// without this entry its localdb.sync.* / localdb.oplog.depth series are silently absent
|
|
// from /metrics on driver nodes (the exact omission a ScadaBridge live gate caught).
|
|
o.Meters = [OtOpcUaTelemetry.MeterName, LocalDbMetrics.MeterName];
|
|
o.ActivitySources = [OtOpcUaTelemetry.ActivitySourceName];
|
|
if (Enum.TryParse<ZbExporter>(configuration["OtOpcUa:Telemetry:Exporter"], ignoreCase: true, out var exporter))
|
|
o.Exporter = exporter;
|
|
var otlp = configuration["OtOpcUa:Telemetry:OtlpEndpoint"];
|
|
if (!string.IsNullOrWhiteSpace(otlp))
|
|
o.OtlpEndpoint = otlp;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mounts the Prometheus <c>/metrics</c> scrape endpoint on the existing ASP.NET pipeline.
|
|
/// The endpoint is explicitly marked <c>AllowAnonymous</c> so unauthenticated Prometheus
|
|
/// scrapers can reach it regardless of the host's auth fallback policy (which on admin-role
|
|
/// nodes is <c>RequireAuthenticatedUser</c>). This mirrors the behaviour of
|
|
/// <c>MapZbHealth</c>, which also marks its endpoints anonymous.
|
|
/// </summary>
|
|
/// <param name="app">The endpoint route builder.</param>
|
|
/// <returns>The endpoint route builder, for chaining.</returns>
|
|
public static IEndpointRouteBuilder MapOtOpcUaMetrics(this IEndpointRouteBuilder app)
|
|
{
|
|
app.MapZbMetrics().AllowAnonymous();
|
|
return app;
|
|
}
|
|
}
|