Files
lmxopcua/src/ZB.MOM.WW.OtOpcUa.Driver.Galaxy/Browse/TracedGalaxyHierarchySource.cs
T
Joseph Doherty 619207e7f5 PR 6.1 — OpenTelemetry traces around gw calls
In-box ActivitySource ("ZB.MOM.WW.OtOpcUa.Driver.Galaxy") wrapped around
the three gw-facing seams via decorators:

- TracedGalaxySubscriber — galaxy.subscribe_bulk / galaxy.unsubscribe_bulk
  / galaxy.stream_events spans. Stream span covers the entire stream
  lifetime with a galaxy.event_count tag (per-event spans would dominate
  the trace volume at 50k tags / 1Hz; PR 6.2 owns per-event metrics).
- TracedGalaxyDataWriter — galaxy.write spans tagged with
  galaxy.tag_count, galaxy.secured_write_count (split between FreeAccess
  /Operate vs Tune/Configure/VerifiedWrite, computed only when a listener
  is recording so the hot path stays free), galaxy.success_count.
- TracedGalaxyHierarchySource — galaxy.get_hierarchy spans tagged with
  galaxy.object_count.

GalaxyDriver.BuildProductionRuntimeAsync wraps the production seams in
the decorators. The driver itself doesn't take an OpenTelemetry package
dependency — System.Diagnostics.ActivitySource is in-box; the host
process picks the listener.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:36:47 -04:00

31 lines
1.2 KiB
C#

using MxGateway.Contracts.Proto.Galaxy;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Runtime;
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Browse;
/// <summary>
/// PR 6.1 — Decorator that emits one <see cref="System.Diagnostics.Activity"/> span
/// per <c>GetHierarchy</c> RPC. <c>galaxy.object_count</c> on the span lets ops
/// correlate slow Discover passes with Galaxy size without instrumenting the
/// discoverer's translation step.
/// </summary>
internal sealed class TracedGalaxyHierarchySource(IGalaxyHierarchySource inner, string clientName) : IGalaxyHierarchySource
{
public async Task<IReadOnlyList<GalaxyObject>> GetHierarchyAsync(CancellationToken cancellationToken)
{
using var activity = GalaxyTelemetry.ActivitySource.StartActivity("galaxy.get_hierarchy");
activity?.SetTag("galaxy.client", clientName);
try
{
var hierarchy = await inner.GetHierarchyAsync(cancellationToken).ConfigureAwait(false);
activity?.SetTag("galaxy.object_count", hierarchy.Count);
return hierarchy;
}
catch (Exception ex)
{
activity.RecordError(ex);
throw;
}
}
}