2025-03-15 01:39:43 +03:30

133 lines
4.0 KiB
C#

using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Reflection;
using Microsoft.Extensions.Options;
namespace BuildingBlocks.OpenTelemetryCollector.DiagnosticsProvider;
public class CustomeDiagnosticsProvider(IMeterFactory meterFactory, IOptions<ObservabilityOptions> 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<ActivityContext> _) => 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<Activity?, CancellationToken, Task> 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<TResult?> ExecuteActivityAsync<TResult>(
CreateActivityInfo createActivityInfo,
Func<Activity?, CancellationToken, Task<TResult>> 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();
}
}