From b47026e9598797c08ec66659959c040ca6d4818f Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Mon, 20 Jul 2026 14:23:56 -0400 Subject: [PATCH 1/2] fix(telemetry): report current meter scope version Signed-off-by: Yordis Prieto --- .../TelemetryMeterFactoryTests.cs | 30 +++++++++++++++++++ .../Diagnostics/TelemetryMeterFactory.cs | 14 +++++++++ src/EventStore.Core/MetricsBootstrapper.cs | 4 +-- .../ProjectionsSubsystem.cs | 4 +-- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs create mode 100644 src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs 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..1651f3276 --- /dev/null +++ b/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs @@ -0,0 +1,30 @@ +using System; +using EventStore.Common.Utils; +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"); + + meter.Name.Should().Be("test-scope"); + meter.Version.Should().Be(VersionInfo.Version); + } + + [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..4b7211d0e --- /dev/null +++ b/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs @@ -0,0 +1,14 @@ +using System; +using System.Diagnostics.Metrics; +using EventStore.Common.Utils; + +namespace EventStore.Core.Diagnostics; + +public static class TelemetryMeterFactory +{ + public static Meter Create(string instrumentationScopeName) + { + ArgumentException.ThrowIfNullOrWhiteSpace(instrumentationScopeName); + return new Meter(instrumentationScopeName, VersionInfo.Version); + } +} 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; From 3ec008617f8ae3df3836cd6670a5eb1bf2481555 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Mon, 20 Jul 2026 14:39:41 -0400 Subject: [PATCH 2/2] fix(telemetry): keep scope version self-contained Signed-off-by: Yordis Prieto --- .../TelemetryMeterFactoryTests.cs | 7 +++++-- .../Diagnostics/TelemetryMeterFactory.cs | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs b/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs index 1651f3276..7ad0b0a5f 100644 --- a/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs +++ b/src/EventStore.Core.XUnit.Tests/OpenTelemetry/TelemetryMeterFactoryTests.cs @@ -1,5 +1,5 @@ using System; -using EventStore.Common.Utils; +using System.Reflection; using EventStore.Core.Diagnostics; using FluentAssertions; using Xunit; @@ -12,9 +12,12 @@ public class TelemetryMeterFactoryTests 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(VersionInfo.Version); + meter.Version.Should().Be(informationalVersion.Split('+', 2)[0]); } [Theory] diff --git a/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs b/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs index 4b7211d0e..bb6028383 100644 --- a/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs +++ b/src/EventStore.Core/Diagnostics/TelemetryMeterFactory.cs @@ -1,14 +1,29 @@ using System; using System.Diagnostics.Metrics; -using EventStore.Common.Utils; +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, VersionInfo.Version); + 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]; } }