Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scope config #6375

Merged
merged 9 commits into from
Apr 18, 2024
19 changes: 18 additions & 1 deletion docs/apidiffs/current_vs_latest/opentelemetry-sdk-common.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
Comparing source compatibility of against
No changes.
+++ 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<T> builder()
GENERIC TEMPLATES: +++ T:java.lang.Object
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder<T> 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<T> addCondition(java.util.function.Predicate<io.opentelemetry.sdk.common.InstrumentationScopeInfo>, java.lang.Object)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfigurator<T> build()
+++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate<io.opentelemetry.sdk.common.InstrumentationScopeInfo> nameEquals(java.lang.String)
+++ NEW METHOD: PUBLIC(+) STATIC(+) java.util.function.Predicate<io.opentelemetry.sdk.common.InstrumentationScopeInfo> nameMatchesGlob(java.lang.String)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.ScopeConfiguratorBuilder<T> setDefault(java.lang.Object)
13 changes: 12 additions & 1 deletion docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
Comparing source compatibility of against
No changes.
+++ 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<io.opentelemetry.sdk.logs.LoggerConfig> 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 addLoggerConfiguratorMatcher(java.util.function.Predicate<io.opentelemetry.sdk.common.InstrumentationScopeInfo>, io.opentelemetry.sdk.logs.LoggerConfig)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder setLoggerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator<io.opentelemetry.sdk.logs.LoggerConfig>)
13 changes: 12 additions & 1 deletion docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
Comparing source compatibility of against
No changes.
+++ 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<io.opentelemetry.sdk.metrics.MeterConfig> 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 addMeterConfiguratorMatcher(java.util.function.Predicate<io.opentelemetry.sdk.common.InstrumentationScopeInfo>, io.opentelemetry.sdk.metrics.MeterConfig)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder setMeterConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator<io.opentelemetry.sdk.metrics.MeterConfig>)
13 changes: 12 additions & 1 deletion docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
Comparing source compatibility of against
No changes.
*** 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.common.InstrumentationScopeInfo>, io.opentelemetry.sdk.trace.TracerConfig)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setTracerConfigurator(io.opentelemetry.sdk.common.ScopeConfigurator<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.common.ScopeConfiguratorBuilder<io.opentelemetry.sdk.trace.TracerConfig> 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()
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk;

import static io.opentelemetry.sdk.common.ScopeConfiguratorBuilder.nameEquals;
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;
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 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. */
@Test
void disableScopeB() {
OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder()
.setTracerProvider(
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(spanExporter))
.addTracerConfiguratorCondition(nameEquals("scopeB"), TracerConfig.disabled())
.build())
.setMeterProvider(
SdkMeterProvider.builder()
.registerMetricReader(metricReader)
.addMeterConfiguratorCondition(nameEquals("scopeB"), MeterConfig.disabled())
.build())
.setLoggerProvider(
SdkLoggerProvider.builder()
.addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter))
.addLoggerConfiguratorCondition(nameEquals("scopeB"), LoggerConfig.disabled())
.build())
.build();

simulateInstrumentation(sdk);

// 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<InstrumentationScopeInfo, List<SpanData>> spansByScope =
spans.stream()
.collect(Collectors.groupingBy(SpanData::getInstrumentationScopeInfo));
assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeA"))).hasSize(1);
jack-berg marked this conversation as resolved.
Show resolved Hide resolved
assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeB"))).isNull();
assertThat(spansByScope.get(InstrumentationScopeInfo.create("scopeC"))).hasSize(1);
});
assertThat(metricReader.collectAllMetrics())
.satisfies(
metrics -> {
Map<InstrumentationScopeInfo, List<MetricData>> 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<InstrumentationScopeInfo, List<LogRecordData>> 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);
});
}

/** Disable all scopes by default and enable a single scope. */
@Test
void disableAllScopesExceptB() {
OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder()
.setTracerProvider(
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(spanExporter))
.setTracerConfigurator(
TracerConfig.configuratorBuilder()
.setDefault(TracerConfig.disabled())
breedx-splk marked this conversation as resolved.
Show resolved Hide resolved
.addCondition(nameEquals("scopeB"), TracerConfig.enabled())
.build())
.build())
.setMeterProvider(
SdkMeterProvider.builder()
.registerMetricReader(metricReader)
.setMeterConfigurator(
MeterConfig.configuratorBuilder()
.setDefault(MeterConfig.disabled())
.addCondition(nameEquals("scopeB"), MeterConfig.enabled())
.build())
.build())
.setLoggerProvider(
SdkLoggerProvider.builder()
.addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter))
.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.
assertThat(spanExporter.getFinishedSpanItems())
.satisfies(
spans -> {
Map<InstrumentationScopeInfo, List<SpanData>> 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<InstrumentationScopeInfo, List<MetricData>> 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<InstrumentationScopeInfo, List<LogRecordData>> 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
}
}
Original file line number Diff line number Diff line change
@@ -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<T> extends Function<InstrumentationScopeInfo, T> {

/** Create a new builder. */
static <T> ScopeConfiguratorBuilder<T> 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<T> toBuilder() {
return new ScopeConfiguratorBuilder<>(this);
}
}
Loading
Loading