From 99ffe61aa6c0c7bd82883989b8096539bf362c9a Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 6 Feb 2024 14:10:14 -0600 Subject: [PATCH 1/7] Prototype disabling scope across traces, metrics, and logs --- .../opentelemetry-sdk-common.txt | 17 ++- .../opentelemetry-sdk-logs.txt | 10 +- .../opentelemetry-sdk-metrics.txt | 10 +- .../opentelemetry-sdk-trace.txt | 10 +- .../io/opentelemetry/sdk/ScopeConfigTest.java | 140 ++++++++++++++++++ .../sdk/common/ScopeSelector.java | 96 ++++++++++++ .../sdk/common/ScopeSelectorBuilder.java | 47 ++++++ .../opentelemetry/sdk/internal/GlobUtil.java | 82 ++++++++++ .../sdk/internal/GlobUtilTest.java | 36 +++++ .../opentelemetry/sdk/logs/LoggerConfig.java | 29 ++++ .../sdk/logs/LoggerSharedState.java | 17 ++- .../io/opentelemetry/sdk/logs/SdkLogger.java | 8 + .../sdk/logs/SdkLoggerProvider.java | 8 +- .../sdk/logs/SdkLoggerProviderBuilder.java | 12 +- .../sdk/logs/LoggerConfigTest.java | 55 +++++++ .../sdk/logs/LoggerSharedStateTest.java | 7 +- .../opentelemetry/sdk/logs/SdkLoggerTest.java | 1 + .../sdk/metrics/MeterConfig.java | 29 ++++ .../opentelemetry/sdk/metrics/SdkMeter.java | 10 +- .../sdk/metrics/SdkMeterProvider.java | 8 +- .../sdk/metrics/SdkMeterProviderBuilder.java | 17 ++- .../state/MeterProviderSharedState.java | 32 +++- .../metrics/internal/view/ViewRegistry.java | 69 +-------- .../sdk/metrics/InstrumentBuilderTest.java | 7 +- .../sdk/metrics/MeterConfigTest.java | 76 ++++++++++ .../internal/view/ViewRegistryTest.java | 23 --- .../io/opentelemetry/sdk/trace/SdkTracer.java | 6 + .../sdk/trace/SdkTracerProvider.java | 14 +- .../sdk/trace/SdkTracerProviderBuilder.java | 17 ++- .../opentelemetry/sdk/trace/TracerConfig.java | 29 ++++ .../sdk/trace/TracerSharedState.java | 19 ++- .../sdk/trace/TracerConfigTest.java | 85 +++++++++++ 32 files changed, 914 insertions(+), 112 deletions(-) create mode 100644 sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/internal/GlobUtil.java create mode 100644 sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java create mode 100644 sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java create mode 100644 sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java create mode 100644 sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java create mode 100644 sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java create mode 100644 sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt index df26146497b..f9c05d4ab38 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt @@ -1,2 +1,17 @@ Comparing source compatibility of against -No changes. \ No newline at end of file ++++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.common.ScopeSelector (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder builder() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getScopeName() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getScopeVersion() + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) boolean matchesScope(io.opentelemetry.sdk.common.InstrumentationScopeInfo) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeSelector named(java.lang.String) + +++ NEW METHOD: PUBLIC(+) FINAL(+) java.lang.String toString() ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeSelector build() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder setScopeName(java.lang.String) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder setScopeVersion(java.lang.String) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt index df26146497b..c07df020398 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt @@ -1,2 +1,10 @@ Comparing source compatibility of against -No changes. \ No newline at end of file ++++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.logs.LoggerConfig (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig defaultConfig() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig disabled() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder addScopeConfig(io.opentelemetry.sdk.common.ScopeSelector, io.opentelemetry.sdk.logs.LoggerConfig) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt index df26146497b..2479717dc75 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt @@ -1,2 +1,10 @@ Comparing source compatibility of against -No changes. \ No newline at end of file ++++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.metrics.MeterConfig (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig defaultConfig() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig disabled() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder addScopeConfig(io.opentelemetry.sdk.common.ScopeSelector, io.opentelemetry.sdk.metrics.MeterConfig) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt index df26146497b..9a9b3e8f4a6 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt @@ -1,2 +1,10 @@ Comparing source compatibility of against -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProviderBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder addScopeConfig(io.opentelemetry.sdk.common.ScopeSelector, io.opentelemetry.sdk.trace.TracerConfig) ++++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.trace.TracerConfig (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig defaultConfig() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig disabled() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java new file mode 100644 index 00000000000..1db354191e4 --- /dev/null +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java @@ -0,0 +1,140 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk; + +import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.logs.LoggerConfig; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; +import io.opentelemetry.sdk.metrics.MeterConfig; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.TracerConfig; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class ScopeConfigTest { + + /** + * Emit spans, metrics and logs in a hierarchy of 3 scopes: scopeA -> scopeB -> scopeC. Exercise + * the scope config which is common across all signals and verify telemetry is as expected. + */ + @Test + void disableScopeAllSignals() { + InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); + InMemoryMetricReader metricReader = InMemoryMetricReader.create(); + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + OpenTelemetrySdk sdk = + OpenTelemetrySdk.builder() + .setTracerProvider( + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .addScopeConfig(named("scopeB"), TracerConfig.disabled()) + .build()) + .setMeterProvider( + SdkMeterProvider.builder() + .registerMetricReader(metricReader) + .addScopeConfig(named("scopeB"), MeterConfig.disabled()) + .build()) + .setLoggerProvider( + SdkLoggerProvider.builder() + .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) + .addScopeConfig(named("scopeB"), LoggerConfig.disabled()) + .build()) + .build(); + + // Start scopeA + Tracer scopeATracer = sdk.getTracer("scopeA"); + Meter scopeAMeter = sdk.getMeter("scopeA"); + Logger scopeALogger = sdk.getSdkLoggerProvider().get("scopeA"); + Span spanA = scopeATracer.spanBuilder("spanA").startSpan(); + try (Scope spanAScope = spanA.makeCurrent()) { + scopeALogger.logRecordBuilder().setBody("scopeA log message").emit(); + + // Start scopeB + Tracer scopeBTracer = sdk.getTracer("scopeB"); + Meter scopeBMeter = sdk.getMeter("scopeB"); + Logger scopeBLogger = sdk.getSdkLoggerProvider().get("scopeB"); + Span spanB = scopeBTracer.spanBuilder("spanB").startSpan(); + try (Scope spanBScope = spanB.makeCurrent()) { + scopeBLogger.logRecordBuilder().setBody("scopeB log message").emit(); + + // Start scopeC + Tracer scopeCTracer = sdk.getTracer("scopeC"); + Meter scopeCMeter = sdk.getMeter("scopeC"); + Logger scopeCLogger = sdk.getSdkLoggerProvider().get("scopeC"); + Span spanC = scopeCTracer.spanBuilder("spanC").startSpan(); + try (Scope spanCScope = spanB.makeCurrent()) { + scopeCLogger.logRecordBuilder().setBody("scopeC log message").emit(); + } finally { + spanC.end(); + scopeCMeter.counterBuilder("scopeCCounter").build().add(1); + } + // End scopeC + + } finally { + spanB.end(); + scopeBMeter.counterBuilder("scopeBCounter").build().add(1); + } + // End scopeB + + } finally { + spanA.end(); + scopeAMeter.counterBuilder("scopeACounter").build().add(1); + } + // End scopeA + + // Collect all the telemetry. Ensure we don't see any from scopeB, and that the telemetry from + // scopeA and scopeC is valid. + assertThat(spanExporter.getFinishedSpanItems()) + .satisfies( + spans -> { + Map> spansByScope = + spans.stream() + .collect(Collectors.groupingBy(SpanData::getInstrumentationScopeInfo)); + assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1); + assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull(); + assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); + }); + assertThat(metricReader.collectAllMetrics()) + .satisfies( + metrics -> { + Map> metricsByScope = + metrics.stream() + .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull(); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); + }); + assertThat(logRecordExporter.getFinishedLogRecordItems()) + .satisfies( + logs -> { + Map> logsByScope = + logs.stream() + .collect(Collectors.groupingBy(LogRecordData::getInstrumentationScopeInfo)); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull(); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); + }); + } +} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java new file mode 100644 index 00000000000..9f4a3bfa9f0 --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java @@ -0,0 +1,96 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.common; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.sdk.internal.GlobUtil; +import java.util.Objects; +import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@AutoValue +@Immutable +public abstract class ScopeSelector { + + private final AtomicReference> selectorPredicate = + new AtomicReference<>(); + + /** Returns a new {@link ScopeSelectorBuilder} for {@link ScopeSelector}. */ + public static ScopeSelectorBuilder builder() { + return new ScopeSelectorBuilder(); + } + + /** + * Returns a {@link ScopeSelector} selecting scopes with the {@code scopeName}. + * + *

Scope name may contain the wildcard characters {@code *} and {@code ?} with the following + * matching criteria: + * + *

    + *
  • {@code *} matches 0 or more instances of any character + *
  • {@code ?} matches exactly one instance of any character + *
+ */ + public static ScopeSelector named(String scopeName) { + return builder().setScopeName(scopeName).build(); + } + + static ScopeSelector create(String scopeName, @Nullable String scopeVersion) { + ScopeSelector selector = new AutoValue_ScopeSelector(scopeName, scopeVersion); + // Compute and cache the predicate because we need to check if a scope matches any registered + // scope selector whenever a scope is created + selector.selectorPredicate.set(matchesScopePredicate(selector)); + return selector; + } + + ScopeSelector() {} + + /** Determine if the {@code scopeInfo} matches the criteria of this {@link ScopeSelector}. */ + public boolean matchesScope(InstrumentationScopeInfo scopeInfo) { + return Objects.requireNonNull(selectorPredicate.get()).test(scopeInfo); + } + + private static Predicate matchesScopePredicate( + ScopeSelector scopeSelector) { + Predicate scopeNamePredicate = + GlobUtil.toGlobPatternPredicate(scopeSelector.getScopeName()); + return scopeInfo -> { + String scopeVersionCriteria = scopeSelector.getScopeVersion(); + return scopeNamePredicate.test(scopeInfo.getName()) + && (scopeVersionCriteria == null || scopeVersionCriteria.equals(scopeInfo.getVersion())); + }; + } + + /** + * Returns the selected scope name. + * + *

Scope name may contain the wildcard characters {@code *} and {@code ?} with the following + * matching criteria: + * + *

    + *
  • {@code *} matches 0 or more instances of any character + *
  • {@code ?} matches exactly one instance of any character + *
+ */ + public abstract String getScopeName(); + + /** Returns the selected scope version, or null of this selects all scope versions. */ + @Nullable + public abstract String getScopeVersion(); + + @Override + public final String toString() { + StringJoiner joiner = new StringJoiner(", ", "ScopeSelector{", "}"); + joiner.add("scopeName=" + getScopeName()); + if (getScopeVersion() != null) { + joiner.add("scopeVersion=" + getScopeVersion()); + } + return joiner.toString(); + } +} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java new file mode 100644 index 00000000000..e49cfa58d87 --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.common; + +import static java.util.Objects.requireNonNull; + +import javax.annotation.Nullable; + +/** Builder for {@link ScopeSelector}. */ +public final class ScopeSelectorBuilder { + + private String scopeName = "*"; + @Nullable private String scopeVersion; + + ScopeSelectorBuilder() {} + + /** + * Select scopes with the given {@code scopeName}. + * + *

Scope name may contain the wildcard characters {@code *} and {@code ?} with the following + * matching criteria: + * + *

    + *
  • {@code *} matches 0 or more instances of any character + *
  • {@code ?} matches exactly one instance of any character + *
+ */ + public ScopeSelectorBuilder setScopeName(String scopeName) { + requireNonNull(scopeName, "scopeName"); + this.scopeName = scopeName; + return this; + } + + public ScopeSelectorBuilder setScopeVersion(String scopeVersion) { + requireNonNull(scopeVersion, "scopeVersion"); + this.scopeVersion = scopeVersion; + return this; + } + + /** Returns an {@link ScopeSelector} with the configuration of this builder. */ + public ScopeSelector build() { + return ScopeSelector.create(scopeName, scopeVersion); + } +} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/internal/GlobUtil.java b/sdk/common/src/main/java/io/opentelemetry/sdk/internal/GlobUtil.java new file mode 100644 index 00000000000..9c914055d7d --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/internal/GlobUtil.java @@ -0,0 +1,82 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.internal; + +import java.util.function.Predicate; +import java.util.regex.Pattern; + +/** + * Utilities for glob pattern matching. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class GlobUtil { + + private GlobUtil() {} + + /** + * Return a predicate that returns {@code true} if a string matches the {@code globPattern}. + * + *

{@code globPattern} may contain the wildcard characters {@code *} and {@code ?} with the + * following matching criteria: + * + *

    + *
  • {@code *} matches 0 or more instances of any character + *
  • {@code ?} matches exactly one instance of any character + *
+ */ + public static Predicate toGlobPatternPredicate(String globPattern) { + // Match all + if (globPattern.equals("*")) { + return unused -> true; + } + + // If globPattern contains '*' or '?', convert it to a regex and return corresponding predicate + for (int i = 0; i < globPattern.length(); i++) { + char c = globPattern.charAt(i); + if (c == '*' || c == '?') { + Pattern pattern = toRegexPattern(globPattern); + return string -> pattern.matcher(string).matches(); + } + } + + // Exact match, ignoring case + return globPattern::equalsIgnoreCase; + } + + /** + * Transform the {@code globPattern} to a regex by converting {@code *} to {@code .*}, {@code ?} + * to {@code .}, and escaping other regex special characters. + */ + private static Pattern toRegexPattern(String globPattern) { + int tokenStart = -1; + StringBuilder patternBuilder = new StringBuilder(); + for (int i = 0; i < globPattern.length(); i++) { + char c = globPattern.charAt(i); + if (c == '*' || c == '?') { + if (tokenStart != -1) { + patternBuilder.append(Pattern.quote(globPattern.substring(tokenStart, i))); + tokenStart = -1; + } + if (c == '*') { + patternBuilder.append(".*"); + } else { + // c == '?' + patternBuilder.append("."); + } + } else { + if (tokenStart == -1) { + tokenStart = i; + } + } + } + if (tokenStart != -1) { + patternBuilder.append(Pattern.quote(globPattern.substring(tokenStart))); + } + return Pattern.compile(patternBuilder.toString()); + } +} diff --git a/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java b/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java new file mode 100644 index 00000000000..dca7860921c --- /dev/null +++ b/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.internal; + +import static io.opentelemetry.sdk.internal.GlobUtil.toGlobPatternPredicate; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class GlobUtilTest { + + @Test + void matchesName() { + assertThat(toGlobPatternPredicate("foo").test("foo")).isTrue(); + assertThat(toGlobPatternPredicate("foo").test("Foo")).isTrue(); + assertThat(toGlobPatternPredicate("foo").test("bar")).isFalse(); + assertThat(toGlobPatternPredicate("fo?").test("foo")).isTrue(); + assertThat(toGlobPatternPredicate("fo??").test("fooo")).isTrue(); + assertThat(toGlobPatternPredicate("fo?").test("fob")).isTrue(); + assertThat(toGlobPatternPredicate("fo?").test("fooo")).isFalse(); + assertThat(toGlobPatternPredicate("*").test("foo")).isTrue(); + assertThat(toGlobPatternPredicate("*").test("bar")).isTrue(); + assertThat(toGlobPatternPredicate("*").test("baz")).isTrue(); + assertThat(toGlobPatternPredicate("*").test("foo.bar.baz")).isTrue(); + assertThat(toGlobPatternPredicate("fo*").test("fo")).isTrue(); + assertThat(toGlobPatternPredicate("fo*").test("foo")).isTrue(); + assertThat(toGlobPatternPredicate("fo*").test("fooo")).isTrue(); + assertThat(toGlobPatternPredicate("fo*").test("foo.bar.baz")).isTrue(); + assertThat(toGlobPatternPredicate("f()[]$^.{}|").test("f()[]$^.{}|")).isTrue(); + assertThat(toGlobPatternPredicate("f()[]$^.{}|?").test("f()[]$^.{}|o")).isTrue(); + assertThat(toGlobPatternPredicate("f()[]$^.{}|*").test("f()[]$^.{}|ooo")).isTrue(); + } +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java new file mode 100644 index 00000000000..b84dfeab93d --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import com.google.auto.value.AutoValue; +import javax.annotation.concurrent.Immutable; + +@AutoValue +@Immutable +public abstract class LoggerConfig { + + private static final LoggerConfig DEFAULT_CONFIG = new AutoValue_LoggerConfig(true); + + public static LoggerConfig disabled() { + return new AutoValue_LoggerConfig(false); + } + + public static LoggerConfig defaultConfig() { + return DEFAULT_CONFIG; + } + + LoggerConfig() {} + + /** Returns {@code true} if this logger is enabled. Defaults to {@code true}. */ + public abstract boolean isEnabled(); +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java index 768871e1e57..ddb00cf7de4 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java @@ -7,7 +7,10 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.resources.Resource; +import java.util.LinkedHashMap; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -21,17 +24,20 @@ final class LoggerSharedState { private final Supplier logLimitsSupplier; private final LogRecordProcessor logRecordProcessor; private final Clock clock; + private final LinkedHashMap loggerConfigMap; @Nullable private volatile CompletableResultCode shutdownResult = null; LoggerSharedState( Resource resource, Supplier logLimitsSupplier, LogRecordProcessor logRecordProcessor, - Clock clock) { + Clock clock, + LinkedHashMap loggerConfigMap) { this.resource = resource; this.logLimitsSupplier = logLimitsSupplier; this.logRecordProcessor = logRecordProcessor; this.clock = clock; + this.loggerConfigMap = loggerConfigMap; } Resource getResource() { @@ -50,6 +56,15 @@ Clock getClock() { return clock; } + LoggerConfig getLoggerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { + for (ScopeSelector scopeSelector : loggerConfigMap.keySet()) { + if (scopeSelector.matchesScope(instrumentationScopeInfo)) { + return loggerConfigMap.get(scopeSelector); + } + } + return LoggerConfig.defaultConfig(); + } + boolean hasBeenShutdown() { return shutdownResult != null; } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index efcb7882ade..2aa9c35feb4 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -7,22 +7,30 @@ import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; /** SDK implementation of {@link Logger}. */ final class SdkLogger implements Logger { + private static final Logger NOOP_LOGGER = LoggerProvider.noop().get("noop"); + private final LoggerSharedState loggerSharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; + private final LoggerConfig loggerConfig; SdkLogger( LoggerSharedState loggerSharedState, InstrumentationScopeInfo instrumentationScopeInfo) { this.loggerSharedState = loggerSharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; + this.loggerConfig = loggerSharedState.getLoggerConfig(instrumentationScopeInfo); } @Override public LogRecordBuilder logRecordBuilder() { + if (!loggerConfig.isEnabled()) { + return NOOP_LOGGER.logRecordBuilder(); + } return new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java index 9b9b2e1a97d..af1a40e26f5 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java @@ -11,9 +11,11 @@ import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; import java.io.Closeable; +import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -48,10 +50,12 @@ public static SdkLoggerProviderBuilder builder() { Resource resource, Supplier logLimitsSupplier, List processors, - Clock clock) { + Clock clock, + LinkedHashMap loggerConfigMap) { LogRecordProcessor logRecordProcessor = LogRecordProcessor.composite(processors); this.sharedState = - new LoggerSharedState(resource, logLimitsSupplier, logRecordProcessor, clock); + new LoggerSharedState( + resource, logLimitsSupplier, logRecordProcessor, clock, loggerConfigMap); this.loggerComponentRegistry = new ComponentRegistry<>( instrumentationScopeInfo -> new SdkLogger(sharedState, instrumentationScopeInfo)); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java index 8d7004eeabd..b5514e5b6eb 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java @@ -11,9 +11,11 @@ import io.opentelemetry.api.logs.Logger; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; import java.util.function.Supplier; @@ -29,6 +31,7 @@ public final class SdkLoggerProviderBuilder { private Resource resource = Resource.getDefault(); private Supplier logLimitsSupplier = LogLimits::getDefault; private Clock clock = Clock.getDefault(); + private final LinkedHashMap loggerConfigMap = new LinkedHashMap<>(); SdkLoggerProviderBuilder() {} @@ -100,12 +103,19 @@ public SdkLoggerProviderBuilder setClock(Clock clock) { return this; } + public SdkLoggerProviderBuilder addScopeConfig( + ScopeSelector scopeSelector, LoggerConfig loggerConfig) { + loggerConfigMap.put(scopeSelector, loggerConfig); + return this; + } + /** * Create a {@link SdkLoggerProvider} instance. * * @return an instance configured with the provided options */ public SdkLoggerProvider build() { - return new SdkLoggerProvider(resource, logLimitsSupplier, logRecordProcessors, clock); + return new SdkLoggerProvider( + resource, logLimitsSupplier, logRecordProcessors, clock, loggerConfigMap); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java new file mode 100644 index 00000000000..a53e2a9604e --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static io.opentelemetry.sdk.logs.LoggerConfig.disabled; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class LoggerConfigTest { + + @Test + void disableScopes() { + InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); + SdkLoggerProvider loggerProvider = + SdkLoggerProvider.builder() + // Disable loggerB. Since loggers are enabled by default, loggerA and loggerC are + // enabled. + .addScopeConfig(named("loggerB"), disabled()) + .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) + .build(); + + Logger loggerA = loggerProvider.get("loggerA"); + Logger loggerB = loggerProvider.get("loggerB"); + Logger loggerC = loggerProvider.get("loggerC"); + + loggerA.logRecordBuilder().setBody("messageA").emit(); + loggerB.logRecordBuilder().setBody("messageB").emit(); + loggerC.logRecordBuilder().setBody("messageC").emit(); + + // Only logs from loggerA and loggerC should be seen + assertThat(exporter.getFinishedLogRecordItems()) + .satisfies( + metrics -> { + Map> logsByScope = + metrics.stream() + .collect(Collectors.groupingBy(LogRecordData::getInstrumentationScopeInfo)); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerA"))).hasSize(1); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerB"))).isNull(); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerC"))).hasSize(1); + }); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java index 29a3a846a56..e1477735ea8 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java @@ -13,6 +13,7 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.resources.Resource; +import java.util.LinkedHashMap; import org.junit.jupiter.api.Test; class LoggerSharedStateTest { @@ -24,7 +25,11 @@ void shutdown() { when(logRecordProcessor.shutdown()).thenReturn(code); LoggerSharedState state = new LoggerSharedState( - Resource.empty(), LogLimits::getDefault, logRecordProcessor, Clock.getDefault()); + Resource.empty(), + LogLimits::getDefault, + logRecordProcessor, + Clock.getDefault(), + new LinkedHashMap<>()); state.shutdown(); state.shutdown(); verify(logRecordProcessor, times(1)).shutdown(); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index f8246dfc0a9..b290de37c54 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -43,6 +43,7 @@ void logRecordBuilder() { when(state.getResource()).thenReturn(Resource.getDefault()); when(state.getLogRecordProcessor()).thenReturn(logRecordProcessor); when(state.getClock()).thenReturn(clock); + when(state.getLoggerConfig(any())).thenReturn(LoggerConfig.defaultConfig()); SdkLogger logger = new SdkLogger(state, info); LogRecordBuilder logRecordBuilder = logger.logRecordBuilder(); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java new file mode 100644 index 00000000000..5a932525a61 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics; + +import com.google.auto.value.AutoValue; +import javax.annotation.concurrent.Immutable; + +@AutoValue +@Immutable +public abstract class MeterConfig { + + private static final MeterConfig DEFAULT_CONFIG = new AutoValue_MeterConfig(true); + + public static MeterConfig disabled() { + return new AutoValue_MeterConfig(false); + } + + public static MeterConfig defaultConfig() { + return DEFAULT_CONFIG; + } + + MeterConfig() {} + + /** Returns {@code true} if this meter is enabled. Defaults to {@code true}. */ + public abstract boolean isEnabled(); +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java index 02eb45a26ff..d88139a032d 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java @@ -55,6 +55,7 @@ final class SdkMeter implements Meter { private final InstrumentationScopeInfo instrumentationScopeInfo; private final MeterProviderSharedState meterProviderSharedState; private final MeterSharedState meterSharedState; + private final MeterConfig meterConfig; SdkMeter( MeterProviderSharedState meterProviderSharedState, @@ -63,6 +64,7 @@ final class SdkMeter implements Meter { this.instrumentationScopeInfo = instrumentationScopeInfo; this.meterProviderSharedState = meterProviderSharedState; this.meterSharedState = MeterSharedState.create(instrumentationScopeInfo, registeredReaders); + this.meterConfig = meterProviderSharedState.getMeterConfig(instrumentationScopeInfo); } // Visible for testing @@ -82,7 +84,7 @@ void resetForTest() { @Override public LongCounterBuilder counterBuilder(String name) { - return !checkValidInstrumentName(name) + return !meterConfig.isEnabled() || !checkValidInstrumentName(name) ? NOOP_METER.counterBuilder(NOOP_INSTRUMENT_NAME) : new SdkLongCounter.SdkLongCounterBuilder( meterProviderSharedState, meterSharedState, name); @@ -90,7 +92,7 @@ public LongCounterBuilder counterBuilder(String name) { @Override public LongUpDownCounterBuilder upDownCounterBuilder(String name) { - return !checkValidInstrumentName(name) + return !meterConfig.isEnabled() || !checkValidInstrumentName(name) ? NOOP_METER.upDownCounterBuilder(NOOP_INSTRUMENT_NAME) : new SdkLongUpDownCounter.SdkLongUpDownCounterBuilder( meterProviderSharedState, meterSharedState, name); @@ -98,7 +100,7 @@ public LongUpDownCounterBuilder upDownCounterBuilder(String name) { @Override public DoubleHistogramBuilder histogramBuilder(String name) { - return !checkValidInstrumentName(name) + return !meterConfig.isEnabled() || !checkValidInstrumentName(name) ? NOOP_METER.histogramBuilder(NOOP_INSTRUMENT_NAME) : new SdkDoubleHistogram.SdkDoubleHistogramBuilder( meterProviderSharedState, meterSharedState, name); @@ -106,7 +108,7 @@ public DoubleHistogramBuilder histogramBuilder(String name) { @Override public DoubleGaugeBuilder gaugeBuilder(String name) { - return !checkValidInstrumentName(name) + return !meterConfig.isEnabled() || !checkValidInstrumentName(name) ? NOOP_METER.gaugeBuilder(NOOP_INSTRUMENT_NAME) : new SdkDoubleGauge.SdkDoubleGaugeBuilder( meterProviderSharedState, meterSharedState, name); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index 63b241bc5b1..1a5fa191766 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.CollectionRegistration; @@ -29,6 +30,7 @@ import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -62,7 +64,8 @@ public static SdkMeterProviderBuilder builder() { List metricProducers, Clock clock, Resource resource, - ExemplarFilter exemplarFilter) { + ExemplarFilter exemplarFilter, + LinkedHashMap meterConfigMap) { long startEpochNanos = clock.now(); this.registeredViews = registeredViews; this.registeredReaders = @@ -75,7 +78,8 @@ public static SdkMeterProviderBuilder builder() { .collect(toList()); this.metricProducers = metricProducers; this.sharedState = - MeterProviderSharedState.create(clock, resource, exemplarFilter, startEpochNanos); + MeterProviderSharedState.create( + clock, resource, exemplarFilter, startEpochNanos, meterConfigMap); this.registry = new ComponentRegistry<>( instrumentationLibraryInfo -> diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index 3e444f10f93..288a6eaf6a3 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -6,6 +6,7 @@ package io.opentelemetry.sdk.metrics; import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.metrics.export.MetricProducer; import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; @@ -16,6 +17,7 @@ import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; @@ -40,6 +42,7 @@ public final class SdkMeterProviderBuilder { private final List metricProducers = new ArrayList<>(); private final List registeredViews = new ArrayList<>(); private ExemplarFilter exemplarFilter = DEFAULT_EXEMPLAR_FILTER; + private final LinkedHashMap meterConfigMap = new LinkedHashMap<>(); SdkMeterProviderBuilder() {} @@ -150,9 +153,21 @@ public SdkMeterProviderBuilder registerMetricProducer(MetricProducer metricProdu return this; } + public SdkMeterProviderBuilder addScopeConfig( + ScopeSelector scopeSelector, MeterConfig meterConfig) { + meterConfigMap.put(scopeSelector, meterConfig); + return this; + } + /** Returns an {@link SdkMeterProvider} built with the configuration of this builder. */ public SdkMeterProvider build() { return new SdkMeterProvider( - registeredViews, metricReaders, metricProducers, clock, resource, exemplarFilter); + registeredViews, + metricReaders, + metricProducers, + clock, + resource, + exemplarFilter, + meterConfigMap); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java index 9b185b36a84..d2b9fc0e66a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java @@ -7,9 +7,15 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.metrics.MeterConfig; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.resources.Resource; +import java.util.LinkedHashMap; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import javax.annotation.concurrent.Immutable; /** @@ -21,9 +27,20 @@ @AutoValue @Immutable public abstract class MeterProviderSharedState { + + private AtomicReference> meterConfigMapRef = + new AtomicReference<>(); + public static MeterProviderSharedState create( - Clock clock, Resource resource, ExemplarFilter exemplarFilter, long startEpochNanos) { - return new AutoValue_MeterProviderSharedState(clock, resource, startEpochNanos, exemplarFilter); + Clock clock, + Resource resource, + ExemplarFilter exemplarFilter, + long startEpochNanos, + LinkedHashMap meterConfigMap) { + MeterProviderSharedState sharedState = + new AutoValue_MeterProviderSharedState(clock, resource, startEpochNanos, exemplarFilter); + sharedState.meterConfigMapRef.set(meterConfigMap); + return sharedState; } MeterProviderSharedState() {} @@ -39,4 +56,15 @@ public static MeterProviderSharedState create( /** Returns the {@link ExemplarFilter} for remembering synchronous measurements. */ abstract ExemplarFilter getExemplarFilter(); + + public MeterConfig getMeterConfig(InstrumentationScopeInfo instrumentationScopeInfo) { + LinkedHashMap meterConfigMap = + Objects.requireNonNull(meterConfigMapRef.get()); + for (ScopeSelector scopeSelector : meterConfigMap.keySet()) { + if (scopeSelector.matchesScope(instrumentationScopeInfo)) { + return meterConfigMap.get(scopeSelector); + } + } + return MeterConfig.defaultConfig(); + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java index 9e5bba37233..4df9f1a35ec 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java @@ -9,6 +9,7 @@ import static java.util.Objects.requireNonNull; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.internal.GlobUtil; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentSelector; import io.opentelemetry.sdk.metrics.InstrumentType; @@ -27,10 +28,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.regex.Pattern; import javax.annotation.concurrent.Immutable; /** @@ -170,7 +169,8 @@ private static boolean matchesSelector( return false; } if (selector.getInstrumentName() != null - && !toGlobPatternPredicate(selector.getInstrumentName()).test(descriptor.getName())) { + && !GlobUtil.toGlobPatternPredicate(selector.getInstrumentName()) + .test(descriptor.getName())) { return false; } return matchesMeter(selector, meterScope); @@ -190,69 +190,6 @@ private static boolean matchesMeter( || selector.getMeterSchemaUrl().equals(meterScope.getSchemaUrl()); } - /** - * Return a predicate that returns {@code true} if a string matches the {@code globPattern}. - * - *

{@code globPattern} may contain the wildcard characters {@code *} and {@code ?} with the - * following matching criteria: - * - *

    - *
  • {@code *} matches 0 or more instances of any character - *
  • {@code ?} matches exactly one instance of any character - *
- */ - // Visible for testing - static Predicate toGlobPatternPredicate(String globPattern) { - // Match all - if (globPattern.equals("*")) { - return unused -> true; - } - - // If globPattern contains '*' or '?', convert it to a regex and return corresponding predicate - for (int i = 0; i < globPattern.length(); i++) { - char c = globPattern.charAt(i); - if (c == '*' || c == '?') { - Pattern pattern = toRegexPattern(globPattern); - return string -> pattern.matcher(string).matches(); - } - } - - // Exact match, ignoring case - return globPattern::equalsIgnoreCase; - } - - /** - * Transform the {@code globPattern} to a regex by converting {@code *} to {@code .*}, {@code ?} - * to {@code .}, and escaping other regex special characters. - */ - private static Pattern toRegexPattern(String globPattern) { - int tokenStart = -1; - StringBuilder patternBuilder = new StringBuilder(); - for (int i = 0; i < globPattern.length(); i++) { - char c = globPattern.charAt(i); - if (c == '*' || c == '?') { - if (tokenStart != -1) { - patternBuilder.append(Pattern.quote(globPattern.substring(tokenStart, i))); - tokenStart = -1; - } - if (c == '*') { - patternBuilder.append(".*"); - } else { - // c == '?' - patternBuilder.append("."); - } - } else { - if (tokenStart == -1) { - tokenStart = i; - } - } - } - if (tokenStart != -1) { - patternBuilder.append(Pattern.quote(globPattern.substring(tokenStart))); - } - return Pattern.compile(patternBuilder.toString()); - } - private static RegisteredView applyAdviceToDefaultView( RegisteredView instrumentDefaultView, Advice advice) { return RegisteredView.create( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java index a351c95d0e6..75d9486f852 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java @@ -15,13 +15,18 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.time.TestClock; import java.util.Collections; +import java.util.LinkedHashMap; import org.junit.jupiter.api.Test; class InstrumentBuilderTest { public static final MeterProviderSharedState PROVIDER_SHARED_STATE = MeterProviderSharedState.create( - TestClock.create(), Resource.getDefault(), ExemplarFilter.alwaysOff(), 0); + TestClock.create(), + Resource.getDefault(), + ExemplarFilter.alwaysOff(), + 0, + new LinkedHashMap<>()); static final InstrumentationScopeInfo SCOPE = InstrumentationScopeInfo.create("scope-name"); public static final MeterSharedState METER_SHARED_STATE = MeterSharedState.create(SCOPE, Collections.emptyList()); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java new file mode 100644 index 00000000000..da4dfb4bb74 --- /dev/null +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics; + +import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static io.opentelemetry.sdk.metrics.MeterConfig.disabled; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class MeterConfigTest { + + @Test + void disableScopes() { + InMemoryMetricReader reader = InMemoryMetricReader.create(); + SdkMeterProvider meterProvider = + SdkMeterProvider.builder() + // Disable meterB. Since meters are enabled by default, meterA and meterC are enabled. + .addScopeConfig(named("meterB"), disabled()) + .registerMetricReader(reader) + .build(); + + Meter meterA = meterProvider.get("meterA"); + Meter meterB = meterProvider.get("meterB"); + Meter meterC = meterProvider.get("meterC"); + + meterA.counterBuilder("counterA").build().add(1); + meterA.counterBuilder("asyncCounterA").buildWithCallback(observable -> observable.record(1)); + meterA.upDownCounterBuilder("upDownCounterA").build().add(1); + meterA + .upDownCounterBuilder("asyncUpDownCounterA") + .buildWithCallback(observable -> observable.record(1)); + meterA.histogramBuilder("histogramA").build().record(1.0); + meterA.gaugeBuilder("gaugeA").buildWithCallback(observable -> observable.record(1.0)); + + meterB.counterBuilder("counterB").build().add(1); + meterB.counterBuilder("asyncCounterB").buildWithCallback(observable -> observable.record(1)); + meterB.upDownCounterBuilder("upDownCounterB").build().add(1); + meterB + .upDownCounterBuilder("asyncUpDownCounterB") + .buildWithCallback(observable -> observable.record(1)); + meterB.histogramBuilder("histogramB").build().record(1.0); + meterB.gaugeBuilder("gaugeB").buildWithCallback(observable -> observable.record(1.0)); + + meterC.counterBuilder("counterC").build().add(1); + meterC.counterBuilder("asyncCounterC").buildWithCallback(observable -> observable.record(1)); + meterC.upDownCounterBuilder("upDownCounterC").build().add(1); + meterC + .upDownCounterBuilder("asyncUpDownCounterC") + .buildWithCallback(observable -> observable.record(1)); + meterC.histogramBuilder("histogramC").build().record(1.0); + meterC.gaugeBuilder("gaugeC").buildWithCallback(observable -> observable.record(1.0)); + + // Only metrics from meterA and meterC should be seen + assertThat(reader.collectAllMetrics()) + .satisfies( + metrics -> { + Map> metricsByScope = + metrics.stream() + .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterA"))).hasSize(6); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterB"))).isNull(); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterC"))).hasSize(6); + }); + } +} diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java index abba1c32133..d2f5925873c 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java @@ -7,7 +7,6 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; import static io.opentelemetry.sdk.metrics.internal.view.ViewRegistry.DEFAULT_REGISTERED_VIEW; -import static io.opentelemetry.sdk.metrics.internal.view.ViewRegistry.toGlobPatternPredicate; import static org.assertj.core.api.Assertions.assertThat; import io.github.netmikey.logunit.api.LogCapturer; @@ -544,26 +543,4 @@ void findViews_ApplyAdvice() { INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); } - - @Test - void matchesName() { - assertThat(toGlobPatternPredicate("foo").test("foo")).isTrue(); - assertThat(toGlobPatternPredicate("foo").test("Foo")).isTrue(); - assertThat(toGlobPatternPredicate("foo").test("bar")).isFalse(); - assertThat(toGlobPatternPredicate("fo?").test("foo")).isTrue(); - assertThat(toGlobPatternPredicate("fo??").test("fooo")).isTrue(); - assertThat(toGlobPatternPredicate("fo?").test("fob")).isTrue(); - assertThat(toGlobPatternPredicate("fo?").test("fooo")).isFalse(); - assertThat(toGlobPatternPredicate("*").test("foo")).isTrue(); - assertThat(toGlobPatternPredicate("*").test("bar")).isTrue(); - assertThat(toGlobPatternPredicate("*").test("baz")).isTrue(); - assertThat(toGlobPatternPredicate("*").test("foo.bar.baz")).isTrue(); - assertThat(toGlobPatternPredicate("fo*").test("fo")).isTrue(); - assertThat(toGlobPatternPredicate("fo*").test("foo")).isTrue(); - assertThat(toGlobPatternPredicate("fo*").test("fooo")).isTrue(); - assertThat(toGlobPatternPredicate("fo*").test("foo.bar.baz")).isTrue(); - assertThat(toGlobPatternPredicate("f()[]$^.{}|").test("f()[]$^.{}|")).isTrue(); - assertThat(toGlobPatternPredicate("f()[]$^.{}|?").test("f()[]$^.{}|o")).isTrue(); - assertThat(toGlobPatternPredicate("f()[]$^.{}|*").test("f()[]$^.{}|ooo")).isTrue(); - } } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java index 81282097cd1..c19350a88d1 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java @@ -13,17 +13,23 @@ /** {@link SdkTracer} is SDK implementation of {@link Tracer}. */ final class SdkTracer implements Tracer { static final String FALLBACK_SPAN_NAME = ""; + private static final Tracer NOOP_TRACER = TracerProvider.noop().get("noop"); private final TracerSharedState sharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; + private final TracerConfig tracerConfig; SdkTracer(TracerSharedState sharedState, InstrumentationScopeInfo instrumentationScopeInfo) { this.sharedState = sharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; + this.tracerConfig = sharedState.getTracerConfig(instrumentationScopeInfo); } @Override public SpanBuilder spanBuilder(String spanName) { + if (!tracerConfig.isEnabled()) { + return NOOP_TRACER.spanBuilder(spanName); + } if (spanName == null || spanName.trim().isEmpty()) { spanName = FALLBACK_SPAN_NAME; } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java index 2e07af579a9..def983f4a46 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java @@ -10,10 +10,12 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; +import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -37,16 +39,24 @@ public static SdkTracerProviderBuilder builder() { return new SdkTracerProviderBuilder(); } + @SuppressWarnings("NonApiType") SdkTracerProvider( Clock clock, IdGenerator idsGenerator, Resource resource, Supplier spanLimitsSupplier, Sampler sampler, - List spanProcessors) { + List spanProcessors, + LinkedHashMap tracerConfigMap) { this.sharedState = new TracerSharedState( - clock, idsGenerator, resource, spanLimitsSupplier, sampler, spanProcessors); + clock, + idsGenerator, + resource, + spanLimitsSupplier, + sampler, + spanProcessors, + tracerConfigMap); this.tracerSdkComponentRegistry = new ComponentRegistry<>( instrumentationScopeInfo -> new SdkTracer(sharedState, instrumentationScopeInfo)); diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java index 20dd76536d5..ac9d9fab7c9 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java @@ -8,9 +8,11 @@ import static java.util.Objects.requireNonNull; import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; import java.util.function.Supplier; @@ -26,6 +28,7 @@ public final class SdkTracerProviderBuilder { private Resource resource = Resource.getDefault(); private Supplier spanLimitsSupplier = SpanLimits::getDefault; private Sampler sampler = DEFAULT_SAMPLER; + private final LinkedHashMap tracerConfigMap = new LinkedHashMap<>(); /** * Assign a {@link Clock}. {@link Clock} will be used each time a {@link @@ -147,6 +150,12 @@ public SdkTracerProviderBuilder addSpanProcessor(SpanProcessor spanProcessor) { return this; } + public SdkTracerProviderBuilder addScopeConfig( + ScopeSelector scopeSelector, TracerConfig tracerConfig) { + tracerConfigMap.put(scopeSelector, tracerConfig); + return this; + } + /** * Create a new {@link SdkTracerProvider} instance with the configuration. * @@ -154,7 +163,13 @@ public SdkTracerProviderBuilder addSpanProcessor(SpanProcessor spanProcessor) { */ public SdkTracerProvider build() { return new SdkTracerProvider( - clock, idsGenerator, resource, spanLimitsSupplier, sampler, spanProcessors); + clock, + idsGenerator, + resource, + spanLimitsSupplier, + sampler, + spanProcessors, + tracerConfigMap); } SdkTracerProviderBuilder() {} diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java new file mode 100644 index 00000000000..367ee7b05a2 --- /dev/null +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.trace; + +import com.google.auto.value.AutoValue; +import javax.annotation.concurrent.Immutable; + +@AutoValue +@Immutable +public abstract class TracerConfig { + + private static final TracerConfig DEFAULT_CONFIG = new AutoValue_TracerConfig(true); + + public static TracerConfig disabled() { + return new AutoValue_TracerConfig(false); + } + + public static TracerConfig defaultConfig() { + return DEFAULT_CONFIG; + } + + TracerConfig() {} + + /** Returns {@code true} if this tracer is enabled. Defaults to {@code true}. */ + public abstract boolean isEnabled(); +} diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java index 99cd1ea26c0..c072bb9fa33 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java @@ -7,14 +7,18 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.util.LinkedHashMap; import java.util.List; import java.util.function.Supplier; import javax.annotation.Nullable; // Represents the shared state/config between all Tracers created by the same TracerProvider. final class TracerSharedState { + private final Object lock = new Object(); private final Clock clock; private final IdGenerator idGenerator; @@ -25,16 +29,19 @@ final class TracerSharedState { private final Supplier spanLimitsSupplier; private final Sampler sampler; private final SpanProcessor activeSpanProcessor; + private final LinkedHashMap tracerConfigMap; @Nullable private volatile CompletableResultCode shutdownResult = null; + @SuppressWarnings("NonApiType") TracerSharedState( Clock clock, IdGenerator idGenerator, Resource resource, Supplier spanLimitsSupplier, Sampler sampler, - List spanProcessors) { + List spanProcessors, + LinkedHashMap tracerConfigMap) { this.clock = clock; this.idGenerator = idGenerator; this.idGeneratorSafeToSkipIdValidation = idGenerator instanceof RandomIdGenerator; @@ -42,6 +49,7 @@ final class TracerSharedState { this.spanLimitsSupplier = spanLimitsSupplier; this.sampler = sampler; activeSpanProcessor = SpanProcessor.composite(spanProcessors); + this.tracerConfigMap = tracerConfigMap; } Clock getClock() { @@ -79,6 +87,15 @@ SpanProcessor getActiveSpanProcessor() { return activeSpanProcessor; } + TracerConfig getTracerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { + for (ScopeSelector scopeSelector : tracerConfigMap.keySet()) { + if (scopeSelector.matchesScope(instrumentationScopeInfo)) { + return tracerConfigMap.get(scopeSelector); + } + } + return TracerConfig.defaultConfig(); + } + /** * Returns {@code true} if tracing has been shut down. * diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java new file mode 100644 index 00000000000..e81b3a34dd3 --- /dev/null +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -0,0 +1,85 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.trace; + +import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.trace.TracerConfig.disabled; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanId; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import org.junit.jupiter.api.Test; + +class TracerConfigTest { + + @Test + void disableScopes() throws InterruptedException { + InMemorySpanExporter exporter = InMemorySpanExporter.create(); + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + // Disable tracerB. Since tracers are enabled by default, tracerA and tracerC are + // enabled. + .addScopeConfig(named("tracerB"), disabled()) + .addSpanProcessor(SimpleSpanProcessor.create(exporter)) + .build(); + + Tracer tracerA = tracerProvider.get("tracerA"); + Tracer tracerB = tracerProvider.get("tracerB"); + Tracer tracerC = tracerProvider.get("tracerC"); + + Span parent; + Span child; + Span grandchild; + + parent = tracerA.spanBuilder("parent").startSpan(); + try (Scope parentScope = parent.makeCurrent()) { + parent.setAttribute("a", "1"); + child = tracerB.spanBuilder("child").startSpan(); + // tracerB is disabled and should behave the same as noop tracer + assertThat(child.getSpanContext()).isEqualTo(parent.getSpanContext()); + assertThat(child.isRecording()).isFalse(); + try (Scope childScope = child.makeCurrent()) { + child.setAttribute("b", "1"); + grandchild = tracerC.spanBuilder("grandchild").startSpan(); + try (Scope grandchildScope = grandchild.makeCurrent()) { + grandchild.setAttribute("c", "1"); + Thread.sleep(100); + } finally { + grandchild.end(); + } + } finally { + child.end(); + } + } finally { + parent.end(); + } + + // Only contain tracerA:parent and tracerC:child should be seen + // tracerC:grandchild should list tracerA:parent as its parent + assertThat(exporter.getFinishedSpanItems()) + .satisfiesExactlyInAnyOrder( + spanData -> + assertThat(spanData) + .hasInstrumentationScopeInfo(InstrumentationScopeInfo.create("tracerA")) + .hasName("parent") + .hasSpanId(parent.getSpanContext().getSpanId()) + .hasParentSpanId(SpanId.getInvalid()) + .hasAttributes(Attributes.builder().put("a", "1").build()), + spanData -> + assertThat(spanData) + .hasInstrumentationScopeInfo(InstrumentationScopeInfo.create("tracerC")) + .hasName("grandchild") + .hasSpanId(grandchild.getSpanContext().getSpanId()) + .hasParentSpanId(parent.getSpanContext().getSpanId()) + .hasAttributes(Attributes.builder().put("c", "1").build())); + } +} From 6fb3a1f196bae8add14275f8a841d6a681d108fb Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 14 Feb 2024 15:37:00 -0600 Subject: [PATCH 2/7] Refactor scope config to use functional interface --- .../opentelemetry-exporter-zipkin.txt | 9 +- .../opentelemetry-sdk-common.txt | 21 +-- .../io/opentelemetry/sdk/ScopeConfigTest.java | 176 +++++++++++++----- .../opentelemetry/sdk/common/ScopeConfig.java | 61 ++++++ .../sdk/common/ScopeSelector.java | 96 ---------- .../sdk/common/ScopeSelectorBuilder.java | 47 ----- .../opentelemetry/sdk/logs/LoggerConfig.java | 9 +- .../sdk/logs/LoggerSharedState.java | 17 +- .../sdk/logs/SdkLoggerProvider.java | 8 +- .../sdk/logs/SdkLoggerProviderBuilder.java | 15 +- .../sdk/logs/LoggerConfigTest.java | 7 +- .../sdk/logs/LoggerSharedStateTest.java | 3 +- .../sdk/metrics/MeterConfig.java | 8 +- .../sdk/metrics/SdkMeterProvider.java | 8 +- .../sdk/metrics/SdkMeterProviderBuilder.java | 15 +- .../state/MeterProviderSharedState.java | 23 +-- .../sdk/trace/SdkTracerProvider.java | 8 +- .../sdk/trace/SdkTracerProviderBuilder.java | 15 +- .../opentelemetry/sdk/trace/TracerConfig.java | 9 +- .../sdk/trace/TracerSharedState.java | 17 +- .../sdk/trace/TracerConfigTest.java | 7 +- 21 files changed, 281 insertions(+), 298 deletions(-) create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java delete mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java delete mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-exporter-zipkin.txt b/docs/apidiffs/current_vs_latest/opentelemetry-exporter-zipkin.txt index b941adbcdd2..df26146497b 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-exporter-zipkin.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-exporter-zipkin.txt @@ -1,9 +1,2 @@ Comparing source compatibility of against -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - === UNCHANGED METHOD: PUBLIC io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder setEncoder(zipkin2.codec.BytesEncoder) - +++ NEW ANNOTATION: java.lang.Deprecated - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder setEncoder(zipkin2.reporter.BytesEncoder) - === UNCHANGED METHOD: PUBLIC io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder setSender(zipkin2.reporter.Sender) - +++ NEW ANNOTATION: java.lang.Deprecated - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder setSender(zipkin2.reporter.BytesMessageSender) +No changes. \ No newline at end of file diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt index f9c05d4ab38..e659ed1f6cd 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt @@ -1,17 +1,10 @@ Comparing source compatibility of against -+++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.common.ScopeSelector (not serializable) ++++* NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.ScopeConfig (not serializable) +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder builder() - +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getScopeName() - +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getScopeVersion() - +++ NEW ANNOTATION: javax.annotation.Nullable - +++ NEW METHOD: PUBLIC(+) boolean matchesScope(io.opentelemetry.sdk.common.InstrumentationScopeInfo) - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeSelector named(java.lang.String) - +++ NEW METHOD: PUBLIC(+) FINAL(+) java.lang.String toString() -+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder (not serializable) - +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. - +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeSelector build() - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder setScopeName(java.lang.String) - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeSelectorBuilder setScopeVersion(java.lang.String) + +++* NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Function applyToMatching(java.util.function.Predicate, java.lang.Object) + GENERIC TEMPLATES: +++ T:java.lang.Object + +++* NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Function applyToMatching(java.util.function.Predicate, java.lang.Object, java.lang.Object) + GENERIC TEMPLATES: +++ T:java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate scopeNameEquals(java.lang.String) + +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate scopeNameMatches(java.lang.String) diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java index 1db354191e4..24fe05f8a2d 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java @@ -5,9 +5,11 @@ package io.opentelemetry.sdk; -import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static io.opentelemetry.sdk.common.ScopeConfig.applyToMatching; +import static io.opentelemetry.sdk.common.ScopeConfig.scopeNameEquals; import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.trace.Span; @@ -35,74 +37,38 @@ class ScopeConfigTest { + private final InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); + private final InMemoryMetricReader metricReader = InMemoryMetricReader.create(); + private final InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + /** - * Emit spans, metrics and logs in a hierarchy of 3 scopes: scopeA -> scopeB -> scopeC. Exercise - * the scope config which is common across all signals and verify telemetry is as expected. + * Disable "scopeB". All other scopes are enabled by default. */ @Test - void disableScopeAllSignals() { - InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); - InMemoryMetricReader metricReader = InMemoryMetricReader.create(); - InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + void disableScopeB() { OpenTelemetrySdk sdk = OpenTelemetrySdk.builder() .setTracerProvider( SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .addScopeConfig(named("scopeB"), TracerConfig.disabled()) + .setTracerConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), TracerConfig.disabled())) .build()) .setMeterProvider( SdkMeterProvider.builder() .registerMetricReader(metricReader) - .addScopeConfig(named("scopeB"), MeterConfig.disabled()) + .setMeterConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), MeterConfig.disabled())) .build()) .setLoggerProvider( SdkLoggerProvider.builder() .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .addScopeConfig(named("scopeB"), LoggerConfig.disabled()) + .setLoggerConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), LoggerConfig.disabled())) .build()) .build(); - // Start scopeA - Tracer scopeATracer = sdk.getTracer("scopeA"); - Meter scopeAMeter = sdk.getMeter("scopeA"); - Logger scopeALogger = sdk.getSdkLoggerProvider().get("scopeA"); - Span spanA = scopeATracer.spanBuilder("spanA").startSpan(); - try (Scope spanAScope = spanA.makeCurrent()) { - scopeALogger.logRecordBuilder().setBody("scopeA log message").emit(); - - // Start scopeB - Tracer scopeBTracer = sdk.getTracer("scopeB"); - Meter scopeBMeter = sdk.getMeter("scopeB"); - Logger scopeBLogger = sdk.getSdkLoggerProvider().get("scopeB"); - Span spanB = scopeBTracer.spanBuilder("spanB").startSpan(); - try (Scope spanBScope = spanB.makeCurrent()) { - scopeBLogger.logRecordBuilder().setBody("scopeB log message").emit(); - - // Start scopeC - Tracer scopeCTracer = sdk.getTracer("scopeC"); - Meter scopeCMeter = sdk.getMeter("scopeC"); - Logger scopeCLogger = sdk.getSdkLoggerProvider().get("scopeC"); - Span spanC = scopeCTracer.spanBuilder("spanC").startSpan(); - try (Scope spanCScope = spanB.makeCurrent()) { - scopeCLogger.logRecordBuilder().setBody("scopeC log message").emit(); - } finally { - spanC.end(); - scopeCMeter.counterBuilder("scopeCCounter").build().add(1); - } - // End scopeC - - } finally { - spanB.end(); - scopeBMeter.counterBuilder("scopeBCounter").build().add(1); - } - // End scopeB - - } finally { - spanA.end(); - scopeAMeter.counterBuilder("scopeACounter").build().add(1); - } - // End scopeA + simulateInstrumentation(sdk); // Collect all the telemetry. Ensure we don't see any from scopeB, and that the telemetry from // scopeA and scopeC is valid. @@ -137,4 +103,114 @@ void disableScopeAllSignals() { assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); }); } + + /** + * Disable all scopes by default and enable a single scope. + */ + @Test + void disableAllScopesExceptB() { + OpenTelemetrySdk sdk = + OpenTelemetrySdk.builder() + .setTracerProvider( + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .setTracerConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), TracerConfig.enabled(), TracerConfig.disabled())) + .build()) + .setMeterProvider( + SdkMeterProvider.builder() + .registerMetricReader(metricReader) + .setMeterConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), MeterConfig.enabled(), MeterConfig.disabled())) + .build()) + .setLoggerProvider( + SdkLoggerProvider.builder() + .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) + .setLoggerConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), LoggerConfig.enabled(), LoggerConfig.disabled())) + .build()) + .build(); + + simulateInstrumentation(sdk); + + // Collect all the telemetry. Ensure we only see telemetry from scopeB, since other scopes have been disabled by default. + assertThat(spanExporter.getFinishedSpanItems()) + .satisfies( + spans -> { + Map> spansByScope = + spans.stream() + .collect(Collectors.groupingBy(SpanData::getInstrumentationScopeInfo)); + assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeA"))).isNull(); + assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeB"))).hasSize(1); + assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeC"))).isNull(); + }); + assertThat(metricReader.collectAllMetrics()) + .satisfies( + metrics -> { + Map> metricsByScope = + metrics.stream() + .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeA"))).isNull(); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeB"))).hasSize(1); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeC"))).isNull(); + }); + assertThat(logRecordExporter.getFinishedLogRecordItems()) + .satisfies( + logs -> { + Map> logsByScope = + logs.stream() + .collect(Collectors.groupingBy(LogRecordData::getInstrumentationScopeInfo)); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeA"))).isNull(); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeB"))).hasSize(1); + assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeC"))).isNull(); + }); + } + + + /** + * Emit spans, metrics and logs in a hierarchy of 3 scopes: scopeA -> scopeB -> scopeC. Exercise + * the scope config which is common across all signals. + */ + private static void simulateInstrumentation(OpenTelemetry openTelemetry) { + // Start scopeA + Tracer scopeATracer = openTelemetry.getTracer("scopeA"); + Meter scopeAMeter = openTelemetry.getMeter("scopeA"); + Logger scopeALogger = openTelemetry.getLogsBridge().get("scopeA"); + Span spanA = scopeATracer.spanBuilder("spanA").startSpan(); + try (Scope spanAScope = spanA.makeCurrent()) { + scopeALogger.logRecordBuilder().setBody("scopeA log message").emit(); + + // Start scopeB + Tracer scopeBTracer = openTelemetry.getTracer("scopeB"); + Meter scopeBMeter = openTelemetry.getMeter("scopeB"); + Logger scopeBLogger = openTelemetry.getLogsBridge().get("scopeB"); + Span spanB = scopeBTracer.spanBuilder("spanB").startSpan(); + try (Scope spanBScope = spanB.makeCurrent()) { + scopeBLogger.logRecordBuilder().setBody("scopeB log message").emit(); + + // Start scopeC + Tracer scopeCTracer = openTelemetry.getTracer("scopeC"); + Meter scopeCMeter = openTelemetry.getMeter("scopeC"); + Logger scopeCLogger = openTelemetry.getLogsBridge().get("scopeC"); + Span spanC = scopeCTracer.spanBuilder("spanC").startSpan(); + try (Scope spanCScope = spanB.makeCurrent()) { + scopeCLogger.logRecordBuilder().setBody("scopeC log message").emit(); + } finally { + spanC.end(); + scopeCMeter.counterBuilder("scopeCCounter").build().add(1); + } + // End scopeC + + } finally { + spanB.end(); + scopeBMeter.counterBuilder("scopeBCounter").build().add(1); + } + // End scopeB + + } finally { + spanA.end(); + scopeAMeter.counterBuilder("scopeACounter").build().add(1); + } + // End scopeA + } } diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java new file mode 100644 index 00000000000..2e3308c490c --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.common; + +import io.opentelemetry.sdk.internal.GlobUtil; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Utilities for configuring scopes. + */ +public final class ScopeConfig { + + /** + * Returns a function which returns {@code matchingConfig} to scopes which match the {@code scopeMatcher}. If a scope does match, returns null, which triggers the default behavior. + * + *

See {@link #scopeNameEquals(String)}, {@link #scopeNameMatches(String)} for helper functions for {@code scopeMatcher}. + */ + public static Function applyToMatching( + Predicate scopeMatcher, T matchingConfig) { + return scopeInfo -> scopeMatcher.test(scopeInfo) ? matchingConfig : null; + } + + /** + * Returns a function which returns {@code matchingConfig} to scopes which match the {@code scopeMatcher}, else returns {@code defaultConfig}. This is useful for overriding the default behavior. For example, you can disable by default and selectively enable select scopes. + * + *

See {@link #scopeNameEquals(String)}, {@link #scopeNameMatches(String)} for helper functions for {@code scopeMatcher}. + */ + public static Function applyToMatching( + Predicate scopeMatcher, T matchingConfig, T defaultConfig) { + return scopeInfo -> scopeMatcher.test(scopeInfo) ? matchingConfig : defaultConfig; + } + + /** + * Returns a predicate which returns {@code true} if the {@link InstrumentationScopeInfo#getName()} is an exact match of {@code targetScopeName}. + */ + public static Predicate scopeNameEquals(String scopeName) { + return scopeInfo -> scopeInfo.getName().equals(scopeName); + } + + /** + * Returns a predicate which returns {@code true} if the {@link InstrumentationScopeInfo#getName()} is a wildcard match of the {@code scopeNameGlobPattern}. + * + *

{@code scopeNameGlobPattern} name may contain the wildcard characters {@code *} and {@code ?} with the following matching criteria: + * + *

    + *
  • {@code *} matches 0 or more instances of any character + *
  • {@code ?} matches exactly one instance of any character + *
+ */ + public static Predicate scopeNameMatches( + String scopeNameGlobPattern) { + Predicate globPredicate = GlobUtil.toGlobPatternPredicate(scopeNameGlobPattern); + return scopeInfo -> globPredicate.test(scopeInfo.getName()); + } + + private ScopeConfig() {} +} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java deleted file mode 100644 index 9f4a3bfa9f0..00000000000 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelector.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.common; - -import com.google.auto.value.AutoValue; -import io.opentelemetry.sdk.internal.GlobUtil; -import java.util.Objects; -import java.util.StringJoiner; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -@AutoValue -@Immutable -public abstract class ScopeSelector { - - private final AtomicReference> selectorPredicate = - new AtomicReference<>(); - - /** Returns a new {@link ScopeSelectorBuilder} for {@link ScopeSelector}. */ - public static ScopeSelectorBuilder builder() { - return new ScopeSelectorBuilder(); - } - - /** - * Returns a {@link ScopeSelector} selecting scopes with the {@code scopeName}. - * - *

Scope name may contain the wildcard characters {@code *} and {@code ?} with the following - * matching criteria: - * - *

    - *
  • {@code *} matches 0 or more instances of any character - *
  • {@code ?} matches exactly one instance of any character - *
- */ - public static ScopeSelector named(String scopeName) { - return builder().setScopeName(scopeName).build(); - } - - static ScopeSelector create(String scopeName, @Nullable String scopeVersion) { - ScopeSelector selector = new AutoValue_ScopeSelector(scopeName, scopeVersion); - // Compute and cache the predicate because we need to check if a scope matches any registered - // scope selector whenever a scope is created - selector.selectorPredicate.set(matchesScopePredicate(selector)); - return selector; - } - - ScopeSelector() {} - - /** Determine if the {@code scopeInfo} matches the criteria of this {@link ScopeSelector}. */ - public boolean matchesScope(InstrumentationScopeInfo scopeInfo) { - return Objects.requireNonNull(selectorPredicate.get()).test(scopeInfo); - } - - private static Predicate matchesScopePredicate( - ScopeSelector scopeSelector) { - Predicate scopeNamePredicate = - GlobUtil.toGlobPatternPredicate(scopeSelector.getScopeName()); - return scopeInfo -> { - String scopeVersionCriteria = scopeSelector.getScopeVersion(); - return scopeNamePredicate.test(scopeInfo.getName()) - && (scopeVersionCriteria == null || scopeVersionCriteria.equals(scopeInfo.getVersion())); - }; - } - - /** - * Returns the selected scope name. - * - *

Scope name may contain the wildcard characters {@code *} and {@code ?} with the following - * matching criteria: - * - *

    - *
  • {@code *} matches 0 or more instances of any character - *
  • {@code ?} matches exactly one instance of any character - *
- */ - public abstract String getScopeName(); - - /** Returns the selected scope version, or null of this selects all scope versions. */ - @Nullable - public abstract String getScopeVersion(); - - @Override - public final String toString() { - StringJoiner joiner = new StringJoiner(", ", "ScopeSelector{", "}"); - joiner.add("scopeName=" + getScopeName()); - if (getScopeVersion() != null) { - joiner.add("scopeVersion=" + getScopeVersion()); - } - return joiner.toString(); - } -} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java deleted file mode 100644 index e49cfa58d87..00000000000 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeSelectorBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.common; - -import static java.util.Objects.requireNonNull; - -import javax.annotation.Nullable; - -/** Builder for {@link ScopeSelector}. */ -public final class ScopeSelectorBuilder { - - private String scopeName = "*"; - @Nullable private String scopeVersion; - - ScopeSelectorBuilder() {} - - /** - * Select scopes with the given {@code scopeName}. - * - *

Scope name may contain the wildcard characters {@code *} and {@code ?} with the following - * matching criteria: - * - *

    - *
  • {@code *} matches 0 or more instances of any character - *
  • {@code ?} matches exactly one instance of any character - *
- */ - public ScopeSelectorBuilder setScopeName(String scopeName) { - requireNonNull(scopeName, "scopeName"); - this.scopeName = scopeName; - return this; - } - - public ScopeSelectorBuilder setScopeVersion(String scopeVersion) { - requireNonNull(scopeVersion, "scopeVersion"); - this.scopeVersion = scopeVersion; - return this; - } - - /** Returns an {@link ScopeSelector} with the configuration of this builder. */ - public ScopeSelector build() { - return ScopeSelector.create(scopeName, scopeVersion); - } -} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java index b84dfeab93d..b3c4b8103a5 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java @@ -12,10 +12,15 @@ @Immutable public abstract class LoggerConfig { - private static final LoggerConfig DEFAULT_CONFIG = new AutoValue_LoggerConfig(true); + private static final LoggerConfig DEFAULT_CONFIG = + new AutoValue_LoggerConfig(/* enabled= */ true); public static LoggerConfig disabled() { - return new AutoValue_LoggerConfig(false); + return new AutoValue_LoggerConfig(/* enabled= */ false); + } + + public static LoggerConfig enabled() { + return DEFAULT_CONFIG; } public static LoggerConfig defaultConfig() { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java index ddb00cf7de4..32d6539e8da 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java @@ -8,9 +8,8 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.resources.Resource; -import java.util.LinkedHashMap; +import java.util.function.Function; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -24,7 +23,7 @@ final class LoggerSharedState { private final Supplier logLimitsSupplier; private final LogRecordProcessor logRecordProcessor; private final Clock clock; - private final LinkedHashMap loggerConfigMap; + private final Function loggerConfigProvider; @Nullable private volatile CompletableResultCode shutdownResult = null; LoggerSharedState( @@ -32,12 +31,12 @@ final class LoggerSharedState { Supplier logLimitsSupplier, LogRecordProcessor logRecordProcessor, Clock clock, - LinkedHashMap loggerConfigMap) { + Function loggerConfigProvider) { this.resource = resource; this.logLimitsSupplier = logLimitsSupplier; this.logRecordProcessor = logRecordProcessor; this.clock = clock; - this.loggerConfigMap = loggerConfigMap; + this.loggerConfigProvider = loggerConfigProvider; } Resource getResource() { @@ -57,12 +56,8 @@ Clock getClock() { } LoggerConfig getLoggerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - for (ScopeSelector scopeSelector : loggerConfigMap.keySet()) { - if (scopeSelector.matchesScope(instrumentationScopeInfo)) { - return loggerConfigMap.get(scopeSelector); - } - } - return LoggerConfig.defaultConfig(); + LoggerConfig loggerConfig = loggerConfigProvider.apply(instrumentationScopeInfo); + return loggerConfig == null ? LoggerConfig.defaultConfig() : loggerConfig; } boolean hasBeenShutdown() { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java index af1a40e26f5..ddf95c4469a 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java @@ -11,13 +11,13 @@ import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; import java.io.Closeable; -import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import javax.annotation.Nullable; @@ -51,11 +51,11 @@ public static SdkLoggerProviderBuilder builder() { Supplier logLimitsSupplier, List processors, Clock clock, - LinkedHashMap loggerConfigMap) { + Function loggerConfigProvider) { LogRecordProcessor logRecordProcessor = LogRecordProcessor.composite(processors); this.sharedState = new LoggerSharedState( - resource, logLimitsSupplier, logRecordProcessor, clock, loggerConfigMap); + resource, logLimitsSupplier, logRecordProcessor, clock, loggerConfigProvider); this.loggerComponentRegistry = new ComponentRegistry<>( instrumentationScopeInfo -> new SdkLogger(sharedState, instrumentationScopeInfo)); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java index b5514e5b6eb..d266073fd66 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java @@ -11,13 +11,13 @@ import io.opentelemetry.api.logs.Logger; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; -import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.function.Function; import java.util.function.Supplier; /** @@ -31,7 +31,8 @@ public final class SdkLoggerProviderBuilder { private Resource resource = Resource.getDefault(); private Supplier logLimitsSupplier = LogLimits::getDefault; private Clock clock = Clock.getDefault(); - private final LinkedHashMap loggerConfigMap = new LinkedHashMap<>(); + private Function loggerConfigProvider = + unused -> LoggerConfig.defaultConfig(); SdkLoggerProviderBuilder() {} @@ -103,9 +104,9 @@ public SdkLoggerProviderBuilder setClock(Clock clock) { return this; } - public SdkLoggerProviderBuilder addScopeConfig( - ScopeSelector scopeSelector, LoggerConfig loggerConfig) { - loggerConfigMap.put(scopeSelector, loggerConfig); + public SdkLoggerProviderBuilder setLoggerConfigProvider( + Function loggerConfigProvider) { + this.loggerConfigProvider = loggerConfigProvider; return this; } @@ -116,6 +117,6 @@ public SdkLoggerProviderBuilder addScopeConfig( */ public SdkLoggerProvider build() { return new SdkLoggerProvider( - resource, logLimitsSupplier, logRecordProcessors, clock, loggerConfigMap); + resource, logLimitsSupplier, logRecordProcessors, clock, loggerConfigProvider); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index a53e2a9604e..139f0efbbe0 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -5,8 +5,8 @@ package io.opentelemetry.sdk.logs; -import static io.opentelemetry.sdk.common.ScopeSelector.named; -import static io.opentelemetry.sdk.logs.LoggerConfig.disabled; +import static io.opentelemetry.sdk.common.ScopeConfig.applyToMatching; +import static io.opentelemetry.sdk.common.ScopeConfig.scopeNameEquals; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import io.opentelemetry.api.logs.Logger; @@ -28,7 +28,8 @@ void disableScopes() { SdkLoggerProvider.builder() // Disable loggerB. Since loggers are enabled by default, loggerA and loggerC are // enabled. - .addScopeConfig(named("loggerB"), disabled()) + .setLoggerConfigProvider( + applyToMatching(scopeNameEquals("loggerB"), LoggerConfig.disabled())) .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) .build(); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java index e1477735ea8..b9b4d5e4f74 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java @@ -13,7 +13,6 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.resources.Resource; -import java.util.LinkedHashMap; import org.junit.jupiter.api.Test; class LoggerSharedStateTest { @@ -29,7 +28,7 @@ void shutdown() { LogLimits::getDefault, logRecordProcessor, Clock.getDefault(), - new LinkedHashMap<>()); + unused -> LoggerConfig.defaultConfig()); state.shutdown(); state.shutdown(); verify(logRecordProcessor, times(1)).shutdown(); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java index 5a932525a61..d5a1a7a7990 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java @@ -12,10 +12,14 @@ @Immutable public abstract class MeterConfig { - private static final MeterConfig DEFAULT_CONFIG = new AutoValue_MeterConfig(true); + private static final MeterConfig DEFAULT_CONFIG = new AutoValue_MeterConfig(/* enabled= */ true); public static MeterConfig disabled() { - return new AutoValue_MeterConfig(false); + return new AutoValue_MeterConfig(/* enabled= */ false); + } + + public static MeterConfig enabled() { + return DEFAULT_CONFIG; } public static MeterConfig defaultConfig() { diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index 1a5fa191766..ef68e37fd9c 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -11,7 +11,7 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.CollectionRegistration; @@ -30,10 +30,10 @@ import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.logging.Logger; /** @@ -65,7 +65,7 @@ public static SdkMeterProviderBuilder builder() { Clock clock, Resource resource, ExemplarFilter exemplarFilter, - LinkedHashMap meterConfigMap) { + Function meterConfigProvider) { long startEpochNanos = clock.now(); this.registeredViews = registeredViews; this.registeredReaders = @@ -79,7 +79,7 @@ public static SdkMeterProviderBuilder builder() { this.metricProducers = metricProducers; this.sharedState = MeterProviderSharedState.create( - clock, resource, exemplarFilter, startEpochNanos, meterConfigMap); + clock, resource, exemplarFilter, startEpochNanos, meterConfigProvider); this.registry = new ComponentRegistry<>( instrumentationLibraryInfo -> diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index 288a6eaf6a3..0fb9a9bebb8 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -6,7 +6,7 @@ package io.opentelemetry.sdk.metrics; import io.opentelemetry.sdk.common.Clock; -import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.export.MetricProducer; import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; @@ -17,9 +17,9 @@ import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; import java.util.IdentityHashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.function.Function; /** * Builder class for the {@link SdkMeterProvider}. @@ -42,7 +42,8 @@ public final class SdkMeterProviderBuilder { private final List metricProducers = new ArrayList<>(); private final List registeredViews = new ArrayList<>(); private ExemplarFilter exemplarFilter = DEFAULT_EXEMPLAR_FILTER; - private final LinkedHashMap meterConfigMap = new LinkedHashMap<>(); + private Function meterConfigProvider = + unused -> MeterConfig.defaultConfig(); SdkMeterProviderBuilder() {} @@ -153,9 +154,9 @@ public SdkMeterProviderBuilder registerMetricProducer(MetricProducer metricProdu return this; } - public SdkMeterProviderBuilder addScopeConfig( - ScopeSelector scopeSelector, MeterConfig meterConfig) { - meterConfigMap.put(scopeSelector, meterConfig); + public SdkMeterProviderBuilder setMeterConfigProvider( + Function meterConfigProvider) { + this.meterConfigProvider = meterConfigProvider; return this; } @@ -168,6 +169,6 @@ public SdkMeterProvider build() { clock, resource, exemplarFilter, - meterConfigMap); + meterConfigProvider); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java index d2b9fc0e66a..ef52fbfaae4 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java @@ -8,14 +8,13 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.metrics.MeterConfig; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.resources.Resource; -import java.util.LinkedHashMap; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import javax.annotation.concurrent.Immutable; /** @@ -28,18 +27,18 @@ @Immutable public abstract class MeterProviderSharedState { - private AtomicReference> meterConfigMapRef = - new AtomicReference<>(); + private final AtomicReference> + meterConfigProviderRef = new AtomicReference<>(); public static MeterProviderSharedState create( Clock clock, Resource resource, ExemplarFilter exemplarFilter, long startEpochNanos, - LinkedHashMap meterConfigMap) { + Function meterConfigProvider) { MeterProviderSharedState sharedState = new AutoValue_MeterProviderSharedState(clock, resource, startEpochNanos, exemplarFilter); - sharedState.meterConfigMapRef.set(meterConfigMap); + sharedState.meterConfigProviderRef.set(meterConfigProvider); return sharedState; } @@ -58,13 +57,9 @@ public static MeterProviderSharedState create( abstract ExemplarFilter getExemplarFilter(); public MeterConfig getMeterConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - LinkedHashMap meterConfigMap = - Objects.requireNonNull(meterConfigMapRef.get()); - for (ScopeSelector scopeSelector : meterConfigMap.keySet()) { - if (scopeSelector.matchesScope(instrumentationScopeInfo)) { - return meterConfigMap.get(scopeSelector); - } - } - return MeterConfig.defaultConfig(); + Function meterConfigProvider = + Objects.requireNonNull(meterConfigProviderRef.get()); + MeterConfig meterConfig = meterConfigProvider.apply(instrumentationScopeInfo); + return meterConfig == null ? MeterConfig.defaultConfig() : meterConfig; } } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java index def983f4a46..6b1a955bfcf 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java @@ -10,14 +10,14 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; -import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,7 +47,7 @@ public static SdkTracerProviderBuilder builder() { Supplier spanLimitsSupplier, Sampler sampler, List spanProcessors, - LinkedHashMap tracerConfigMap) { + Function tracerConfigProvider) { this.sharedState = new TracerSharedState( clock, @@ -56,7 +56,7 @@ public static SdkTracerProviderBuilder builder() { spanLimitsSupplier, sampler, spanProcessors, - tracerConfigMap); + tracerConfigProvider); this.tracerSdkComponentRegistry = new ComponentRegistry<>( instrumentationScopeInfo -> new SdkTracer(sharedState, instrumentationScopeInfo)); diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java index ac9d9fab7c9..6464709ad3a 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java @@ -8,13 +8,13 @@ import static java.util.Objects.requireNonNull; import io.opentelemetry.sdk.common.Clock; -import io.opentelemetry.sdk.common.ScopeSelector; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.function.Function; import java.util.function.Supplier; /** Builder of {@link SdkTracerProvider}. */ @@ -28,7 +28,8 @@ public final class SdkTracerProviderBuilder { private Resource resource = Resource.getDefault(); private Supplier spanLimitsSupplier = SpanLimits::getDefault; private Sampler sampler = DEFAULT_SAMPLER; - private final LinkedHashMap tracerConfigMap = new LinkedHashMap<>(); + private Function tracerConfigProvider = + unused -> TracerConfig.defaultConfig(); /** * Assign a {@link Clock}. {@link Clock} will be used each time a {@link @@ -150,9 +151,9 @@ public SdkTracerProviderBuilder addSpanProcessor(SpanProcessor spanProcessor) { return this; } - public SdkTracerProviderBuilder addScopeConfig( - ScopeSelector scopeSelector, TracerConfig tracerConfig) { - tracerConfigMap.put(scopeSelector, tracerConfig); + public SdkTracerProviderBuilder setTracerConfigProvider( + Function tracerConfigProvider) { + this.tracerConfigProvider = tracerConfigProvider; return this; } @@ -169,7 +170,7 @@ public SdkTracerProvider build() { spanLimitsSupplier, sampler, spanProcessors, - tracerConfigMap); + tracerConfigProvider); } SdkTracerProviderBuilder() {} diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java index 367ee7b05a2..a7ffd25d915 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java @@ -12,10 +12,15 @@ @Immutable public abstract class TracerConfig { - private static final TracerConfig DEFAULT_CONFIG = new AutoValue_TracerConfig(true); + private static final TracerConfig DEFAULT_CONFIG = + new AutoValue_TracerConfig(/* enabled= */ true); public static TracerConfig disabled() { - return new AutoValue_TracerConfig(false); + return new AutoValue_TracerConfig(/* enabled= */ false); + } + + public static TracerConfig enabled() { + return DEFAULT_CONFIG; } public static TracerConfig defaultConfig() { diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java index c072bb9fa33..1681affb9d0 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java @@ -8,11 +8,10 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeSelector; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; -import java.util.LinkedHashMap; import java.util.List; +import java.util.function.Function; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -29,7 +28,7 @@ final class TracerSharedState { private final Supplier spanLimitsSupplier; private final Sampler sampler; private final SpanProcessor activeSpanProcessor; - private final LinkedHashMap tracerConfigMap; + private final Function tracerConfigProvider; @Nullable private volatile CompletableResultCode shutdownResult = null; @@ -41,7 +40,7 @@ final class TracerSharedState { Supplier spanLimitsSupplier, Sampler sampler, List spanProcessors, - LinkedHashMap tracerConfigMap) { + Function tracerConfigProvider) { this.clock = clock; this.idGenerator = idGenerator; this.idGeneratorSafeToSkipIdValidation = idGenerator instanceof RandomIdGenerator; @@ -49,7 +48,7 @@ final class TracerSharedState { this.spanLimitsSupplier = spanLimitsSupplier; this.sampler = sampler; activeSpanProcessor = SpanProcessor.composite(spanProcessors); - this.tracerConfigMap = tracerConfigMap; + this.tracerConfigProvider = tracerConfigProvider; } Clock getClock() { @@ -88,12 +87,8 @@ SpanProcessor getActiveSpanProcessor() { } TracerConfig getTracerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - for (ScopeSelector scopeSelector : tracerConfigMap.keySet()) { - if (scopeSelector.matchesScope(instrumentationScopeInfo)) { - return tracerConfigMap.get(scopeSelector); - } - } - return TracerConfig.defaultConfig(); + TracerConfig tracerConfig = tracerConfigProvider.apply(instrumentationScopeInfo); + return tracerConfig == null ? TracerConfig.defaultConfig() : tracerConfig; } /** diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index e81b3a34dd3..abacbab6f29 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -5,9 +5,9 @@ package io.opentelemetry.sdk.trace; -import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static io.opentelemetry.sdk.common.ScopeConfig.applyToMatching; +import static io.opentelemetry.sdk.common.ScopeConfig.scopeNameEquals; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.trace.TracerConfig.disabled; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; @@ -28,7 +28,8 @@ void disableScopes() throws InterruptedException { SdkTracerProvider.builder() // Disable tracerB. Since tracers are enabled by default, tracerA and tracerC are // enabled. - .addScopeConfig(named("tracerB"), disabled()) + .setTracerConfigProvider( + applyToMatching(scopeNameEquals("scopeB"), TracerConfig.disabled())) .addSpanProcessor(SimpleSpanProcessor.create(exporter)) .build(); From 69c5c0c9e64243fa10436c5648e30cf01aa0d8c4 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 10 Apr 2024 15:04:08 -0500 Subject: [PATCH 3/7] Refactor for improved ergonomics --- .../opentelemetry-sdk-common.txt | 21 +++- .../opentelemetry-sdk-logs.txt | 5 +- .../opentelemetry-sdk-metrics.txt | 5 +- .../opentelemetry-sdk-trace.txt | 5 +- ...igTest.java => ScopeConfiguratorTest.java} | 47 ++++---- .../opentelemetry/sdk/common/ScopeConfig.java | 61 ---------- .../sdk/common/ScopeConfigurator.java | 29 +++++ .../sdk/common/ScopeConfiguratorBuilder.java | 111 ++++++++++++++++++ .../opentelemetry/sdk/logs/LoggerConfig.java | 30 ++++- .../sdk/logs/LoggerSharedState.java | 10 +- .../sdk/logs/SdkLoggerProvider.java | 7 +- .../sdk/logs/SdkLoggerProviderBuilder.java | 44 +++++-- .../sdk/logs/LoggerConfigTest.java | 78 +++++++++++- .../sdk/metrics/MeterConfig.java | 30 ++++- .../sdk/metrics/SdkMeterProvider.java | 5 +- .../sdk/metrics/SdkMeterProviderBuilder.java | 44 +++++-- .../state/MeterProviderSharedState.java | 15 ++- .../sdk/metrics/InstrumentBuilderTest.java | 3 +- .../sdk/metrics/MeterConfigTest.java | 75 +++++++++++- .../sdk/trace/SdkTracerProvider.java | 7 +- .../sdk/trace/SdkTracerProviderBuilder.java | 44 +++++-- .../opentelemetry/sdk/trace/TracerConfig.java | 30 ++++- .../sdk/trace/TracerSharedState.java | 10 +- .../sdk/trace/TracerConfigTest.java | 77 +++++++++++- 24 files changed, 635 insertions(+), 158 deletions(-) rename sdk/all/src/test/java/io/opentelemetry/sdk/{ScopeConfigTest.java => ScopeConfiguratorTest.java} (85%) delete mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java create mode 100644 sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt index e659ed1f6cd..8a82b0ed757 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt @@ -1,10 +1,19 @@ Comparing source compatibility of against -+++* NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.ScopeConfig (not serializable) ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.common.ScopeConfigurator (not serializable) +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + GENERIC TEMPLATES: +++ T:java.lang.Object + +++ NEW INTERFACE: java.util.function.Function +++ NEW SUPERCLASS: java.lang.Object - +++* NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Function applyToMatching(java.util.function.Predicate, java.lang.Object) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder builder() GENERIC TEMPLATES: +++ T:java.lang.Object - +++* NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Function applyToMatching(java.util.function.Predicate, java.lang.Object, java.lang.Object) - GENERIC TEMPLATES: +++ T:java.lang.Object - +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate scopeNameEquals(java.lang.String) - +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate scopeNameMatches(java.lang.String) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder toBuilder() + +++ NEW ANNOTATION: java.lang.FunctionalInterface ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + GENERIC TEMPLATES: +++ T:java.lang.Object + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder addCondition(java.util.function.Predicate, java.lang.Object) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfigurator build() + +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate nameEquals(java.lang.String) + +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate nameMatchesGlob(java.lang.String) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder setDefault(java.lang.Object) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt index c07df020398..04564ce6825 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt @@ -2,9 +2,12 @@ Comparing source compatibility of against +++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.logs.LoggerConfig (not serializable) +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder configuratorBuilder() +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig defaultConfig() +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig disabled() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig enabled() +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder addScopeConfig(io.opentelemetry.sdk.common.ScopeSelector, io.opentelemetry.sdk.logs.LoggerConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder addLoggerConfiguratorMatcher(java.util.function.Predicate, io.opentelemetry.sdk.logs.LoggerConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder setLoggerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt index 2479717dc75..aaff534ebbe 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt @@ -2,9 +2,12 @@ Comparing source compatibility of against +++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.metrics.MeterConfig (not serializable) +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder configuratorBuilder() +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig defaultConfig() +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig disabled() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig enabled() +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder addScopeConfig(io.opentelemetry.sdk.common.ScopeSelector, io.opentelemetry.sdk.metrics.MeterConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder addMeterConfiguratorMatcher(java.util.function.Predicate, io.opentelemetry.sdk.metrics.MeterConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder setMeterConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt index 9a9b3e8f4a6..4d6ac336508 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt @@ -1,10 +1,13 @@ Comparing source compatibility of against *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProviderBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder addScopeConfig(io.opentelemetry.sdk.common.ScopeSelector, io.opentelemetry.sdk.trace.TracerConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder addTracerConfiguratorMatcher(java.util.function.Predicate, io.opentelemetry.sdk.trace.TracerConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setTracerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) +++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.trace.TracerConfig (not serializable) +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder configuratorBuilder() +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig defaultConfig() +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig disabled() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig enabled() +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java similarity index 85% rename from sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java rename to sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java index 24fe05f8a2d..d865c2882dc 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfigTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java @@ -5,8 +5,7 @@ package io.opentelemetry.sdk; -import static io.opentelemetry.sdk.common.ScopeConfig.applyToMatching; -import static io.opentelemetry.sdk.common.ScopeConfig.scopeNameEquals; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; @@ -35,15 +34,13 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Test; -class ScopeConfigTest { +class ScopeConfiguratorTest { private final InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); private final InMemoryMetricReader metricReader = InMemoryMetricReader.create(); private final InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); - /** - * Disable "scopeB". All other scopes are enabled by default. - */ + /** Disable "scopeB". All other scopes are enabled by default. */ @Test void disableScopeB() { OpenTelemetrySdk sdk = @@ -51,20 +48,17 @@ void disableScopeB() { .setTracerProvider( SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .setTracerConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), TracerConfig.disabled())) + .addTracerConfiguratorMatcher(nameEquals("scopeB"), TracerConfig.disabled()) .build()) .setMeterProvider( SdkMeterProvider.builder() .registerMetricReader(metricReader) - .setMeterConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), MeterConfig.disabled())) + .addMeterConfiguratorMatcher(nameEquals("scopeB"), MeterConfig.disabled()) .build()) .setLoggerProvider( SdkLoggerProvider.builder() .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .setLoggerConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), LoggerConfig.disabled())) + .addLoggerConfiguratorMatcher(nameEquals("scopeB"), LoggerConfig.disabled()) .build()) .build(); @@ -104,9 +98,7 @@ void disableScopeB() { }); } - /** - * Disable all scopes by default and enable a single scope. - */ + /** Disable all scopes by default and enable a single scope. */ @Test void disableAllScopesExceptB() { OpenTelemetrySdk sdk = @@ -114,26 +106,36 @@ void disableAllScopesExceptB() { .setTracerProvider( SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .setTracerConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), TracerConfig.enabled(), TracerConfig.disabled())) + .setTracerConfigurator( + TracerConfig.configuratorBuilder() + .setDefault(TracerConfig.disabled()) + .addCondition(nameEquals("scopeB"), TracerConfig.enabled()) + .build()) .build()) .setMeterProvider( SdkMeterProvider.builder() .registerMetricReader(metricReader) - .setMeterConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), MeterConfig.enabled(), MeterConfig.disabled())) + .setMeterConfigurator( + MeterConfig.configuratorBuilder() + .setDefault(MeterConfig.disabled()) + .addCondition(nameEquals("scopeB"), MeterConfig.enabled()) + .build()) .build()) .setLoggerProvider( SdkLoggerProvider.builder() .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .setLoggerConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), LoggerConfig.enabled(), LoggerConfig.disabled())) + .setLoggerConfigurator( + LoggerConfig.configuratorBuilder() + .setDefault(LoggerConfig.disabled()) + .addCondition(nameEquals("scopeB"), LoggerConfig.enabled()) + .build()) .build()) .build(); simulateInstrumentation(sdk); - // Collect all the telemetry. Ensure we only see telemetry from scopeB, since other scopes have been disabled by default. + // Collect all the telemetry. Ensure we only see telemetry from scopeB, since other scopes have + // been disabled by default. assertThat(spanExporter.getFinishedSpanItems()) .satisfies( spans -> { @@ -166,7 +168,6 @@ void disableAllScopesExceptB() { }); } - /** * Emit spans, metrics and logs in a hierarchy of 3 scopes: scopeA -> scopeB -> scopeC. Exercise * the scope config which is common across all signals. diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java deleted file mode 100644 index 2e3308c490c..00000000000 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.common; - -import io.opentelemetry.sdk.internal.GlobUtil; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * Utilities for configuring scopes. - */ -public final class ScopeConfig { - - /** - * Returns a function which returns {@code matchingConfig} to scopes which match the {@code scopeMatcher}. If a scope does match, returns null, which triggers the default behavior. - * - *

See {@link #scopeNameEquals(String)}, {@link #scopeNameMatches(String)} for helper functions for {@code scopeMatcher}. - */ - public static Function applyToMatching( - Predicate scopeMatcher, T matchingConfig) { - return scopeInfo -> scopeMatcher.test(scopeInfo) ? matchingConfig : null; - } - - /** - * Returns a function which returns {@code matchingConfig} to scopes which match the {@code scopeMatcher}, else returns {@code defaultConfig}. This is useful for overriding the default behavior. For example, you can disable by default and selectively enable select scopes. - * - *

See {@link #scopeNameEquals(String)}, {@link #scopeNameMatches(String)} for helper functions for {@code scopeMatcher}. - */ - public static Function applyToMatching( - Predicate scopeMatcher, T matchingConfig, T defaultConfig) { - return scopeInfo -> scopeMatcher.test(scopeInfo) ? matchingConfig : defaultConfig; - } - - /** - * Returns a predicate which returns {@code true} if the {@link InstrumentationScopeInfo#getName()} is an exact match of {@code targetScopeName}. - */ - public static Predicate scopeNameEquals(String scopeName) { - return scopeInfo -> scopeInfo.getName().equals(scopeName); - } - - /** - * Returns a predicate which returns {@code true} if the {@link InstrumentationScopeInfo#getName()} is a wildcard match of the {@code scopeNameGlobPattern}. - * - *

{@code scopeNameGlobPattern} name may contain the wildcard characters {@code *} and {@code ?} with the following matching criteria: - * - *

    - *
  • {@code *} matches 0 or more instances of any character - *
  • {@code ?} matches exactly one instance of any character - *
- */ - public static Predicate scopeNameMatches( - String scopeNameGlobPattern) { - Predicate globPredicate = GlobUtil.toGlobPatternPredicate(scopeNameGlobPattern); - return scopeInfo -> globPredicate.test(scopeInfo.getName()); - } - - private ScopeConfig() {} -} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java new file mode 100644 index 00000000000..e6bcec857e0 --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.common; + +import java.util.function.Function; + +/** + * A {@link ScopeConfigurator} computes configuration for a given {@link InstrumentationScopeInfo}. + */ +@FunctionalInterface +public interface ScopeConfigurator extends Function { + + /** Create a new builder. */ + static ScopeConfiguratorBuilder builder() { + return new ScopeConfiguratorBuilder<>(unused -> null); + } + + /** + * Convert this {@link ScopeConfigurator} to a builder. Additional added matchers only apply when + * {@link #apply(Object)} returns {@code null}. If this configurator contains {@link + * ScopeConfiguratorBuilder#setDefault(Object)}, additional matchers are never applied. + */ + default ScopeConfiguratorBuilder toBuilder() { + return new ScopeConfiguratorBuilder<>(this); + } +} diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java new file mode 100644 index 00000000000..036eaf33400 --- /dev/null +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java @@ -0,0 +1,111 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.common; + +import io.opentelemetry.sdk.internal.GlobUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import javax.annotation.Nullable; + +/** + * Builder for {@link ScopeConfigurator}. + * + * @param The scope configuration object, e.g. {@code TracerConfig}, {@code LoggerConfig}, + * {@code MeterConfig}. + */ +public final class ScopeConfiguratorBuilder { + + private final ScopeConfigurator baseScopeConfigurator; + @Nullable private T defaultScopeConfig; + private final List> conditions = new ArrayList<>(); + + ScopeConfiguratorBuilder(ScopeConfigurator baseScopeConfigurator) { + this.baseScopeConfigurator = baseScopeConfigurator; + } + + /** + * Set the default scope config, which is returned by {@link ScopeConfigurator#apply(Object)} if a + * {@link InstrumentationScopeInfo} does not match any {@link #addCondition(Predicate, Object) + * conditions}. If a default is not set, an SDK defined default is used. + */ + public ScopeConfiguratorBuilder setDefault(T defaultScopeConfig) { + this.defaultScopeConfig = defaultScopeConfig; + return this; + } + + /** + * Add a condition. Conditions are evaluated in order. The {@code scopeConfig} for the first match + * is returned by {@link ScopeConfigurator#apply(Object)}. + * + * @param scopePredicate predicate that {@link InstrumentationScopeInfo}s are evaluated against + * @param scopeConfig the scope config to use when this condition is the first matching {@code + * scopePredicate} + * @see #nameMatchesGlob(String) + * @see #nameEquals(String) + */ + public ScopeConfiguratorBuilder addCondition( + Predicate scopePredicate, T scopeConfig) { + conditions.add(new Condition<>(scopePredicate, scopeConfig)); + return this; + } + + /** + * Helper function for pattern matching {@link InstrumentationScopeInfo#getName()} against the + * {@code globPattern}. + * + *

{@code globPattern} may contain the wildcard characters {@code *} and {@code ?} with the + * following matching criteria: + * + *

    + *
  • {@code *} matches 0 or more instances of any character + *
  • {@code ?} matches exactly one instance of any character + *
+ * + * @see #addCondition(Predicate, Object) + */ + public static Predicate nameMatchesGlob(String globPattern) { + Predicate globPredicate = GlobUtil.toGlobPatternPredicate(globPattern); + return scopeInfo -> globPredicate.test(scopeInfo.getName()); + } + + /** + * Helper function for exact matching {@link InstrumentationScopeInfo#getName()} against the + * {@code scopeName}. + * + * @see #addCondition(Predicate, Object) + */ + public static Predicate nameEquals(String scopeName) { + return scopeInfo -> scopeInfo.getName().equals(scopeName); + } + + /** Build a {@link ScopeConfigurator} with the configuration of this builder. */ + public ScopeConfigurator build() { + // TODO: return an instance with toString implementation which self describes rules + return scopeInfo -> { + T scopeConfig = baseScopeConfigurator.apply(scopeInfo); + if (scopeConfig != null) { + return scopeConfig; + } + for (Condition condition : conditions) { + if (condition.scopeMatcher.test(scopeInfo)) { + return condition.scopeConfig; + } + } + return defaultScopeConfig; + }; + } + + private static final class Condition { + private final Predicate scopeMatcher; + private final T scopeConfig; + + private Condition(Predicate scopeMatcher, T scopeConfig) { + this.scopeMatcher = scopeMatcher; + this.scopeConfig = scopeConfig; + } + } +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java index b3c4b8103a5..3260e099bd7 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java @@ -6,27 +6,55 @@ package io.opentelemetry.sdk.logs; import com.google.auto.value.AutoValue; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import java.util.function.Predicate; import javax.annotation.concurrent.Immutable; +/** + * A collection of configuration options which define the behavior of a {@link Logger}. + * + * @see SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator) + * @see SdkLoggerProviderBuilder#addLoggerConfiguratorMatcher(Predicate, LoggerConfig) + */ @AutoValue @Immutable public abstract class LoggerConfig { private static final LoggerConfig DEFAULT_CONFIG = new AutoValue_LoggerConfig(/* enabled= */ true); + private static final LoggerConfig DISABLED_CONFIG = + new AutoValue_LoggerConfig(/* enabled= */ false); + /** Returns a disabled {@link LoggerConfig}. */ public static LoggerConfig disabled() { - return new AutoValue_LoggerConfig(/* enabled= */ false); + return DISABLED_CONFIG; } + /** Returns an enabled {@link LoggerConfig}. */ public static LoggerConfig enabled() { return DEFAULT_CONFIG; } + /** + * Returns the default {@link LoggerConfig}, which is used when no {@link + * SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator)} is set or when the logger + * configurator returns {@code null} for a {@link InstrumentationScopeInfo}. + */ public static LoggerConfig defaultConfig() { return DEFAULT_CONFIG; } + /** + * Create a {@link ScopeConfiguratorBuilder} for configuring {@link + * SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator)}. + */ + public static ScopeConfiguratorBuilder configuratorBuilder() { + return ScopeConfigurator.builder(); + } + LoggerConfig() {} /** Returns {@code true} if this logger is enabled. Defaults to {@code true}. */ diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java index 32d6539e8da..4b46f4cfc71 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java @@ -8,8 +8,8 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.resources.Resource; -import java.util.function.Function; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -23,7 +23,7 @@ final class LoggerSharedState { private final Supplier logLimitsSupplier; private final LogRecordProcessor logRecordProcessor; private final Clock clock; - private final Function loggerConfigProvider; + private final ScopeConfigurator loggerConfigurator; @Nullable private volatile CompletableResultCode shutdownResult = null; LoggerSharedState( @@ -31,12 +31,12 @@ final class LoggerSharedState { Supplier logLimitsSupplier, LogRecordProcessor logRecordProcessor, Clock clock, - Function loggerConfigProvider) { + ScopeConfigurator loggerConfigurator) { this.resource = resource; this.logLimitsSupplier = logLimitsSupplier; this.logRecordProcessor = logRecordProcessor; this.clock = clock; - this.loggerConfigProvider = loggerConfigProvider; + this.loggerConfigurator = loggerConfigurator; } Resource getResource() { @@ -56,7 +56,7 @@ Clock getClock() { } LoggerConfig getLoggerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - LoggerConfig loggerConfig = loggerConfigProvider.apply(instrumentationScopeInfo); + LoggerConfig loggerConfig = loggerConfigurator.apply(instrumentationScopeInfo); return loggerConfig == null ? LoggerConfig.defaultConfig() : loggerConfig; } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java index ddf95c4469a..1037d77f0a3 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java @@ -11,13 +11,12 @@ import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; import java.io.Closeable; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import javax.annotation.Nullable; @@ -51,11 +50,11 @@ public static SdkLoggerProviderBuilder builder() { Supplier logLimitsSupplier, List processors, Clock clock, - Function loggerConfigProvider) { + ScopeConfigurator loggerConfigurator) { LogRecordProcessor logRecordProcessor = LogRecordProcessor.composite(processors); this.sharedState = new LoggerSharedState( - resource, logLimitsSupplier, logRecordProcessor, clock, loggerConfigProvider); + resource, logLimitsSupplier, logRecordProcessor, clock, loggerConfigurator); this.loggerComponentRegistry = new ComponentRegistry<>( instrumentationScopeInfo -> new SdkLogger(sharedState, instrumentationScopeInfo)); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java index d266073fd66..4f5d60390e1 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java @@ -12,12 +12,14 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; /** @@ -31,8 +33,8 @@ public final class SdkLoggerProviderBuilder { private Resource resource = Resource.getDefault(); private Supplier logLimitsSupplier = LogLimits::getDefault; private Clock clock = Clock.getDefault(); - private Function loggerConfigProvider = - unused -> LoggerConfig.defaultConfig(); + private ScopeConfiguratorBuilder loggerConfiguratorBuilder = + LoggerConfig.configuratorBuilder(); SdkLoggerProviderBuilder() {} @@ -104,9 +106,37 @@ public SdkLoggerProviderBuilder setClock(Clock clock) { return this; } - public SdkLoggerProviderBuilder setLoggerConfigProvider( - Function loggerConfigProvider) { - this.loggerConfigProvider = loggerConfigProvider; + /** + * Set the logger configurator, which computes {@link LoggerConfig} for each {@link + * InstrumentationScopeInfo}. + * + *

Overrides any matchers added via {@link #addLoggerConfiguratorMatcher(Predicate, + * LoggerConfig)}. + * + * @see LoggerConfig#configuratorBuilder() + */ + public SdkLoggerProviderBuilder setLoggerConfigurator( + ScopeConfigurator loggerConfigurator) { + this.loggerConfiguratorBuilder = loggerConfigurator.toBuilder(); + return this; + } + + /** + * Adds a condition to the logger configurator, which computes {@link LoggerConfig} for each + * {@link InstrumentationScopeInfo}. + * + *

Applies after any previously added conditions. + * + *

If {@link #setLoggerConfigurator(ScopeConfigurator)} was previously called, this condition + * will only be applied if the {@link ScopeConfigurator#apply(Object)} returns null for the + * matched {@link InstrumentationScopeInfo}(s). + * + * @see ScopeConfiguratorBuilder#nameEquals(String) + * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) + */ + public SdkLoggerProviderBuilder addLoggerConfiguratorMatcher( + Predicate scopeMatcher, LoggerConfig loggerConfig) { + this.loggerConfiguratorBuilder.addCondition(scopeMatcher, loggerConfig); return this; } @@ -117,6 +147,6 @@ public SdkLoggerProviderBuilder setLoggerConfigProvider( */ public SdkLoggerProvider build() { return new SdkLoggerProvider( - resource, logLimitsSupplier, logRecordProcessors, clock, loggerConfigProvider); + resource, logLimitsSupplier, logRecordProcessors, clock, loggerConfiguratorBuilder.build()); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 139f0efbbe0..01106e58324 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -5,19 +5,26 @@ package io.opentelemetry.sdk.logs; -import static io.opentelemetry.sdk.common.ScopeConfig.applyToMatching; -import static io.opentelemetry.sdk.common.ScopeConfig.scopeNameEquals; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameMatchesGlob; +import static io.opentelemetry.sdk.logs.LoggerConfig.defaultConfig; +import static io.opentelemetry.sdk.logs.LoggerConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class LoggerConfigTest { @@ -28,8 +35,7 @@ void disableScopes() { SdkLoggerProvider.builder() // Disable loggerB. Since loggers are enabled by default, loggerA and loggerC are // enabled. - .setLoggerConfigProvider( - applyToMatching(scopeNameEquals("loggerB"), LoggerConfig.disabled())) + .addLoggerConfiguratorMatcher(nameEquals("loggerB"), LoggerConfig.disabled()) .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) .build(); @@ -53,4 +59,68 @@ void disableScopes() { assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerC"))).hasSize(1); }); } + + @ParameterizedTest + @MethodSource("loggerConfiguratorArgs") + void loggerConfigurator( + ScopeConfigurator loggerConfigurator, + InstrumentationScopeInfo scope, + LoggerConfig expectedLoggerConfig) { + LoggerConfig loggerConfig = loggerConfigurator.apply(scope); + loggerConfig = loggerConfig == null ? defaultConfig() : loggerConfig; + assertThat(loggerConfig).isEqualTo(expectedLoggerConfig); + } + + private static final InstrumentationScopeInfo scopeCat = InstrumentationScopeInfo.create("cat"); + private static final InstrumentationScopeInfo scopeDog = InstrumentationScopeInfo.create("dog"); + private static final InstrumentationScopeInfo scopeDuck = InstrumentationScopeInfo.create("duck"); + + private static Stream loggerConfiguratorArgs() { + ScopeConfigurator defaultConfigurator = + LoggerConfig.configuratorBuilder().build(); + ScopeConfigurator disableCat = + LoggerConfig.configuratorBuilder() + .addCondition(nameEquals("cat"), LoggerConfig.disabled()) + // Second matching rule for cat should be ignored + .addCondition(nameEquals("cat"), enabled()) + .build(); + ScopeConfigurator disableStartsWithD = + LoggerConfig.configuratorBuilder() + .addCondition(nameMatchesGlob("d*"), LoggerConfig.disabled()) + .build(); + ScopeConfigurator enableCat = + LoggerConfig.configuratorBuilder() + .setDefault(LoggerConfig.disabled()) + .addCondition(nameEquals("cat"), enabled()) + // Second matching rule for cat should be ignored + .addCondition(nameEquals("cat"), LoggerConfig.disabled()) + .build(); + ScopeConfigurator enableStartsWithD = + LoggerConfig.configuratorBuilder() + .setDefault(LoggerConfig.disabled()) + .addCondition(nameMatchesGlob("d*"), LoggerConfig.enabled()) + .build(); + + return Stream.of( + // default + Arguments.of(defaultConfigurator, scopeCat, defaultConfig()), + Arguments.of(defaultConfigurator, scopeDog, defaultConfig()), + Arguments.of(defaultConfigurator, scopeDuck, defaultConfig()), + // default enabled, disable cat + Arguments.of(disableCat, scopeCat, LoggerConfig.disabled()), + Arguments.of(disableCat, scopeDog, enabled()), + Arguments.of(disableCat, scopeDuck, enabled()), + // default enabled, disable pattern + Arguments.of(disableStartsWithD, scopeCat, enabled()), + Arguments.of(disableStartsWithD, scopeDog, LoggerConfig.disabled()), + Arguments.of(disableStartsWithD, scopeDuck, LoggerConfig.disabled()), + // default disabled, enable cat + Arguments.of(enableCat, scopeCat, enabled()), + Arguments.of(enableCat, scopeDog, LoggerConfig.disabled()), + Arguments.of(enableCat, scopeDuck, LoggerConfig.disabled()), + // default disabled, enable pattern + Arguments.of(enableStartsWithD, scopeCat, LoggerConfig.disabled()), + Arguments.of(enableStartsWithD, scopeDog, enabled()), + Arguments.of(enableStartsWithD, scopeDuck, enabled())); + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java index d5a1a7a7990..20f0a0fa972 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java @@ -6,26 +6,54 @@ package io.opentelemetry.sdk.metrics; import com.google.auto.value.AutoValue; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import java.util.function.Predicate; import javax.annotation.concurrent.Immutable; +/** + * A collection of configuration options which define the behavior of a {@link Meter}. + * + * @see SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator) + * @see SdkMeterProviderBuilder#addMeterConfiguratorMatcher(Predicate, MeterConfig) + */ @AutoValue @Immutable public abstract class MeterConfig { private static final MeterConfig DEFAULT_CONFIG = new AutoValue_MeterConfig(/* enabled= */ true); + private static final MeterConfig DISABLED_CONFIG = + new AutoValue_MeterConfig(/* enabled= */ false); + /** Returns a disabled {@link MeterConfig}. */ public static MeterConfig disabled() { - return new AutoValue_MeterConfig(/* enabled= */ false); + return DISABLED_CONFIG; } + /** Returns an enabled {@link MeterConfig}. */ public static MeterConfig enabled() { return DEFAULT_CONFIG; } + /** + * Returns the default {@link MeterConfig}, which is used when no {@link + * SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator)} is set or when the meter + * configurator returns {@code null} for a {@link InstrumentationScopeInfo}. + */ public static MeterConfig defaultConfig() { return DEFAULT_CONFIG; } + /** + * Create a {@link ScopeConfiguratorBuilder} for configuring {@link + * SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator)}. + */ + public static ScopeConfiguratorBuilder configuratorBuilder() { + return ScopeConfigurator.builder(); + } + MeterConfig() {} /** Returns {@code true} if this meter is enabled. Defaults to {@code true}. */ diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index ef68e37fd9c..8fe8f1630c8 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -11,7 +11,7 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.CollectionRegistration; @@ -33,7 +33,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; import java.util.logging.Logger; /** @@ -65,7 +64,7 @@ public static SdkMeterProviderBuilder builder() { Clock clock, Resource resource, ExemplarFilter exemplarFilter, - Function meterConfigProvider) { + ScopeConfigurator meterConfigProvider) { long startEpochNanos = clock.now(); this.registeredViews = registeredViews; this.registeredReaders = diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index 0fb9a9bebb8..ca008fd4bbd 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -7,6 +7,8 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; import io.opentelemetry.sdk.metrics.export.MetricProducer; import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; @@ -19,7 +21,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Objects; -import java.util.function.Function; +import java.util.function.Predicate; /** * Builder class for the {@link SdkMeterProvider}. @@ -42,8 +44,8 @@ public final class SdkMeterProviderBuilder { private final List metricProducers = new ArrayList<>(); private final List registeredViews = new ArrayList<>(); private ExemplarFilter exemplarFilter = DEFAULT_EXEMPLAR_FILTER; - private Function meterConfigProvider = - unused -> MeterConfig.defaultConfig(); + private ScopeConfiguratorBuilder meterConfiguratorBuilder = + MeterConfig.configuratorBuilder(); SdkMeterProviderBuilder() {} @@ -154,9 +156,37 @@ public SdkMeterProviderBuilder registerMetricProducer(MetricProducer metricProdu return this; } - public SdkMeterProviderBuilder setMeterConfigProvider( - Function meterConfigProvider) { - this.meterConfigProvider = meterConfigProvider; + /** + * Set the meter configurator, which computes {@link MeterConfig} for each {@link + * InstrumentationScopeInfo}. + * + *

Overrides any matchers added via {@link #addMeterConfiguratorMatcher(Predicate, + * MeterConfig)}. + * + * @see MeterConfig#configuratorBuilder() + */ + public SdkMeterProviderBuilder setMeterConfigurator( + ScopeConfigurator meterConfigurator) { + this.meterConfiguratorBuilder = meterConfigurator.toBuilder(); + return this; + } + + /** + * Adds a condition to the meter configurator, which computes {@link MeterConfig} for each {@link + * InstrumentationScopeInfo}. + * + *

Applies after any previously added conditions. + * + *

If {@link #setMeterConfigurator(ScopeConfigurator)} was previously called, this condition + * will only be applied if the {@link ScopeConfigurator#apply(Object)} returns null for the + * matched {@link InstrumentationScopeInfo}(s). + * + * @see ScopeConfiguratorBuilder#nameEquals(String) + * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) + */ + public SdkMeterProviderBuilder addMeterConfiguratorMatcher( + Predicate scopeMatcher, MeterConfig meterConfig) { + this.meterConfiguratorBuilder.addCondition(scopeMatcher, meterConfig); return this; } @@ -169,6 +199,6 @@ public SdkMeterProvider build() { clock, resource, exemplarFilter, - meterConfigProvider); + meterConfiguratorBuilder.build()); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java index ef52fbfaae4..20fa5912e79 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java @@ -8,13 +8,13 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.metrics.MeterConfig; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.resources.Resource; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import javax.annotation.concurrent.Immutable; /** @@ -27,18 +27,18 @@ @Immutable public abstract class MeterProviderSharedState { - private final AtomicReference> - meterConfigProviderRef = new AtomicReference<>(); + private final AtomicReference> meterConfigProviderRef = + new AtomicReference<>(); public static MeterProviderSharedState create( Clock clock, Resource resource, ExemplarFilter exemplarFilter, long startEpochNanos, - Function meterConfigProvider) { + ScopeConfigurator meterConfigurator) { MeterProviderSharedState sharedState = new AutoValue_MeterProviderSharedState(clock, resource, startEpochNanos, exemplarFilter); - sharedState.meterConfigProviderRef.set(meterConfigProvider); + sharedState.meterConfigProviderRef.set(meterConfigurator); return sharedState; } @@ -57,9 +57,8 @@ public static MeterProviderSharedState create( abstract ExemplarFilter getExemplarFilter(); public MeterConfig getMeterConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - Function meterConfigProvider = - Objects.requireNonNull(meterConfigProviderRef.get()); - MeterConfig meterConfig = meterConfigProvider.apply(instrumentationScopeInfo); + MeterConfig meterConfig = + Objects.requireNonNull(meterConfigProviderRef.get()).apply(instrumentationScopeInfo); return meterConfig == null ? MeterConfig.defaultConfig() : meterConfig; } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java index 75d9486f852..f4f57eb1bb2 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java @@ -15,7 +15,6 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.time.TestClock; import java.util.Collections; -import java.util.LinkedHashMap; import org.junit.jupiter.api.Test; class InstrumentBuilderTest { @@ -26,7 +25,7 @@ class InstrumentBuilderTest { Resource.getDefault(), ExemplarFilter.alwaysOff(), 0, - new LinkedHashMap<>()); + MeterConfig.configuratorBuilder().build()); static final InstrumentationScopeInfo SCOPE = InstrumentationScopeInfo.create("scope-name"); public static final MeterSharedState METER_SHARED_STATE = MeterSharedState.create(SCOPE, Collections.emptyList()); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java index da4dfb4bb74..7f329e1451c 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -5,18 +5,26 @@ package io.opentelemetry.sdk.metrics; -import static io.opentelemetry.sdk.common.ScopeSelector.named; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameMatchesGlob; +import static io.opentelemetry.sdk.metrics.MeterConfig.defaultConfig; import static io.opentelemetry.sdk.metrics.MeterConfig.disabled; +import static io.opentelemetry.sdk.metrics.MeterConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class MeterConfigTest { @@ -26,7 +34,7 @@ void disableScopes() { SdkMeterProvider meterProvider = SdkMeterProvider.builder() // Disable meterB. Since meters are enabled by default, meterA and meterC are enabled. - .addScopeConfig(named("meterB"), disabled()) + .addMeterConfiguratorMatcher(nameEquals("meterB"), disabled()) .registerMetricReader(reader) .build(); @@ -73,4 +81,67 @@ void disableScopes() { assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterC"))).hasSize(6); }); } + + @ParameterizedTest + @MethodSource("meterConfiguratorArgs") + void meterConfigurator( + ScopeConfigurator meterConfigurator, + InstrumentationScopeInfo scope, + MeterConfig expectedMeterConfig) { + MeterConfig meterConfig = meterConfigurator.apply(scope); + meterConfig = meterConfig == null ? defaultConfig() : meterConfig; + assertThat(meterConfig).isEqualTo(expectedMeterConfig); + } + + private static final InstrumentationScopeInfo scopeCat = InstrumentationScopeInfo.create("cat"); + private static final InstrumentationScopeInfo scopeDog = InstrumentationScopeInfo.create("dog"); + private static final InstrumentationScopeInfo scopeDuck = InstrumentationScopeInfo.create("duck"); + + private static Stream meterConfiguratorArgs() { + ScopeConfigurator defaultConfigurator = MeterConfig.configuratorBuilder().build(); + ScopeConfigurator disableCat = + MeterConfig.configuratorBuilder() + .addCondition(nameEquals("cat"), MeterConfig.disabled()) + // Second matching rule for cat should be ignored + .addCondition(nameEquals("cat"), enabled()) + .build(); + ScopeConfigurator disableStartsWithD = + MeterConfig.configuratorBuilder() + .addCondition(nameMatchesGlob("d*"), MeterConfig.disabled()) + .build(); + ScopeConfigurator enableCat = + MeterConfig.configuratorBuilder() + .setDefault(MeterConfig.disabled()) + .addCondition(nameEquals("cat"), enabled()) + // Second matching rule for cat should be ignored + .addCondition(nameEquals("cat"), MeterConfig.disabled()) + .build(); + ScopeConfigurator enableStartsWithD = + MeterConfig.configuratorBuilder() + .setDefault(MeterConfig.disabled()) + .addCondition(nameMatchesGlob("d*"), MeterConfig.enabled()) + .build(); + + return Stream.of( + // default + Arguments.of(defaultConfigurator, scopeCat, defaultConfig()), + Arguments.of(defaultConfigurator, scopeDog, defaultConfig()), + Arguments.of(defaultConfigurator, scopeDuck, defaultConfig()), + // default enabled, disable cat + Arguments.of(disableCat, scopeCat, MeterConfig.disabled()), + Arguments.of(disableCat, scopeDog, enabled()), + Arguments.of(disableCat, scopeDuck, enabled()), + // default enabled, disable pattern + Arguments.of(disableStartsWithD, scopeCat, enabled()), + Arguments.of(disableStartsWithD, scopeDog, MeterConfig.disabled()), + Arguments.of(disableStartsWithD, scopeDuck, MeterConfig.disabled()), + // default disabled, enable cat + Arguments.of(enableCat, scopeCat, enabled()), + Arguments.of(enableCat, scopeDog, MeterConfig.disabled()), + Arguments.of(enableCat, scopeDuck, MeterConfig.disabled()), + // default disabled, enable pattern + Arguments.of(enableStartsWithD, scopeCat, MeterConfig.disabled()), + Arguments.of(enableStartsWithD, scopeDog, enabled()), + Arguments.of(enableStartsWithD, scopeDuck, enabled())); + } } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java index 6b1a955bfcf..34315a70da1 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java @@ -10,14 +10,13 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,7 +46,7 @@ public static SdkTracerProviderBuilder builder() { Supplier spanLimitsSupplier, Sampler sampler, List spanProcessors, - Function tracerConfigProvider) { + ScopeConfigurator tracerConfigurator) { this.sharedState = new TracerSharedState( clock, @@ -56,7 +55,7 @@ public static SdkTracerProviderBuilder builder() { spanLimitsSupplier, sampler, spanProcessors, - tracerConfigProvider); + tracerConfigurator); this.tracerSdkComponentRegistry = new ComponentRegistry<>( instrumentationScopeInfo -> new SdkTracer(sharedState, instrumentationScopeInfo)); diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java index 6464709ad3a..8bc43142aca 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java @@ -9,12 +9,14 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; /** Builder of {@link SdkTracerProvider}. */ @@ -28,8 +30,8 @@ public final class SdkTracerProviderBuilder { private Resource resource = Resource.getDefault(); private Supplier spanLimitsSupplier = SpanLimits::getDefault; private Sampler sampler = DEFAULT_SAMPLER; - private Function tracerConfigProvider = - unused -> TracerConfig.defaultConfig(); + private ScopeConfiguratorBuilder tracerConfiguratorBuilder = + TracerConfig.configuratorBuilder(); /** * Assign a {@link Clock}. {@link Clock} will be used each time a {@link @@ -151,9 +153,37 @@ public SdkTracerProviderBuilder addSpanProcessor(SpanProcessor spanProcessor) { return this; } - public SdkTracerProviderBuilder setTracerConfigProvider( - Function tracerConfigProvider) { - this.tracerConfigProvider = tracerConfigProvider; + /** + * Set the tracer configurator, which computes {@link TracerConfig} for each {@link + * InstrumentationScopeInfo}. + * + *

Overrides any matchers added via {@link #addTracerConfiguratorMatcher(Predicate, + * TracerConfig)}. + * + * @see TracerConfig#configuratorBuilder() + */ + public SdkTracerProviderBuilder setTracerConfigurator( + ScopeConfigurator tracerConfigurator) { + this.tracerConfiguratorBuilder = tracerConfigurator.toBuilder(); + return this; + } + + /** + * Adds a condition to the tracer configurator, which computes {@link TracerConfig} for each + * {@link InstrumentationScopeInfo}. + * + *

Applies after any previously added conditions. + * + *

If {@link #setTracerConfigurator(ScopeConfigurator)} was previously called, this condition + * will only be applied if the {@link ScopeConfigurator#apply(Object)} returns null for the + * matched {@link InstrumentationScopeInfo}(s). + * + * @see ScopeConfiguratorBuilder#nameEquals(String) + * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) + */ + public SdkTracerProviderBuilder addTracerConfiguratorMatcher( + Predicate scopeMatcher, TracerConfig tracerConfig) { + this.tracerConfiguratorBuilder.addCondition(scopeMatcher, tracerConfig); return this; } @@ -170,7 +200,7 @@ public SdkTracerProvider build() { spanLimitsSupplier, sampler, spanProcessors, - tracerConfigProvider); + tracerConfiguratorBuilder.build()); } SdkTracerProviderBuilder() {} diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java index a7ffd25d915..e44111d71ad 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java @@ -6,27 +6,55 @@ package io.opentelemetry.sdk.trace; import com.google.auto.value.AutoValue; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import java.util.function.Predicate; import javax.annotation.concurrent.Immutable; +/** + * A collection of configuration options which define the behavior of a {@link Tracer}. + * + * @see SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator) + * @see SdkTracerProviderBuilder#addTracerConfiguratorMatcher(Predicate, TracerConfig) + */ @AutoValue @Immutable public abstract class TracerConfig { private static final TracerConfig DEFAULT_CONFIG = new AutoValue_TracerConfig(/* enabled= */ true); + private static final TracerConfig DISABLED_CONFIG = + new AutoValue_TracerConfig(/* enabled= */ false); + /** Returns a disabled {@link TracerConfig}. */ public static TracerConfig disabled() { - return new AutoValue_TracerConfig(/* enabled= */ false); + return DISABLED_CONFIG; } + /** Returns an enabled {@link TracerConfig}. */ public static TracerConfig enabled() { return DEFAULT_CONFIG; } + /** + * Returns the default {@link TracerConfig}, which is used when no {@link + * SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator)} is set or when the tracer + * configurator returns {@code null} for a {@link InstrumentationScopeInfo}. + */ public static TracerConfig defaultConfig() { return DEFAULT_CONFIG; } + /** + * Create a {@link ScopeConfiguratorBuilder} for configuring {@link + * SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator)}. + */ + public static ScopeConfiguratorBuilder configuratorBuilder() { + return ScopeConfigurator.builder(); + } + TracerConfig() {} /** Returns {@code true} if this tracer is enabled. Defaults to {@code true}. */ diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java index 1681affb9d0..c31e1517e31 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java @@ -8,10 +8,10 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.List; -import java.util.function.Function; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -28,7 +28,7 @@ final class TracerSharedState { private final Supplier spanLimitsSupplier; private final Sampler sampler; private final SpanProcessor activeSpanProcessor; - private final Function tracerConfigProvider; + private final ScopeConfigurator tracerConfigurator; @Nullable private volatile CompletableResultCode shutdownResult = null; @@ -40,7 +40,7 @@ final class TracerSharedState { Supplier spanLimitsSupplier, Sampler sampler, List spanProcessors, - Function tracerConfigProvider) { + ScopeConfigurator tracerConfigurator) { this.clock = clock; this.idGenerator = idGenerator; this.idGeneratorSafeToSkipIdValidation = idGenerator instanceof RandomIdGenerator; @@ -48,7 +48,7 @@ final class TracerSharedState { this.spanLimitsSupplier = spanLimitsSupplier; this.sampler = sampler; activeSpanProcessor = SpanProcessor.composite(spanProcessors); - this.tracerConfigProvider = tracerConfigProvider; + this.tracerConfigurator = tracerConfigurator; } Clock getClock() { @@ -87,7 +87,7 @@ SpanProcessor getActiveSpanProcessor() { } TracerConfig getTracerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - TracerConfig tracerConfig = tracerConfigProvider.apply(instrumentationScopeInfo); + TracerConfig tracerConfig = tracerConfigurator.apply(instrumentationScopeInfo); return tracerConfig == null ? TracerConfig.defaultConfig() : tracerConfig; } diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index abacbab6f29..6db2eccd595 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -5,9 +5,12 @@ package io.opentelemetry.sdk.trace; -import static io.opentelemetry.sdk.common.ScopeConfig.applyToMatching; -import static io.opentelemetry.sdk.common.ScopeConfig.scopeNameEquals; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameMatchesGlob; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.trace.TracerConfig.defaultConfig; +import static io.opentelemetry.sdk.trace.TracerConfig.disabled; +import static io.opentelemetry.sdk.trace.TracerConfig.enabled; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; @@ -15,9 +18,14 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class TracerConfigTest { @@ -28,8 +36,7 @@ void disableScopes() throws InterruptedException { SdkTracerProvider.builder() // Disable tracerB. Since tracers are enabled by default, tracerA and tracerC are // enabled. - .setTracerConfigProvider( - applyToMatching(scopeNameEquals("scopeB"), TracerConfig.disabled())) + .addTracerConfiguratorMatcher(nameEquals("tracerB"), disabled()) .addSpanProcessor(SimpleSpanProcessor.create(exporter)) .build(); @@ -83,4 +90,66 @@ void disableScopes() throws InterruptedException { .hasParentSpanId(parent.getSpanContext().getSpanId()) .hasAttributes(Attributes.builder().put("c", "1").build())); } + + @ParameterizedTest + @MethodSource("tracerConfiguratorArgs") + void tracerConfigurator( + ScopeConfigurator tracerConfigurator, + InstrumentationScopeInfo scope, + TracerConfig expectedTracerConfig) { + TracerConfig tracerConfig = tracerConfigurator.apply(scope); + tracerConfig = tracerConfig == null ? defaultConfig() : tracerConfig; + assertThat(tracerConfig).isEqualTo(expectedTracerConfig); + } + + private static final InstrumentationScopeInfo scopeCat = InstrumentationScopeInfo.create("cat"); + private static final InstrumentationScopeInfo scopeDog = InstrumentationScopeInfo.create("dog"); + private static final InstrumentationScopeInfo scopeDuck = InstrumentationScopeInfo.create("duck"); + + private static Stream tracerConfiguratorArgs() { + ScopeConfigurator defaultConfigurator = + TracerConfig.configuratorBuilder().build(); + ScopeConfigurator disableCat = + TracerConfig.configuratorBuilder() + .addCondition(nameEquals("cat"), disabled()) + // Second matching rule for cat should be ignored + .addCondition(nameEquals("cat"), enabled()) + .build(); + ScopeConfigurator disableStartsWithD = + TracerConfig.configuratorBuilder().addCondition(nameMatchesGlob("d*"), disabled()).build(); + ScopeConfigurator enableCat = + TracerConfig.configuratorBuilder() + .setDefault(disabled()) + .addCondition(nameEquals("cat"), enabled()) + // Second matching rule for cat should be ignored + .addCondition(nameEquals("cat"), disabled()) + .build(); + ScopeConfigurator enableStartsWithD = + TracerConfig.configuratorBuilder() + .setDefault(disabled()) + .addCondition(nameMatchesGlob("d*"), TracerConfig.enabled()) + .build(); + + return Stream.of( + // default + Arguments.of(defaultConfigurator, scopeCat, defaultConfig()), + Arguments.of(defaultConfigurator, scopeDog, defaultConfig()), + Arguments.of(defaultConfigurator, scopeDuck, defaultConfig()), + // default enabled, disable cat + Arguments.of(disableCat, scopeCat, disabled()), + Arguments.of(disableCat, scopeDog, enabled()), + Arguments.of(disableCat, scopeDuck, enabled()), + // default enabled, disable pattern + Arguments.of(disableStartsWithD, scopeCat, enabled()), + Arguments.of(disableStartsWithD, scopeDog, disabled()), + Arguments.of(disableStartsWithD, scopeDuck, disabled()), + // default disabled, enable cat + Arguments.of(enableCat, scopeCat, enabled()), + Arguments.of(enableCat, scopeDog, disabled()), + Arguments.of(enableCat, scopeDuck, disabled()), + // default disabled, enable pattern + Arguments.of(enableStartsWithD, scopeCat, disabled()), + Arguments.of(enableStartsWithD, scopeDog, enabled()), + Arguments.of(enableStartsWithD, scopeDuck, enabled())); + } } From 8273a8ad140ba926200f6c26f0109453bc4f5c62 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 11 Apr 2024 11:57:45 -0500 Subject: [PATCH 4/7] Rename method name to condition --- .../java/io/opentelemetry/sdk/ScopeConfiguratorTest.java | 6 +++--- .../main/java/io/opentelemetry/sdk/logs/LoggerConfig.java | 2 +- .../io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java | 4 ++-- .../java/io/opentelemetry/sdk/logs/LoggerConfigTest.java | 2 +- .../main/java/io/opentelemetry/sdk/metrics/MeterConfig.java | 2 +- .../opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java | 4 ++-- .../java/io/opentelemetry/sdk/metrics/MeterConfigTest.java | 2 +- .../opentelemetry/sdk/trace/SdkTracerProviderBuilder.java | 4 ++-- .../main/java/io/opentelemetry/sdk/trace/TracerConfig.java | 2 +- .../java/io/opentelemetry/sdk/trace/TracerConfigTest.java | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java index d865c2882dc..b5609fa2578 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java @@ -48,17 +48,17 @@ void disableScopeB() { .setTracerProvider( SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .addTracerConfiguratorMatcher(nameEquals("scopeB"), TracerConfig.disabled()) + .addTracerConfiguratorCondition(nameEquals("scopeB"), TracerConfig.disabled()) .build()) .setMeterProvider( SdkMeterProvider.builder() .registerMetricReader(metricReader) - .addMeterConfiguratorMatcher(nameEquals("scopeB"), MeterConfig.disabled()) + .addMeterConfiguratorCondition(nameEquals("scopeB"), MeterConfig.disabled()) .build()) .setLoggerProvider( SdkLoggerProvider.builder() .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .addLoggerConfiguratorMatcher(nameEquals("scopeB"), LoggerConfig.disabled()) + .addLoggerConfiguratorCondition(nameEquals("scopeB"), LoggerConfig.disabled()) .build()) .build(); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java index 3260e099bd7..cee92a76536 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java @@ -17,7 +17,7 @@ * A collection of configuration options which define the behavior of a {@link Logger}. * * @see SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator) - * @see SdkLoggerProviderBuilder#addLoggerConfiguratorMatcher(Predicate, LoggerConfig) + * @see SdkLoggerProviderBuilder#addLoggerConfiguratorCondition(Predicate, LoggerConfig) */ @AutoValue @Immutable diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java index 4f5d60390e1..ccbf5c59ad4 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java @@ -110,7 +110,7 @@ public SdkLoggerProviderBuilder setClock(Clock clock) { * Set the logger configurator, which computes {@link LoggerConfig} for each {@link * InstrumentationScopeInfo}. * - *

Overrides any matchers added via {@link #addLoggerConfiguratorMatcher(Predicate, + *

Overrides any matchers added via {@link #addLoggerConfiguratorCondition(Predicate, * LoggerConfig)}. * * @see LoggerConfig#configuratorBuilder() @@ -134,7 +134,7 @@ public SdkLoggerProviderBuilder setLoggerConfigurator( * @see ScopeConfiguratorBuilder#nameEquals(String) * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) */ - public SdkLoggerProviderBuilder addLoggerConfiguratorMatcher( + public SdkLoggerProviderBuilder addLoggerConfiguratorCondition( Predicate scopeMatcher, LoggerConfig loggerConfig) { this.loggerConfiguratorBuilder.addCondition(scopeMatcher, loggerConfig); return this; diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 01106e58324..7dcb88ee3f3 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -35,7 +35,7 @@ void disableScopes() { SdkLoggerProvider.builder() // Disable loggerB. Since loggers are enabled by default, loggerA and loggerC are // enabled. - .addLoggerConfiguratorMatcher(nameEquals("loggerB"), LoggerConfig.disabled()) + .addLoggerConfiguratorCondition(nameEquals("loggerB"), LoggerConfig.disabled()) .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) .build(); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java index 20f0a0fa972..ec997fe1b4c 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java @@ -17,7 +17,7 @@ * A collection of configuration options which define the behavior of a {@link Meter}. * * @see SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator) - * @see SdkMeterProviderBuilder#addMeterConfiguratorMatcher(Predicate, MeterConfig) + * @see SdkMeterProviderBuilder#addMeterConfiguratorCondition(Predicate, MeterConfig) */ @AutoValue @Immutable diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index ca008fd4bbd..a4c15a4ce04 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -160,7 +160,7 @@ public SdkMeterProviderBuilder registerMetricProducer(MetricProducer metricProdu * Set the meter configurator, which computes {@link MeterConfig} for each {@link * InstrumentationScopeInfo}. * - *

Overrides any matchers added via {@link #addMeterConfiguratorMatcher(Predicate, + *

Overrides any matchers added via {@link #addMeterConfiguratorCondition(Predicate, * MeterConfig)}. * * @see MeterConfig#configuratorBuilder() @@ -184,7 +184,7 @@ public SdkMeterProviderBuilder setMeterConfigurator( * @see ScopeConfiguratorBuilder#nameEquals(String) * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) */ - public SdkMeterProviderBuilder addMeterConfiguratorMatcher( + public SdkMeterProviderBuilder addMeterConfiguratorCondition( Predicate scopeMatcher, MeterConfig meterConfig) { this.meterConfiguratorBuilder.addCondition(scopeMatcher, meterConfig); return this; diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java index 7f329e1451c..d9416ee700b 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -34,7 +34,7 @@ void disableScopes() { SdkMeterProvider meterProvider = SdkMeterProvider.builder() // Disable meterB. Since meters are enabled by default, meterA and meterC are enabled. - .addMeterConfiguratorMatcher(nameEquals("meterB"), disabled()) + .addMeterConfiguratorCondition(nameEquals("meterB"), disabled()) .registerMetricReader(reader) .build(); diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java index 8bc43142aca..5ce53c3b9c0 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java @@ -157,7 +157,7 @@ public SdkTracerProviderBuilder addSpanProcessor(SpanProcessor spanProcessor) { * Set the tracer configurator, which computes {@link TracerConfig} for each {@link * InstrumentationScopeInfo}. * - *

Overrides any matchers added via {@link #addTracerConfiguratorMatcher(Predicate, + *

Overrides any matchers added via {@link #addTracerConfiguratorCondition(Predicate, * TracerConfig)}. * * @see TracerConfig#configuratorBuilder() @@ -181,7 +181,7 @@ public SdkTracerProviderBuilder setTracerConfigurator( * @see ScopeConfiguratorBuilder#nameEquals(String) * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) */ - public SdkTracerProviderBuilder addTracerConfiguratorMatcher( + public SdkTracerProviderBuilder addTracerConfiguratorCondition( Predicate scopeMatcher, TracerConfig tracerConfig) { this.tracerConfiguratorBuilder.addCondition(scopeMatcher, tracerConfig); return this; diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java index e44111d71ad..ca9becd1e62 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java @@ -17,7 +17,7 @@ * A collection of configuration options which define the behavior of a {@link Tracer}. * * @see SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator) - * @see SdkTracerProviderBuilder#addTracerConfiguratorMatcher(Predicate, TracerConfig) + * @see SdkTracerProviderBuilder#addTracerConfiguratorCondition(Predicate, TracerConfig) */ @AutoValue @Immutable diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index 6db2eccd595..c91d2867cdf 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -36,7 +36,7 @@ void disableScopes() throws InterruptedException { SdkTracerProvider.builder() // Disable tracerB. Since tracers are enabled by default, tracerA and tracerC are // enabled. - .addTracerConfiguratorMatcher(nameEquals("tracerB"), disabled()) + .addTracerConfiguratorCondition(nameEquals("tracerB"), disabled()) .addSpanProcessor(SimpleSpanProcessor.create(exporter)) .build(); From 786c20276b97f2403ac12946c584f300e8b59f1b Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 17 Apr 2024 14:52:38 -0500 Subject: [PATCH 5/7] PR feedback --- .../opentelemetry-sdk-logs.txt | 2 +- .../opentelemetry-sdk-metrics.txt | 2 +- .../opentelemetry-sdk-trace.txt | 2 +- .../sdk/ScopeConfiguratorTest.java | 73 ++++++++++--------- .../sdk/internal/GlobUtilTest.java | 10 +++ .../sdk/logs/LoggerSharedState.java | 12 +-- .../io/opentelemetry/sdk/logs/SdkLogger.java | 12 +-- .../sdk/logs/SdkLoggerProvider.java | 17 ++++- .../sdk/logs/LoggerSharedStateTest.java | 6 +- .../opentelemetry/sdk/logs/SdkLoggerTest.java | 3 +- .../opentelemetry/sdk/metrics/SdkMeter.java | 38 +++++----- .../sdk/metrics/SdkMeterProvider.java | 19 ++++- .../state/MeterProviderSharedState.java | 21 +----- .../sdk/metrics/InstrumentBuilderTest.java | 6 +- .../io/opentelemetry/sdk/trace/SdkTracer.java | 7 +- .../sdk/trace/SdkTracerProvider.java | 22 ++++-- .../sdk/trace/TracerSharedState.java | 12 +-- 17 files changed, 134 insertions(+), 130 deletions(-) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt index 04564ce6825..bb7e7776887 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt @@ -9,5 +9,5 @@ Comparing source compatibility of against +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder addLoggerConfiguratorMatcher(java.util.function.Predicate, io.opentelemetry.sdk.logs.LoggerConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder addLoggerConfiguratorCondition(java.util.function.Predicate, io.opentelemetry.sdk.logs.LoggerConfig) +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder setLoggerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt index aaff534ebbe..3254be124bc 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt @@ -9,5 +9,5 @@ Comparing source compatibility of against +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder addMeterConfiguratorMatcher(java.util.function.Predicate, io.opentelemetry.sdk.metrics.MeterConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder addMeterConfiguratorCondition(java.util.function.Predicate, io.opentelemetry.sdk.metrics.MeterConfig) +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder setMeterConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt index 4d6ac336508..04760e6e26b 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt @@ -1,7 +1,7 @@ Comparing source compatibility of against *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProviderBuilder (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder addTracerConfiguratorMatcher(java.util.function.Predicate, io.opentelemetry.sdk.trace.TracerConfig) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder addTracerConfiguratorCondition(java.util.function.Predicate, io.opentelemetry.sdk.trace.TracerConfig) +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setTracerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) +++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.trace.TracerConfig (not serializable) +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java index b5609fa2578..7407f76d54e 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java @@ -40,6 +40,10 @@ class ScopeConfiguratorTest { private final InMemoryMetricReader metricReader = InMemoryMetricReader.create(); private final InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + private static final InstrumentationScopeInfo scopeA = InstrumentationScopeInfo.create("scopeA"); + private static final InstrumentationScopeInfo scopeB = InstrumentationScopeInfo.create("scopeB"); + private static final InstrumentationScopeInfo scopeC = InstrumentationScopeInfo.create("scopeC"); + /** Disable "scopeB". All other scopes are enabled by default. */ @Test void disableScopeB() { @@ -48,17 +52,20 @@ void disableScopeB() { .setTracerProvider( SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .addTracerConfiguratorCondition(nameEquals("scopeB"), TracerConfig.disabled()) + .addTracerConfiguratorCondition( + nameEquals(scopeB.getName()), TracerConfig.disabled()) .build()) .setMeterProvider( SdkMeterProvider.builder() .registerMetricReader(metricReader) - .addMeterConfiguratorCondition(nameEquals("scopeB"), MeterConfig.disabled()) + .addMeterConfiguratorCondition( + nameEquals(scopeB.getName()), MeterConfig.disabled()) .build()) .setLoggerProvider( SdkLoggerProvider.builder() .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .addLoggerConfiguratorCondition(nameEquals("scopeB"), LoggerConfig.disabled()) + .addLoggerConfiguratorCondition( + nameEquals(scopeB.getName()), LoggerConfig.disabled()) .build()) .build(); @@ -72,9 +79,9 @@ void disableScopeB() { Map> spansByScope = spans.stream() .collect(Collectors.groupingBy(SpanData::getInstrumentationScopeInfo)); - assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1); - assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull(); - assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); + assertThat(spansByScope.get(scopeA)).hasSize(1); + assertThat(spansByScope.get(scopeB)).isNull(); + assertThat(spansByScope.get(scopeC)).hasSize(1); }); assertThat(metricReader.collectAllMetrics()) .satisfies( @@ -82,9 +89,9 @@ void disableScopeB() { Map> metricsByScope = metrics.stream() .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull(); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); + assertThat(metricsByScope.get(scopeA)).hasSize(1); + assertThat(metricsByScope.get(scopeB)).isNull(); + assertThat(metricsByScope.get(scopeC)).hasSize(1); }); assertThat(logRecordExporter.getFinishedLogRecordItems()) .satisfies( @@ -92,9 +99,9 @@ void disableScopeB() { Map> logsByScope = logs.stream() .collect(Collectors.groupingBy(LogRecordData::getInstrumentationScopeInfo)); - assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1); - assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull(); - assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1); + assertThat(logsByScope.get(scopeA)).hasSize(1); + assertThat(logsByScope.get(scopeB)).isNull(); + assertThat(logsByScope.get(scopeC)).hasSize(1); }); } @@ -109,7 +116,7 @@ void disableAllScopesExceptB() { .setTracerConfigurator( TracerConfig.configuratorBuilder() .setDefault(TracerConfig.disabled()) - .addCondition(nameEquals("scopeB"), TracerConfig.enabled()) + .addCondition(nameEquals(scopeB.getName()), TracerConfig.enabled()) .build()) .build()) .setMeterProvider( @@ -118,7 +125,7 @@ void disableAllScopesExceptB() { .setMeterConfigurator( MeterConfig.configuratorBuilder() .setDefault(MeterConfig.disabled()) - .addCondition(nameEquals("scopeB"), MeterConfig.enabled()) + .addCondition(nameEquals(scopeB.getName()), MeterConfig.enabled()) .build()) .build()) .setLoggerProvider( @@ -127,7 +134,7 @@ void disableAllScopesExceptB() { .setLoggerConfigurator( LoggerConfig.configuratorBuilder() .setDefault(LoggerConfig.disabled()) - .addCondition(nameEquals("scopeB"), LoggerConfig.enabled()) + .addCondition(nameEquals(scopeB.getName()), LoggerConfig.enabled()) .build()) .build()) .build(); @@ -142,9 +149,9 @@ void disableAllScopesExceptB() { Map> spansByScope = spans.stream() .collect(Collectors.groupingBy(SpanData::getInstrumentationScopeInfo)); - assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeA"))).isNull(); - assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeB"))).hasSize(1); - assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeC"))).isNull(); + assertThat(spansByScope.get(scopeA)).isNull(); + assertThat(spansByScope.get(scopeB)).hasSize(1); + assertThat(spansByScope.get(scopeC)).isNull(); }); assertThat(metricReader.collectAllMetrics()) .satisfies( @@ -152,9 +159,9 @@ void disableAllScopesExceptB() { Map> metricsByScope = metrics.stream() .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeA"))).isNull(); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeB"))).hasSize(1); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("scopeC"))).isNull(); + assertThat(metricsByScope.get(scopeA)).isNull(); + assertThat(metricsByScope.get(scopeB)).hasSize(1); + assertThat(metricsByScope.get(scopeC)).isNull(); }); assertThat(logRecordExporter.getFinishedLogRecordItems()) .satisfies( @@ -162,9 +169,9 @@ void disableAllScopesExceptB() { Map> logsByScope = logs.stream() .collect(Collectors.groupingBy(LogRecordData::getInstrumentationScopeInfo)); - assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeA"))).isNull(); - assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeB"))).hasSize(1); - assertThat(logsByScope.get(InstrumentationScopeInfo.create("scopeC"))).isNull(); + assertThat(logsByScope.get(scopeA)).isNull(); + assertThat(logsByScope.get(scopeB)).hasSize(1); + assertThat(logsByScope.get(scopeC)).isNull(); }); } @@ -174,25 +181,25 @@ void disableAllScopesExceptB() { */ private static void simulateInstrumentation(OpenTelemetry openTelemetry) { // Start scopeA - Tracer scopeATracer = openTelemetry.getTracer("scopeA"); - Meter scopeAMeter = openTelemetry.getMeter("scopeA"); - Logger scopeALogger = openTelemetry.getLogsBridge().get("scopeA"); + Tracer scopeATracer = openTelemetry.getTracer(scopeA.getName()); + Meter scopeAMeter = openTelemetry.getMeter(scopeA.getName()); + Logger scopeALogger = openTelemetry.getLogsBridge().get(scopeA.getName()); Span spanA = scopeATracer.spanBuilder("spanA").startSpan(); try (Scope spanAScope = spanA.makeCurrent()) { scopeALogger.logRecordBuilder().setBody("scopeA log message").emit(); // Start scopeB - Tracer scopeBTracer = openTelemetry.getTracer("scopeB"); - Meter scopeBMeter = openTelemetry.getMeter("scopeB"); - Logger scopeBLogger = openTelemetry.getLogsBridge().get("scopeB"); + Tracer scopeBTracer = openTelemetry.getTracer(scopeB.getName()); + Meter scopeBMeter = openTelemetry.getMeter(scopeB.getName()); + Logger scopeBLogger = openTelemetry.getLogsBridge().get(scopeB.getName()); Span spanB = scopeBTracer.spanBuilder("spanB").startSpan(); try (Scope spanBScope = spanB.makeCurrent()) { scopeBLogger.logRecordBuilder().setBody("scopeB log message").emit(); // Start scopeC - Tracer scopeCTracer = openTelemetry.getTracer("scopeC"); - Meter scopeCMeter = openTelemetry.getMeter("scopeC"); - Logger scopeCLogger = openTelemetry.getLogsBridge().get("scopeC"); + Tracer scopeCTracer = openTelemetry.getTracer(scopeC.getName()); + Meter scopeCMeter = openTelemetry.getMeter(scopeC.getName()); + Logger scopeCLogger = openTelemetry.getLogsBridge().get(scopeC.getName()); Span spanC = scopeCTracer.spanBuilder("spanC").startSpan(); try (Scope spanCScope = spanB.makeCurrent()) { scopeCLogger.logRecordBuilder().setBody("scopeC log message").emit(); diff --git a/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java b/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java index dca7860921c..a26928f34bc 100644 --- a/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java +++ b/sdk/common/src/test/java/io/opentelemetry/sdk/internal/GlobUtilTest.java @@ -25,10 +25,20 @@ void matchesName() { assertThat(toGlobPatternPredicate("*").test("bar")).isTrue(); assertThat(toGlobPatternPredicate("*").test("baz")).isTrue(); assertThat(toGlobPatternPredicate("*").test("foo.bar.baz")).isTrue(); + assertThat(toGlobPatternPredicate("*").test(null)).isTrue(); + assertThat(toGlobPatternPredicate("*").test("")).isTrue(); assertThat(toGlobPatternPredicate("fo*").test("fo")).isTrue(); assertThat(toGlobPatternPredicate("fo*").test("foo")).isTrue(); assertThat(toGlobPatternPredicate("fo*").test("fooo")).isTrue(); assertThat(toGlobPatternPredicate("fo*").test("foo.bar.baz")).isTrue(); + assertThat(toGlobPatternPredicate("*bar").test("sandbar")).isTrue(); + assertThat(toGlobPatternPredicate("fo*b*").test("foobar")).isTrue(); + assertThat(toGlobPatternPredicate("fo*b*").test("foob")).isTrue(); + assertThat(toGlobPatternPredicate("fo*b*").test("foo bar")).isTrue(); + assertThat(toGlobPatternPredicate("fo? b??").test("foo bar")).isTrue(); + assertThat(toGlobPatternPredicate("fo? b??").test("fooo bar")).isFalse(); + assertThat(toGlobPatternPredicate("fo* ba?").test("foo is not bar")).isTrue(); + assertThat(toGlobPatternPredicate("fo? b*").test("fox beetles for lunch")).isTrue(); assertThat(toGlobPatternPredicate("f()[]$^.{}|").test("f()[]$^.{}|")).isTrue(); assertThat(toGlobPatternPredicate("f()[]$^.{}|?").test("f()[]$^.{}|o")).isTrue(); assertThat(toGlobPatternPredicate("f()[]$^.{}|*").test("f()[]$^.{}|ooo")).isTrue(); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java index 4b46f4cfc71..768871e1e57 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerSharedState.java @@ -7,8 +7,6 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.resources.Resource; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -23,20 +21,17 @@ final class LoggerSharedState { private final Supplier logLimitsSupplier; private final LogRecordProcessor logRecordProcessor; private final Clock clock; - private final ScopeConfigurator loggerConfigurator; @Nullable private volatile CompletableResultCode shutdownResult = null; LoggerSharedState( Resource resource, Supplier logLimitsSupplier, LogRecordProcessor logRecordProcessor, - Clock clock, - ScopeConfigurator loggerConfigurator) { + Clock clock) { this.resource = resource; this.logLimitsSupplier = logLimitsSupplier; this.logRecordProcessor = logRecordProcessor; this.clock = clock; - this.loggerConfigurator = loggerConfigurator; } Resource getResource() { @@ -55,11 +50,6 @@ Clock getClock() { return clock; } - LoggerConfig getLoggerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - LoggerConfig loggerConfig = loggerConfigurator.apply(instrumentationScopeInfo); - return loggerConfig == null ? LoggerConfig.defaultConfig() : loggerConfig; - } - boolean hasBeenShutdown() { return shutdownResult != null; } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index 2aa9c35feb4..ce855ab0818 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -20,18 +20,20 @@ final class SdkLogger implements Logger { private final LoggerConfig loggerConfig; SdkLogger( - LoggerSharedState loggerSharedState, InstrumentationScopeInfo instrumentationScopeInfo) { + LoggerSharedState loggerSharedState, + InstrumentationScopeInfo instrumentationScopeInfo, + LoggerConfig loggerConfig) { this.loggerSharedState = loggerSharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; - this.loggerConfig = loggerSharedState.getLoggerConfig(instrumentationScopeInfo); + this.loggerConfig = loggerConfig; } @Override public LogRecordBuilder logRecordBuilder() { - if (!loggerConfig.isEnabled()) { - return NOOP_LOGGER.logRecordBuilder(); + if (loggerConfig.isEnabled()) { + return new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); } - return new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); + return NOOP_LOGGER.logRecordBuilder(); } // VisibleForTesting diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java index 1037d77f0a3..3d13782f814 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; @@ -34,6 +35,7 @@ public final class SdkLoggerProvider implements LoggerProvider, Closeable { private final LoggerSharedState sharedState; private final ComponentRegistry loggerComponentRegistry; + private final ScopeConfigurator loggerConfigurator; private final boolean isNoopLogRecordProcessor; /** @@ -53,14 +55,23 @@ public static SdkLoggerProviderBuilder builder() { ScopeConfigurator loggerConfigurator) { LogRecordProcessor logRecordProcessor = LogRecordProcessor.composite(processors); this.sharedState = - new LoggerSharedState( - resource, logLimitsSupplier, logRecordProcessor, clock, loggerConfigurator); + new LoggerSharedState(resource, logLimitsSupplier, logRecordProcessor, clock); this.loggerComponentRegistry = new ComponentRegistry<>( - instrumentationScopeInfo -> new SdkLogger(sharedState, instrumentationScopeInfo)); + instrumentationScopeInfo -> + new SdkLogger( + sharedState, + instrumentationScopeInfo, + getLoggerConfig(instrumentationScopeInfo))); + this.loggerConfigurator = loggerConfigurator; this.isNoopLogRecordProcessor = logRecordProcessor instanceof NoopLogRecordProcessor; } + private LoggerConfig getLoggerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { + LoggerConfig loggerConfig = loggerConfigurator.apply(instrumentationScopeInfo); + return loggerConfig == null ? LoggerConfig.defaultConfig() : loggerConfig; + } + @Override public Logger get(String instrumentationScopeName) { return loggerComponentRegistry.get( diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java index b9b4d5e4f74..29a3a846a56 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerSharedStateTest.java @@ -24,11 +24,7 @@ void shutdown() { when(logRecordProcessor.shutdown()).thenReturn(code); LoggerSharedState state = new LoggerSharedState( - Resource.empty(), - LogLimits::getDefault, - logRecordProcessor, - Clock.getDefault(), - unused -> LoggerConfig.defaultConfig()); + Resource.empty(), LogLimits::getDefault, logRecordProcessor, Clock.getDefault()); state.shutdown(); state.shutdown(); verify(logRecordProcessor, times(1)).shutdown(); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index b290de37c54..550c32e8370 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -43,9 +43,8 @@ void logRecordBuilder() { when(state.getResource()).thenReturn(Resource.getDefault()); when(state.getLogRecordProcessor()).thenReturn(logRecordProcessor); when(state.getClock()).thenReturn(clock); - when(state.getLoggerConfig(any())).thenReturn(LoggerConfig.defaultConfig()); - SdkLogger logger = new SdkLogger(state, info); + SdkLogger logger = new SdkLogger(state, info, LoggerConfig.defaultConfig()); LogRecordBuilder logRecordBuilder = logger.logRecordBuilder(); logRecordBuilder.setBody("foo"); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java index d88139a032d..752e4e73a4d 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java @@ -60,11 +60,12 @@ final class SdkMeter implements Meter { SdkMeter( MeterProviderSharedState meterProviderSharedState, InstrumentationScopeInfo instrumentationScopeInfo, - List registeredReaders) { + List registeredReaders, + MeterConfig meterConfig) { this.instrumentationScopeInfo = instrumentationScopeInfo; this.meterProviderSharedState = meterProviderSharedState; this.meterSharedState = MeterSharedState.create(instrumentationScopeInfo, registeredReaders); - this.meterConfig = meterProviderSharedState.getMeterConfig(instrumentationScopeInfo); + this.meterConfig = meterConfig; } // Visible for testing @@ -84,34 +85,32 @@ void resetForTest() { @Override public LongCounterBuilder counterBuilder(String name) { - return !meterConfig.isEnabled() || !checkValidInstrumentName(name) - ? NOOP_METER.counterBuilder(NOOP_INSTRUMENT_NAME) - : new SdkLongCounter.SdkLongCounterBuilder( - meterProviderSharedState, meterSharedState, name); + return meterConfig.isEnabled() && checkValidInstrumentName(name) + ? new SdkLongCounter.SdkLongCounterBuilder(meterProviderSharedState, meterSharedState, name) + : NOOP_METER.counterBuilder(NOOP_INSTRUMENT_NAME); } @Override public LongUpDownCounterBuilder upDownCounterBuilder(String name) { - return !meterConfig.isEnabled() || !checkValidInstrumentName(name) - ? NOOP_METER.upDownCounterBuilder(NOOP_INSTRUMENT_NAME) - : new SdkLongUpDownCounter.SdkLongUpDownCounterBuilder( - meterProviderSharedState, meterSharedState, name); + return meterConfig.isEnabled() && checkValidInstrumentName(name) + ? new SdkLongUpDownCounter.SdkLongUpDownCounterBuilder( + meterProviderSharedState, meterSharedState, name) + : NOOP_METER.upDownCounterBuilder(NOOP_INSTRUMENT_NAME); } @Override public DoubleHistogramBuilder histogramBuilder(String name) { - return !meterConfig.isEnabled() || !checkValidInstrumentName(name) - ? NOOP_METER.histogramBuilder(NOOP_INSTRUMENT_NAME) - : new SdkDoubleHistogram.SdkDoubleHistogramBuilder( - meterProviderSharedState, meterSharedState, name); + return meterConfig.isEnabled() && checkValidInstrumentName(name) + ? new SdkDoubleHistogram.SdkDoubleHistogramBuilder( + meterProviderSharedState, meterSharedState, name) + : NOOP_METER.histogramBuilder(NOOP_INSTRUMENT_NAME); } @Override public DoubleGaugeBuilder gaugeBuilder(String name) { - return !meterConfig.isEnabled() || !checkValidInstrumentName(name) - ? NOOP_METER.gaugeBuilder(NOOP_INSTRUMENT_NAME) - : new SdkDoubleGauge.SdkDoubleGaugeBuilder( - meterProviderSharedState, meterSharedState, name); + return meterConfig.isEnabled() && checkValidInstrumentName(name) + ? new SdkDoubleGauge.SdkDoubleGaugeBuilder(meterProviderSharedState, meterSharedState, name) + : NOOP_METER.gaugeBuilder(NOOP_INSTRUMENT_NAME); } @Override @@ -119,6 +118,9 @@ public BatchCallback batchCallback( Runnable callback, ObservableMeasurement observableMeasurement, ObservableMeasurement... additionalMeasurements) { + if (!meterConfig.isEnabled()) { + return NOOP_METER.batchCallback(callback, observableMeasurement, additionalMeasurements); + } Set measurements = new HashSet<>(); measurements.add(observableMeasurement); Collections.addAll(measurements, additionalMeasurements); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index 8fe8f1630c8..fa9911c576e 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.metrics.data.MetricData; @@ -50,6 +51,7 @@ public final class SdkMeterProvider implements MeterProvider, Closeable { private final List metricProducers; private final MeterProviderSharedState sharedState; private final ComponentRegistry registry; + private final ScopeConfigurator meterConfigurator; private final AtomicBoolean isClosed = new AtomicBoolean(false); /** Returns a new {@link SdkMeterProviderBuilder} for {@link SdkMeterProvider}. */ @@ -64,7 +66,7 @@ public static SdkMeterProviderBuilder builder() { Clock clock, Resource resource, ExemplarFilter exemplarFilter, - ScopeConfigurator meterConfigProvider) { + ScopeConfigurator meterConfigurator) { long startEpochNanos = clock.now(); this.registeredViews = registeredViews; this.registeredReaders = @@ -77,12 +79,16 @@ public static SdkMeterProviderBuilder builder() { .collect(toList()); this.metricProducers = metricProducers; this.sharedState = - MeterProviderSharedState.create( - clock, resource, exemplarFilter, startEpochNanos, meterConfigProvider); + MeterProviderSharedState.create(clock, resource, exemplarFilter, startEpochNanos); this.registry = new ComponentRegistry<>( instrumentationLibraryInfo -> - new SdkMeter(sharedState, instrumentationLibraryInfo, registeredReaders)); + new SdkMeter( + sharedState, + instrumentationLibraryInfo, + registeredReaders, + getMeterConfig(instrumentationLibraryInfo))); + this.meterConfigurator = meterConfigurator; for (RegisteredReader registeredReader : registeredReaders) { List readerMetricProducers = new ArrayList<>(metricProducers); readerMetricProducers.add(new LeasedMetricProducer(registry, sharedState, registeredReader)); @@ -93,6 +99,11 @@ public static SdkMeterProviderBuilder builder() { } } + private MeterConfig getMeterConfig(InstrumentationScopeInfo instrumentationScopeInfo) { + MeterConfig meterConfig = meterConfigurator.apply(instrumentationScopeInfo); + return meterConfig == null ? MeterConfig.defaultConfig() : meterConfig; + } + @Override public MeterBuilder meterBuilder(String instrumentationScopeName) { if (registeredReaders.isEmpty()) { diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java index 20fa5912e79..8f3647c6d46 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java @@ -7,14 +7,9 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.sdk.common.Clock; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.metrics.MeterConfig; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.resources.Resource; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; import javax.annotation.concurrent.Immutable; /** @@ -27,18 +22,10 @@ @Immutable public abstract class MeterProviderSharedState { - private final AtomicReference> meterConfigProviderRef = - new AtomicReference<>(); - public static MeterProviderSharedState create( - Clock clock, - Resource resource, - ExemplarFilter exemplarFilter, - long startEpochNanos, - ScopeConfigurator meterConfigurator) { + Clock clock, Resource resource, ExemplarFilter exemplarFilter, long startEpochNanos) { MeterProviderSharedState sharedState = new AutoValue_MeterProviderSharedState(clock, resource, startEpochNanos, exemplarFilter); - sharedState.meterConfigProviderRef.set(meterConfigurator); return sharedState; } @@ -55,10 +42,4 @@ public static MeterProviderSharedState create( /** Returns the {@link ExemplarFilter} for remembering synchronous measurements. */ abstract ExemplarFilter getExemplarFilter(); - - public MeterConfig getMeterConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - MeterConfig meterConfig = - Objects.requireNonNull(meterConfigProviderRef.get()).apply(instrumentationScopeInfo); - return meterConfig == null ? MeterConfig.defaultConfig() : meterConfig; - } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java index f4f57eb1bb2..a351c95d0e6 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java @@ -21,11 +21,7 @@ class InstrumentBuilderTest { public static final MeterProviderSharedState PROVIDER_SHARED_STATE = MeterProviderSharedState.create( - TestClock.create(), - Resource.getDefault(), - ExemplarFilter.alwaysOff(), - 0, - MeterConfig.configuratorBuilder().build()); + TestClock.create(), Resource.getDefault(), ExemplarFilter.alwaysOff(), 0); static final InstrumentationScopeInfo SCOPE = InstrumentationScopeInfo.create("scope-name"); public static final MeterSharedState METER_SHARED_STATE = MeterSharedState.create(SCOPE, Collections.emptyList()); diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java index c19350a88d1..360ab926317 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java @@ -19,10 +19,13 @@ final class SdkTracer implements Tracer { private final InstrumentationScopeInfo instrumentationScopeInfo; private final TracerConfig tracerConfig; - SdkTracer(TracerSharedState sharedState, InstrumentationScopeInfo instrumentationScopeInfo) { + SdkTracer( + TracerSharedState sharedState, + InstrumentationScopeInfo instrumentationScopeInfo, + TracerConfig tracerConfig) { this.sharedState = sharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; - this.tracerConfig = sharedState.getTracerConfig(instrumentationScopeInfo); + this.tracerConfig = tracerConfig; } @Override diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java index 34315a70da1..cdcc13098bd 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; @@ -28,6 +29,7 @@ public final class SdkTracerProvider implements TracerProvider, Closeable { static final String DEFAULT_TRACER_NAME = ""; private final TracerSharedState sharedState; private final ComponentRegistry tracerSdkComponentRegistry; + private final ScopeConfigurator tracerConfigurator; /** * Returns a new {@link SdkTracerProviderBuilder} for {@link SdkTracerProvider}. @@ -49,16 +51,20 @@ public static SdkTracerProviderBuilder builder() { ScopeConfigurator tracerConfigurator) { this.sharedState = new TracerSharedState( - clock, - idsGenerator, - resource, - spanLimitsSupplier, - sampler, - spanProcessors, - tracerConfigurator); + clock, idsGenerator, resource, spanLimitsSupplier, sampler, spanProcessors); this.tracerSdkComponentRegistry = new ComponentRegistry<>( - instrumentationScopeInfo -> new SdkTracer(sharedState, instrumentationScopeInfo)); + instrumentationScopeInfo -> + new SdkTracer( + sharedState, + instrumentationScopeInfo, + getTracerConfig(instrumentationScopeInfo))); + this.tracerConfigurator = tracerConfigurator; + } + + private TracerConfig getTracerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { + TracerConfig tracerConfig = tracerConfigurator.apply(instrumentationScopeInfo); + return tracerConfig == null ? TracerConfig.defaultConfig() : tracerConfig; } @Override diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java index c31e1517e31..b1f06d1bc19 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java @@ -7,8 +7,6 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.List; @@ -28,7 +26,6 @@ final class TracerSharedState { private final Supplier spanLimitsSupplier; private final Sampler sampler; private final SpanProcessor activeSpanProcessor; - private final ScopeConfigurator tracerConfigurator; @Nullable private volatile CompletableResultCode shutdownResult = null; @@ -39,8 +36,7 @@ final class TracerSharedState { Resource resource, Supplier spanLimitsSupplier, Sampler sampler, - List spanProcessors, - ScopeConfigurator tracerConfigurator) { + List spanProcessors) { this.clock = clock; this.idGenerator = idGenerator; this.idGeneratorSafeToSkipIdValidation = idGenerator instanceof RandomIdGenerator; @@ -48,7 +44,6 @@ final class TracerSharedState { this.spanLimitsSupplier = spanLimitsSupplier; this.sampler = sampler; activeSpanProcessor = SpanProcessor.composite(spanProcessors); - this.tracerConfigurator = tracerConfigurator; } Clock getClock() { @@ -86,11 +81,6 @@ SpanProcessor getActiveSpanProcessor() { return activeSpanProcessor; } - TracerConfig getTracerConfig(InstrumentationScopeInfo instrumentationScopeInfo) { - TracerConfig tracerConfig = tracerConfigurator.apply(instrumentationScopeInfo); - return tracerConfig == null ? TracerConfig.defaultConfig() : tracerConfig; - } - /** * Returns {@code true} if tracing has been shut down. * From 6e86e0dcc12b440cbe6576e71f1d03fb2db45c18 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 17 Apr 2024 14:53:46 -0500 Subject: [PATCH 6/7] Remove used annotation --- .../main/java/io/opentelemetry/sdk/trace/TracerSharedState.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java index b1f06d1bc19..3d07a2853f8 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerSharedState.java @@ -29,7 +29,6 @@ final class TracerSharedState { @Nullable private volatile CompletableResultCode shutdownResult = null; - @SuppressWarnings("NonApiType") TracerSharedState( Clock clock, IdGenerator idGenerator, From 171438702c56d89a8af1568d28885649bc547d03 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 18 Apr 2024 10:34:31 -0500 Subject: [PATCH 7/7] Move all public APIs to internal --- .../opentelemetry-sdk-common.txt | 19 +--- .../opentelemetry-sdk-logs.txt | 13 +-- .../opentelemetry-sdk-metrics.txt | 13 +-- .../opentelemetry-sdk-trace.txt | 12 --- .../sdk/ScopeConfiguratorTest.java | 87 +++++++++++-------- .../ScopeConfigurator.java | 6 +- .../ScopeConfiguratorBuilder.java | 7 +- .../io/opentelemetry/sdk/logs/SdkLogger.java | 1 + .../sdk/logs/SdkLoggerProvider.java | 3 +- .../sdk/logs/SdkLoggerProviderBuilder.java | 9 +- .../sdk/logs/{ => internal}/LoggerConfig.java | 19 ++-- .../logs/internal/SdkLoggerProviderUtil.java | 58 +++++++++++++ .../sdk/logs/LoggerConfigTest.java | 11 +-- .../opentelemetry/sdk/logs/SdkLoggerTest.java | 1 + .../opentelemetry/sdk/metrics/SdkMeter.java | 1 + .../sdk/metrics/SdkMeterProvider.java | 3 +- .../sdk/metrics/SdkMeterProviderBuilder.java | 10 +-- .../metrics/{ => internal}/MeterConfig.java | 19 ++-- .../internal/SdkMeterProviderUtil.java | 42 ++++++++- .../sdk/metrics/MeterConfigTest.java | 13 +-- .../io/opentelemetry/sdk/trace/SdkTracer.java | 1 + .../sdk/trace/SdkTracerProvider.java | 3 +- .../sdk/trace/SdkTracerProviderBuilder.java | 9 +- .../trace/internal/SdkTracerProviderUtil.java | 58 +++++++++++++ .../trace/{ => internal}/TracerConfig.java | 19 ++-- .../sdk/trace/TracerConfigTest.java | 13 +-- 26 files changed, 294 insertions(+), 156 deletions(-) rename sdk/common/src/main/java/io/opentelemetry/sdk/{common => internal}/ScopeConfigurator.java (80%) rename sdk/common/src/main/java/io/opentelemetry/sdk/{common => internal}/ScopeConfiguratorBuilder.java (94%) rename sdk/logs/src/main/java/io/opentelemetry/sdk/logs/{ => internal}/LoggerConfig.java (68%) create mode 100644 sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkLoggerProviderUtil.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{ => internal}/MeterConfig.java (68%) create mode 100644 sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/SdkTracerProviderUtil.java rename sdk/trace/src/main/java/io/opentelemetry/sdk/trace/{ => internal}/TracerConfig.java (68%) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt index 8a82b0ed757..df26146497b 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt @@ -1,19 +1,2 @@ Comparing source compatibility of against -+++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.common.ScopeConfigurator (not serializable) - +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. - GENERIC TEMPLATES: +++ T:java.lang.Object - +++ NEW INTERFACE: java.util.function.Function - +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder builder() - GENERIC TEMPLATES: +++ T:java.lang.Object - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder toBuilder() - +++ NEW ANNOTATION: java.lang.FunctionalInterface -+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder (not serializable) - +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. - GENERIC TEMPLATES: +++ T:java.lang.Object - +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder addCondition(java.util.function.Predicate, java.lang.Object) - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfigurator build() - +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate nameEquals(java.lang.String) - +++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate nameMatchesGlob(java.lang.String) - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder setDefault(java.lang.Object) +No changes. \ No newline at end of file diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt index bb7e7776887..df26146497b 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt @@ -1,13 +1,2 @@ Comparing source compatibility of against -+++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.logs.LoggerConfig (not serializable) - +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. - +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder configuratorBuilder() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig defaultConfig() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig disabled() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.logs.LoggerConfig enabled() - +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder addLoggerConfiguratorCondition(java.util.function.Predicate, io.opentelemetry.sdk.logs.LoggerConfig) - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder setLoggerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) +No changes. \ No newline at end of file diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt index 3254be124bc..df26146497b 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt @@ -1,13 +1,2 @@ Comparing source compatibility of against -+++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.metrics.MeterConfig (not serializable) - +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. - +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder configuratorBuilder() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig defaultConfig() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig disabled() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.MeterConfig enabled() - +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder addMeterConfiguratorCondition(java.util.function.Predicate, io.opentelemetry.sdk.metrics.MeterConfig) - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder setMeterConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) +No changes. \ No newline at end of file diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt index 436b8debeb2..722ee3a950f 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt @@ -2,15 +2,3 @@ Comparing source compatibility of against *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.trace.ReadableSpan (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.common.Attributes getAttributes() -*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProviderBuilder (not serializable) - === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder addTracerConfiguratorCondition(java.util.function.Predicate, io.opentelemetry.sdk.trace.TracerConfig) - +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setTracerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator) -+++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.trace.TracerConfig (not serializable) - +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. - +++ NEW SUPERCLASS: java.lang.Object - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder configuratorBuilder() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig defaultConfig() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig disabled() - +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.TracerConfig enabled() - +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) boolean isEnabled() diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java index 7407f76d54e..0055df8ce7f 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/ScopeConfiguratorTest.java @@ -5,7 +5,7 @@ package io.opentelemetry.sdk; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; @@ -15,20 +15,26 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.logs.LoggerConfig; import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import io.opentelemetry.sdk.metrics.MeterConfig; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; +import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil; import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; +import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.TracerConfig; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import io.opentelemetry.sdk.trace.internal.SdkTracerProviderUtil; +import io.opentelemetry.sdk.trace.internal.TracerConfig; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -47,25 +53,27 @@ class ScopeConfiguratorTest { /** Disable "scopeB". All other scopes are enabled by default. */ @Test void disableScopeB() { + // Configuration ergonomics will improve after APIs stabilize + SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder(); + SdkTracerProviderUtil.addTracerConfiguratorCondition( + tracerProviderBuilder, nameEquals(scopeB.getName()), TracerConfig.disabled()); + SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder(); + SdkMeterProviderUtil.addMeterConfiguratorCondition( + meterProviderBuilder, nameEquals(scopeB.getName()), MeterConfig.disabled()); + SdkLoggerProviderBuilder loggerProviderBuilder = SdkLoggerProvider.builder(); + SdkLoggerProviderUtil.addLoggerConfiguratorCondition( + loggerProviderBuilder, nameEquals(scopeB.getName()), LoggerConfig.disabled()); + OpenTelemetrySdk sdk = OpenTelemetrySdk.builder() .setTracerProvider( - SdkTracerProvider.builder() + tracerProviderBuilder .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .addTracerConfiguratorCondition( - nameEquals(scopeB.getName()), TracerConfig.disabled()) - .build()) - .setMeterProvider( - SdkMeterProvider.builder() - .registerMetricReader(metricReader) - .addMeterConfiguratorCondition( - nameEquals(scopeB.getName()), MeterConfig.disabled()) .build()) + .setMeterProvider(meterProviderBuilder.registerMetricReader(metricReader).build()) .setLoggerProvider( - SdkLoggerProvider.builder() + loggerProviderBuilder .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .addLoggerConfiguratorCondition( - nameEquals(scopeB.getName()), LoggerConfig.disabled()) .build()) .build(); @@ -108,34 +116,39 @@ void disableScopeB() { /** Disable all scopes by default and enable a single scope. */ @Test void disableAllScopesExceptB() { + // Configuration ergonomics will improve after APIs stabilize + SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder(); + SdkTracerProviderUtil.setTracerConfigurator( + tracerProviderBuilder, + TracerConfig.configuratorBuilder() + .setDefault(TracerConfig.disabled()) + .addCondition(nameEquals(scopeB.getName()), TracerConfig.enabled()) + .build()); + SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder(); + SdkMeterProviderUtil.setMeterConfigurator( + meterProviderBuilder, + MeterConfig.configuratorBuilder() + .setDefault(MeterConfig.disabled()) + .addCondition(nameEquals(scopeB.getName()), MeterConfig.enabled()) + .build()); + SdkLoggerProviderBuilder loggerProviderBuilder = SdkLoggerProvider.builder(); + SdkLoggerProviderUtil.setLoggerConfigurator( + loggerProviderBuilder, + LoggerConfig.configuratorBuilder() + .setDefault(LoggerConfig.disabled()) + .addCondition(nameEquals(scopeB.getName()), LoggerConfig.enabled()) + .build()); + OpenTelemetrySdk sdk = OpenTelemetrySdk.builder() .setTracerProvider( - SdkTracerProvider.builder() + tracerProviderBuilder .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .setTracerConfigurator( - TracerConfig.configuratorBuilder() - .setDefault(TracerConfig.disabled()) - .addCondition(nameEquals(scopeB.getName()), TracerConfig.enabled()) - .build()) - .build()) - .setMeterProvider( - SdkMeterProvider.builder() - .registerMetricReader(metricReader) - .setMeterConfigurator( - MeterConfig.configuratorBuilder() - .setDefault(MeterConfig.disabled()) - .addCondition(nameEquals(scopeB.getName()), MeterConfig.enabled()) - .build()) .build()) + .setMeterProvider(meterProviderBuilder.registerMetricReader(metricReader).build()) .setLoggerProvider( - SdkLoggerProvider.builder() + loggerProviderBuilder .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .setLoggerConfigurator( - LoggerConfig.configuratorBuilder() - .setDefault(LoggerConfig.disabled()) - .addCondition(nameEquals(scopeB.getName()), LoggerConfig.enabled()) - .build()) .build()) .build(); diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java b/sdk/common/src/main/java/io/opentelemetry/sdk/internal/ScopeConfigurator.java similarity index 80% rename from sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java rename to sdk/common/src/main/java/io/opentelemetry/sdk/internal/ScopeConfigurator.java index e6bcec857e0..cb1fdaeed43 100644 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfigurator.java +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/internal/ScopeConfigurator.java @@ -3,12 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.common; +package io.opentelemetry.sdk.internal; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import java.util.function.Function; /** * A {@link ScopeConfigurator} computes configuration for a given {@link InstrumentationScopeInfo}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. */ @FunctionalInterface public interface ScopeConfigurator extends Function { diff --git a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java b/sdk/common/src/main/java/io/opentelemetry/sdk/internal/ScopeConfiguratorBuilder.java similarity index 94% rename from sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java rename to sdk/common/src/main/java/io/opentelemetry/sdk/internal/ScopeConfiguratorBuilder.java index 036eaf33400..4c32e2f8d9a 100644 --- a/sdk/common/src/main/java/io/opentelemetry/sdk/common/ScopeConfiguratorBuilder.java +++ b/sdk/common/src/main/java/io/opentelemetry/sdk/internal/ScopeConfiguratorBuilder.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.common; +package io.opentelemetry.sdk.internal; -import io.opentelemetry.sdk.internal.GlobUtil; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; @@ -14,6 +14,9 @@ /** * Builder for {@link ScopeConfigurator}. * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + * * @param The scope configuration object, e.g. {@code TracerConfig}, {@code LoggerConfig}, * {@code MeterConfig}. */ diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index ce855ab0818..74bad693bfa 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -9,6 +9,7 @@ import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; /** SDK implementation of {@link Logger}. */ final class SdkLogger implements Logger { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java index 3d13782f814..2d7b87e6b47 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java @@ -12,8 +12,9 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; import io.opentelemetry.sdk.resources.Resource; import java.io.Closeable; import java.util.List; diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java index ccbf5c59ad4..87fec0c8d84 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProviderBuilder.java @@ -12,9 +12,10 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; import java.util.List; @@ -115,7 +116,7 @@ public SdkLoggerProviderBuilder setClock(Clock clock) { * * @see LoggerConfig#configuratorBuilder() */ - public SdkLoggerProviderBuilder setLoggerConfigurator( + SdkLoggerProviderBuilder setLoggerConfigurator( ScopeConfigurator loggerConfigurator) { this.loggerConfiguratorBuilder = loggerConfigurator.toBuilder(); return this; @@ -134,7 +135,7 @@ public SdkLoggerProviderBuilder setLoggerConfigurator( * @see ScopeConfiguratorBuilder#nameEquals(String) * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) */ - public SdkLoggerProviderBuilder addLoggerConfiguratorCondition( + SdkLoggerProviderBuilder addLoggerConfiguratorCondition( Predicate scopeMatcher, LoggerConfig loggerConfig) { this.loggerConfiguratorBuilder.addCondition(scopeMatcher, loggerConfig); return this; diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java similarity index 68% rename from sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java rename to sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java index cee92a76536..39825686c86 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java @@ -3,21 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.logs; +package io.opentelemetry.sdk.logs.internal; import com.google.auto.value.AutoValue; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; import java.util.function.Predicate; import javax.annotation.concurrent.Immutable; /** * A collection of configuration options which define the behavior of a {@link Logger}. * - * @see SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator) - * @see SdkLoggerProviderBuilder#addLoggerConfiguratorCondition(Predicate, LoggerConfig) + * @see SdkLoggerProviderUtil#setLoggerConfigurator(SdkLoggerProviderBuilder, ScopeConfigurator) + * @see SdkLoggerProviderUtil#addLoggerConfiguratorCondition(SdkLoggerProviderBuilder, Predicate, + * LoggerConfig) */ @AutoValue @Immutable @@ -39,9 +41,8 @@ public static LoggerConfig enabled() { } /** - * Returns the default {@link LoggerConfig}, which is used when no {@link - * SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator)} is set or when the logger - * configurator returns {@code null} for a {@link InstrumentationScopeInfo}. + * Returns the default {@link LoggerConfig}, which is used when no configurator is set or when the + * logger configurator returns {@code null} for a {@link InstrumentationScopeInfo}. */ public static LoggerConfig defaultConfig() { return DEFAULT_CONFIG; @@ -49,7 +50,7 @@ public static LoggerConfig defaultConfig() { /** * Create a {@link ScopeConfiguratorBuilder} for configuring {@link - * SdkLoggerProviderBuilder#setLoggerConfigurator(ScopeConfigurator)}. + * SdkLoggerProviderUtil#setLoggerConfigurator(SdkLoggerProviderBuilder, ScopeConfigurator)}. */ public static ScopeConfiguratorBuilder configuratorBuilder() { return ScopeConfigurator.builder(); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkLoggerProviderUtil.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkLoggerProviderUtil.java new file mode 100644 index 00000000000..eb4fbb4ec29 --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkLoggerProviderUtil.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs.internal; + +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Predicate; + +/** + * A collection of methods that allow use of experimental features prior to availability in public + * APIs. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class SdkLoggerProviderUtil { + + private SdkLoggerProviderUtil() {} + + /** Reflectively set the {@link ScopeConfigurator} to the {@link SdkLoggerProviderBuilder}. */ + public static void setLoggerConfigurator( + SdkLoggerProviderBuilder sdkLoggerProviderBuilder, + ScopeConfigurator loggerConfigurator) { + try { + Method method = + SdkLoggerProviderBuilder.class.getDeclaredMethod( + "setLoggerConfigurator", ScopeConfigurator.class); + method.setAccessible(true); + method.invoke(sdkLoggerProviderBuilder, loggerConfigurator); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException( + "Error calling setLoggerConfigurator on SdkLoggerProviderBuilder", e); + } + } + + /** Reflectively add a logger configurator condition to the {@link SdkLoggerProviderBuilder}. */ + public static void addLoggerConfiguratorCondition( + SdkLoggerProviderBuilder sdkLoggerProviderBuilder, + Predicate scopeMatcher, + LoggerConfig loggerConfig) { + try { + Method method = + SdkLoggerProviderBuilder.class.getDeclaredMethod( + "addLoggerConfiguratorCondition", Predicate.class, LoggerConfig.class); + method.setAccessible(true); + method.invoke(sdkLoggerProviderBuilder, scopeMatcher, loggerConfig); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException( + "Error calling addLoggerConfiguratorCondition on SdkLoggerProviderBuilder", e); + } + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 7dcb88ee3f3..371098267eb 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -5,17 +5,18 @@ package io.opentelemetry.sdk.logs; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameMatchesGlob; -import static io.opentelemetry.sdk.logs.LoggerConfig.defaultConfig; -import static io.opentelemetry.sdk.logs.LoggerConfig.enabled; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameMatchesGlob; +import static io.opentelemetry.sdk.logs.internal.LoggerConfig.defaultConfig; +import static io.opentelemetry.sdk.logs.internal.LoggerConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; import java.util.List; import java.util.Map; diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index 550c32e8370..2ea1ee19291 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -24,6 +24,7 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; import io.opentelemetry.sdk.resources.Resource; import java.util.Arrays; import java.util.concurrent.TimeUnit; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java index 23b124125cb..bb76fe6701a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java @@ -15,6 +15,7 @@ import io.opentelemetry.api.metrics.ObservableMeasurement; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.state.CallbackRegistration; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index fa9911c576e..6990ea30cac 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -12,12 +12,13 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.CollectionRegistration; import io.opentelemetry.sdk.metrics.export.MetricProducer; import io.opentelemetry.sdk.metrics.export.MetricReader; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.export.CardinalityLimitSelector; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index a4c15a4ce04..9317c26e6c9 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -7,10 +7,11 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; import io.opentelemetry.sdk.metrics.export.MetricProducer; import io.opentelemetry.sdk.metrics.export.MetricReader; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; @@ -165,8 +166,7 @@ public SdkMeterProviderBuilder registerMetricProducer(MetricProducer metricProdu * * @see MeterConfig#configuratorBuilder() */ - public SdkMeterProviderBuilder setMeterConfigurator( - ScopeConfigurator meterConfigurator) { + SdkMeterProviderBuilder setMeterConfigurator(ScopeConfigurator meterConfigurator) { this.meterConfiguratorBuilder = meterConfigurator.toBuilder(); return this; } @@ -184,7 +184,7 @@ public SdkMeterProviderBuilder setMeterConfigurator( * @see ScopeConfiguratorBuilder#nameEquals(String) * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) */ - public SdkMeterProviderBuilder addMeterConfiguratorCondition( + SdkMeterProviderBuilder addMeterConfiguratorCondition( Predicate scopeMatcher, MeterConfig meterConfig) { this.meterConfiguratorBuilder.addCondition(scopeMatcher, meterConfig); return this; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/MeterConfig.java similarity index 68% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/MeterConfig.java index ec997fe1b4c..12d2c1df1b1 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterConfig.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/MeterConfig.java @@ -3,21 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal; import com.google.auto.value.AutoValue; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import java.util.function.Predicate; import javax.annotation.concurrent.Immutable; /** * A collection of configuration options which define the behavior of a {@link Meter}. * - * @see SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator) - * @see SdkMeterProviderBuilder#addMeterConfiguratorCondition(Predicate, MeterConfig) + * @see SdkMeterProviderUtil#setMeterConfigurator(SdkMeterProviderBuilder, ScopeConfigurator) + * @see SdkMeterProviderUtil#addMeterConfiguratorCondition(SdkMeterProviderBuilder, Predicate, + * MeterConfig) */ @AutoValue @Immutable @@ -38,9 +40,8 @@ public static MeterConfig enabled() { } /** - * Returns the default {@link MeterConfig}, which is used when no {@link - * SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator)} is set or when the meter - * configurator returns {@code null} for a {@link InstrumentationScopeInfo}. + * Returns the default {@link MeterConfig}, which is used when no configurator is set or when the + * meter configurator returns {@code null} for a {@link InstrumentationScopeInfo}. */ public static MeterConfig defaultConfig() { return DEFAULT_CONFIG; @@ -48,7 +49,7 @@ public static MeterConfig defaultConfig() { /** * Create a {@link ScopeConfiguratorBuilder} for configuring {@link - * SdkMeterProviderBuilder#setMeterConfigurator(ScopeConfigurator)}. + * SdkMeterProviderUtil#setMeterConfigurator(SdkMeterProviderBuilder, ScopeConfigurator)}. */ public static ScopeConfiguratorBuilder configuratorBuilder() { return ScopeConfigurator.builder(); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java index ecaf5e388ca..e27856881e1 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java @@ -5,6 +5,8 @@ package io.opentelemetry.sdk.metrics.internal; +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.ViewBuilder; @@ -18,8 +20,11 @@ import java.util.function.Predicate; /** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. + * A collection of methods that allow use of experimental features prior to availability in public + * APIs. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. */ public final class SdkMeterProviderUtil { @@ -66,6 +71,39 @@ public static void registerMetricReaderWithCardinalitySelector( } } + /** Reflectively set the {@link ScopeConfigurator} to the {@link SdkMeterProviderBuilder}. */ + public static void setMeterConfigurator( + SdkMeterProviderBuilder sdkMeterProviderBuilder, + ScopeConfigurator meterConfigurator) { + try { + Method method = + SdkMeterProviderBuilder.class.getDeclaredMethod( + "setMeterConfigurator", ScopeConfigurator.class); + method.setAccessible(true); + method.invoke(sdkMeterProviderBuilder, meterConfigurator); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException( + "Error calling setMeterConfigurator on SdkMeterProviderBuilder", e); + } + } + + /** Reflectively add a tracer configurator condition to the {@link SdkMeterProviderBuilder}. */ + public static void addMeterConfiguratorCondition( + SdkMeterProviderBuilder sdkMeterProviderBuilder, + Predicate scopeMatcher, + MeterConfig meterConfig) { + try { + Method method = + SdkMeterProviderBuilder.class.getDeclaredMethod( + "addMeterConfiguratorCondition", Predicate.class, MeterConfig.class); + method.setAccessible(true); + method.invoke(sdkMeterProviderBuilder, scopeMatcher, meterConfig); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException( + "Error calling addMeterConfiguratorCondition on SdkMeterProviderBuilder", e); + } + } + /** * Reflectively add an {@link AttributesProcessor} to the {@link ViewBuilder} which appends * key-values from baggage to all measurements. diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java index d9416ee700b..3b78f2abd0d 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -5,17 +5,18 @@ package io.opentelemetry.sdk.metrics; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameMatchesGlob; -import static io.opentelemetry.sdk.metrics.MeterConfig.defaultConfig; -import static io.opentelemetry.sdk.metrics.MeterConfig.disabled; -import static io.opentelemetry.sdk.metrics.MeterConfig.enabled; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameMatchesGlob; +import static io.opentelemetry.sdk.metrics.internal.MeterConfig.defaultConfig; +import static io.opentelemetry.sdk.metrics.internal.MeterConfig.disabled; +import static io.opentelemetry.sdk.metrics.internal.MeterConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import java.util.List; import java.util.Map; diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java index 360ab926317..a0b2704fc72 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java @@ -9,6 +9,7 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.trace.internal.TracerConfig; /** {@link SdkTracer} is SDK implementation of {@link Tracer}. */ final class SdkTracer implements Tracer { diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java index cdcc13098bd..036e812c5ab 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java @@ -11,9 +11,10 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; import io.opentelemetry.sdk.internal.ComponentRegistry; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.internal.TracerConfig; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; import java.util.List; diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java index 5ce53c3b9c0..f84c7f79855 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java @@ -9,9 +9,10 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.internal.TracerConfig; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.ArrayList; import java.util.List; @@ -162,7 +163,7 @@ public SdkTracerProviderBuilder addSpanProcessor(SpanProcessor spanProcessor) { * * @see TracerConfig#configuratorBuilder() */ - public SdkTracerProviderBuilder setTracerConfigurator( + SdkTracerProviderBuilder setTracerConfigurator( ScopeConfigurator tracerConfigurator) { this.tracerConfiguratorBuilder = tracerConfigurator.toBuilder(); return this; @@ -181,7 +182,7 @@ public SdkTracerProviderBuilder setTracerConfigurator( * @see ScopeConfiguratorBuilder#nameEquals(String) * @see ScopeConfiguratorBuilder#nameMatchesGlob(String) */ - public SdkTracerProviderBuilder addTracerConfiguratorCondition( + SdkTracerProviderBuilder addTracerConfiguratorCondition( Predicate scopeMatcher, TracerConfig tracerConfig) { this.tracerConfiguratorBuilder.addCondition(scopeMatcher, tracerConfig); return this; diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/SdkTracerProviderUtil.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/SdkTracerProviderUtil.java new file mode 100644 index 00000000000..7d00f230dea --- /dev/null +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/SdkTracerProviderUtil.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.trace.internal; + +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Predicate; + +/** + * A collection of methods that allow use of experimental features prior to availability in public + * APIs. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class SdkTracerProviderUtil { + + private SdkTracerProviderUtil() {} + + /** Reflectively set the {@link ScopeConfigurator} to the {@link SdkTracerProviderBuilder}. */ + public static void setTracerConfigurator( + SdkTracerProviderBuilder sdkTracerProviderBuilder, + ScopeConfigurator tracerConfigurator) { + try { + Method method = + SdkTracerProviderBuilder.class.getDeclaredMethod( + "setTracerConfigurator", ScopeConfigurator.class); + method.setAccessible(true); + method.invoke(sdkTracerProviderBuilder, tracerConfigurator); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException( + "Error calling setTracerConfigurator on SdkTracerProviderBuilder", e); + } + } + + /** Reflectively add a tracer configurator condition to the {@link SdkTracerProviderBuilder}. */ + public static void addTracerConfiguratorCondition( + SdkTracerProviderBuilder sdkTracerProviderBuilder, + Predicate scopeMatcher, + TracerConfig tracerConfig) { + try { + Method method = + SdkTracerProviderBuilder.class.getDeclaredMethod( + "addTracerConfiguratorCondition", Predicate.class, TracerConfig.class); + method.setAccessible(true); + method.invoke(sdkTracerProviderBuilder, scopeMatcher, tracerConfig); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException( + "Error calling addTracerConfiguratorCondition on SdkTracerProviderBuilder", e); + } + } +} diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/TracerConfig.java similarity index 68% rename from sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java rename to sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/TracerConfig.java index ca9becd1e62..d019055b36a 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/TracerConfig.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/internal/TracerConfig.java @@ -3,21 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.trace; +package io.opentelemetry.sdk.trace.internal; import com.google.auto.value.AutoValue; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; -import io.opentelemetry.sdk.common.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.internal.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import java.util.function.Predicate; import javax.annotation.concurrent.Immutable; /** * A collection of configuration options which define the behavior of a {@link Tracer}. * - * @see SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator) - * @see SdkTracerProviderBuilder#addTracerConfiguratorCondition(Predicate, TracerConfig) + * @see SdkTracerProviderUtil#setTracerConfigurator(SdkTracerProviderBuilder, ScopeConfigurator) + * @see SdkTracerProviderUtil#addTracerConfiguratorCondition(SdkTracerProviderBuilder, Predicate, + * TracerConfig) */ @AutoValue @Immutable @@ -39,9 +41,8 @@ public static TracerConfig enabled() { } /** - * Returns the default {@link TracerConfig}, which is used when no {@link - * SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator)} is set or when the tracer - * configurator returns {@code null} for a {@link InstrumentationScopeInfo}. + * Returns the default {@link TracerConfig}, which is used when no configurator is set or when the + * tracer configurator returns {@code null} for a {@link InstrumentationScopeInfo}. */ public static TracerConfig defaultConfig() { return DEFAULT_CONFIG; @@ -49,7 +50,7 @@ public static TracerConfig defaultConfig() { /** * Create a {@link ScopeConfiguratorBuilder} for configuring {@link - * SdkTracerProviderBuilder#setTracerConfigurator(ScopeConfigurator)}. + * SdkTracerProviderUtil#setTracerConfigurator(SdkTracerProviderBuilder, ScopeConfigurator)}. */ public static ScopeConfiguratorBuilder configuratorBuilder() { return ScopeConfigurator.builder(); diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index c91d2867cdf..4df99b4c999 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -5,12 +5,12 @@ package io.opentelemetry.sdk.trace; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals; -import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameMatchesGlob; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameMatchesGlob; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.trace.TracerConfig.defaultConfig; -import static io.opentelemetry.sdk.trace.TracerConfig.disabled; -import static io.opentelemetry.sdk.trace.TracerConfig.enabled; +import static io.opentelemetry.sdk.trace.internal.TracerConfig.defaultConfig; +import static io.opentelemetry.sdk.trace.internal.TracerConfig.disabled; +import static io.opentelemetry.sdk.trace.internal.TracerConfig.enabled; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; @@ -18,9 +18,10 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.common.ScopeConfigurator; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import io.opentelemetry.sdk.trace.internal.TracerConfig; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest;