diff --git a/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs b/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs new file mode 100644 index 000000000..7ad0b0a5f --- /dev/null +++ b/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs @@ -0,0 +1,33 @@ +using System; +using System.Reflection; +using EventStore.Core.Diagnostics; +using FluentAssertions; +using Xunit; + +namespace EventStore.Core.XUnit.Tests.OpenTelemetry; + +public class TelemetryMeterFactoryTests +{ + [Fact] + public void UsesTheCurrentServerVersionForTheInstrumentationScope() + { + using var meter = TelemetryMeterFactory.Create("test-scope"); + var informationalVersion = typeof(TelemetryMeterFactory).Assembly + .GetCustomAttribute()! + .InformationalVersion; + + meter.Name.Should().Be("test-scope"); + meter.Version.Should().Be(informationalVersion.Split('+', 2)[0]); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void RejectsMissingInstrumentationScopeNames(string instrumentationScopeName) + { + var action = () => TelemetryMeterFactory.Create(instrumentationScopeName); + + action.Should().Throw(); + } +} diff --git a/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs b/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs new file mode 100644 index 000000000..bb6028383 --- /dev/null +++ b/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs @@ -0,0 +1,29 @@ +using System; +using System.Diagnostics.Metrics; +using System.Reflection; + +namespace EventStore.Core.Diagnostics; + +public static class TelemetryMeterFactory +{ + private static readonly string InstrumentationScopeVersion = GetInstrumentationScopeVersion(); + + public static Meter Create(string instrumentationScopeName) + { + ArgumentException.ThrowIfNullOrWhiteSpace(instrumentationScopeName); + return new Meter(instrumentationScopeName, InstrumentationScopeVersion); + } + + private static string GetInstrumentationScopeVersion() + { + var informationalVersion = typeof(TelemetryMeterFactory).Assembly + .GetCustomAttribute()? + .InformationalVersion; + if (string.IsNullOrWhiteSpace(informationalVersion)) + { + throw new InvalidOperationException("The telemetry assembly has no informational version."); + } + + return informationalVersion.Split('+', 2)[0]; + } +} diff --git a/src/EventStore.Core/MetricsBootstrapper.cs b/src/EventStore.Core/MetricsBootstrapper.cs index dc82c3ff5..e1c18e495 100644 --- a/src/EventStore.Core/MetricsBootstrapper.cs +++ b/src/EventStore.Core/MetricsBootstrapper.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics.Metrics; using System.Linq; using EventStore.Core.Bus; +using EventStore.Core.Diagnostics; using EventStore.Core.Index; using EventStore.Core.Metrics; using EventStore.Core.Services.VNode; @@ -84,7 +84,7 @@ public static void Bootstrap( return; } - var coreMeter = new Meter("EventStore.Core", version: "1.0.0"); + var coreMeter = TelemetryMeterFactory.Create("EventStore.Core"); var statusMetric = new StatusMetric(coreMeter, "eventstore-statuses"); var grpcMethodMetric = new DurationMetric(coreMeter, "eventstore-grpc-method-duration"); var gossipLatencyMetric = new DurationMetric(coreMeter, "eventstore-gossip-latency"); diff --git a/src/EventStore.Projections.Core/ProjectionsSubsystem.cs b/src/EventStore.Projections.Core/ProjectionsSubsystem.cs index 8a64d037e..ced9a5f2e 100644 --- a/src/EventStore.Projections.Core/ProjectionsSubsystem.cs +++ b/src/EventStore.Projections.Core/ProjectionsSubsystem.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.Metrics; using System.Linq; using System.Threading.Tasks; using DotNext; @@ -9,6 +8,7 @@ using EventStore.Core; using EventStore.Core.Bus; using EventStore.Core.Data; +using EventStore.Core.Diagnostics; using EventStore.Core.Messages; using EventStore.Core.Messaging; using EventStore.Core.Services.AwakeReaderService; @@ -205,7 +205,7 @@ private void ConfigureProjectionMetrics(bool isEnabled) return; } - var projectionMeter = new Meter("EventStore.Projections.Core", version: "1.0.0"); + var projectionMeter = TelemetryMeterFactory.Create("EventStore.Projections.Core"); var tracker = new ProjectionTracker(); _projectionTracker = tracker;