From 8f92955f5ecccb2c471727cbc1a31b43c2b73839 Mon Sep 17 00:00:00 2001 From: Jack Berg <34418638+jack-berg@users.noreply.github.com> Date: Fri, 15 May 2026 14:46:16 -0500 Subject: [PATCH 1/3] Add unit test codifying that view names need to conform to metric name requirements --- .../sdk/metrics/IdentityTest.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java index 195c8730e45..7be2bd1c210 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java @@ -28,6 +28,8 @@ class IdentityTest { @RegisterExtension LogCapturer viewRegistryLogs = LogCapturer.create().captureForType(ViewRegistry.class); + @RegisterExtension LogCapturer sdkMeterLogs = LogCapturer.create().captureForType(SdkMeter.class); + private InMemoryMetricReader reader; private SdkMeterProviderBuilder builder; @@ -1092,6 +1094,51 @@ void sameMeterDifferentInstrumentIncompatibleViewAggregation() { .hasSize(1); } + @Test + void viewNameNotValidated() { + // View names are not validated against the instrument name pattern. When a view sets a name + // that would be rejected if used directly as an instrument name (e.g. starts with a digit), + // the SDK accepts it and produces a metric with the invalid name without logging a warning. + SdkMeterProvider meterProvider = + builder + .registerView( + InstrumentSelector.builder().setType(InstrumentType.COUNTER).build(), + View.builder().setName("1invalid-name").build()) + .build(); + + meterProvider.get("meter1").counterBuilder("counter1").build().add(10); + + assertThat(reader.collectAllMetrics()) + .satisfiesExactlyInAnyOrder( + metricData -> + assertThat(metricData) + .hasInstrumentationScope(forMeter("meter1")) + .hasName("1invalid-name") + .hasLongSumSatisfying( + sum -> sum.hasPointsSatisfying(point -> point.hasValue(10)))); + + assertThat(metricStorageRegistryLogs.getEvents()).hasSize(0); + assertThat(viewRegistryLogs.getEvents()).hasSize(0); + } + + @Test + @SuppressLogger(SdkMeter.class) + void instrumentWithInvalidName() { + // When an instrument is initialized with an invalid name, a noop instrument is returned + // and a warning is logged. No metric data is produced. + SdkMeterProvider meterProvider = builder.build(); + + meterProvider.get("meter1").counterBuilder("1invalid-name").build().add(10); + + assertThat(reader.collectAllMetrics()).isEmpty(); + assertThat(sdkMeterLogs.getEvents()) + .allSatisfy( + logEvent -> + assertThat(logEvent.getMessage()) + .contains("Instrument name \"1invalid-name\" is invalid")) + .hasSize(1); + } + private static InstrumentationScopeInfo forMeter(String meterName) { return InstrumentationScopeInfo.create(meterName); } From 964ddab9c92a49736fd21844f21a6be5094f637a Mon Sep 17 00:00:00 2001 From: Jack Berg <34418638+jack-berg@users.noreply.github.com> Date: Tue, 19 May 2026 14:10:40 -0500 Subject: [PATCH 2/3] Add assertions --- .../java/io/opentelemetry/sdk/metrics/IdentityTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java index 7be2bd1c210..cf230236915 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/IdentityTest.java @@ -8,6 +8,7 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import io.github.netmikey.logunit.api.LogCapturer; +import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.internal.state.MetricStorageRegistry; @@ -1106,8 +1107,10 @@ void viewNameNotValidated() { View.builder().setName("1invalid-name").build()) .build(); - meterProvider.get("meter1").counterBuilder("counter1").build().add(10); + LongCounter counter = meterProvider.get("meter1").counterBuilder("counter1").build(); + counter.add(10); + assertThat(counter.isEnabled()).isTrue(); assertThat(reader.collectAllMetrics()) .satisfiesExactlyInAnyOrder( metricData -> @@ -1128,8 +1131,10 @@ void instrumentWithInvalidName() { // and a warning is logged. No metric data is produced. SdkMeterProvider meterProvider = builder.build(); - meterProvider.get("meter1").counterBuilder("1invalid-name").build().add(10); + LongCounter counter = meterProvider.get("meter1").counterBuilder("1invalid-name").build(); + counter.add(10); + assertThat(counter.isEnabled()).isFalse(); assertThat(reader.collectAllMetrics()).isEmpty(); assertThat(sdkMeterLogs.getEvents()) .allSatisfy( From 613896f2d862835cc6d5f918e706c93ff9950888 Mon Sep 17 00:00:00 2001 From: Jack Berg <34418638+jack-berg@users.noreply.github.com> Date: Tue, 19 May 2026 15:12:03 -0500 Subject: [PATCH 3/3] Fix build --- exporters/otlp/all/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/otlp/all/build.gradle.kts b/exporters/otlp/all/build.gradle.kts index 0588e0fddd8..62fee8cfc87 100644 --- a/exporters/otlp/all/build.gradle.kts +++ b/exporters/otlp/all/build.gradle.kts @@ -10,8 +10,8 @@ apply() description = "OpenTelemetry Protocol (OTLP) Exporters" otelJava.moduleName.set("io.opentelemetry.exporter.otlp") otelJava.osgiOptionalPackages.set(listOf("io.opentelemetry.api.incubator.config")) -// io.grpc is not an OSGi bundle and has no package versioning; must use unversioned optional. -otelJava.osgiUnversionedOptionalPackages.set(listOf("io.grpc")) +// io.grpc and org.jspecify.annotations are not OSGi bundles; must use unversioned optional. +otelJava.osgiUnversionedOptionalPackages.set(listOf("io.grpc", "org.jspecify.annotations")) base.archivesName.set("opentelemetry-exporter-otlp") dependencies {