using System.Diagnostics; using System.Diagnostics.Metrics; using System.Reflection; using Microsoft.Extensions.Options; namespace BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider; public class CustomeDiagnosticsProvider(IMeterFactory meterFactory, IOptions options) : IDiagnosticsProvider { private readonly Version? _version = Assembly.GetCallingAssembly().GetName().Version; private ActivitySource? _activitySource; private ActivityListener? _listener; private Meter? _meter; public string InstrumentationName { get; } = options.Value.InstrumentationName ?? throw new ArgumentException("InstrumentationName cannot be null or empty."); // https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs public ActivitySource ActivitySource { get { if (_activitySource != null) return _activitySource; _activitySource = new(InstrumentationName, _version?.ToString()); _listener = new ActivityListener { ShouldListenTo = x => true, Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllDataAndRecorded, }; ActivitySource.AddActivityListener(_listener); return _activitySource; } } // https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation public Meter Meter { get { if (_meter != null) return _meter; _meter = meterFactory.Create(InstrumentationName, _version?.ToString()); return _meter; } } public async Task ExecuteActivityAsync( CreateActivityInfo createActivityInfo, Func action, CancellationToken cancellationToken = default ) { if (!options.Value.TracingEnabled) { await action(null, cancellationToken); return; } using var activity = ActivitySource .CreateActivity( name: $"{InstrumentationName}.{createActivityInfo.Name}", kind: createActivityInfo.ActivityKind, parentContext: createActivityInfo.Parent ?? default, idFormat: ActivityIdFormat.W3C, tags: createActivityInfo.Tags ) ?.Start() ?? Activity.Current; try { await action(activity!, cancellationToken); activity?.SetOkStatus(); } catch (System.Exception ex) { activity?.SetErrorStatus(ex); throw; } } public async Task ExecuteActivityAsync( CreateActivityInfo createActivityInfo, Func> action, CancellationToken cancellationToken = default ) { if (!options.Value.TracingEnabled) { return await action(null, cancellationToken); } using var activity = ActivitySource .CreateActivity( name: $"{InstrumentationName}.{createActivityInfo.Name}", kind: createActivityInfo.ActivityKind, parentContext: createActivityInfo.Parent ?? default, idFormat: ActivityIdFormat.W3C, tags: createActivityInfo.Tags ) ?.Start() ?? Activity.Current; try { var result = await action(activity!, cancellationToken); activity?.SetOkStatus(); return result; } catch (System.Exception ex) { activity?.SetErrorStatus(ex); throw; } } public void Dispose() { _listener?.Dispose(); _meter?.Dispose(); _activitySource?.Dispose(); } }