Skip to content

Commit 7ef1410

Browse files
authored
don't call old plugin when declarative config is in use (#7472)
1 parent b18583a commit 7ef1410

File tree

9 files changed

+267
-46
lines changed

9 files changed

+267
-46
lines changed

sdk-extensions/autoconfigure/build.gradle.kts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ testing {
8686
implementation(project(":sdk:testing"))
8787
}
8888
}
89+
90+
register<JvmTestSuite>("testDeclarativeConfigSpi") {
91+
dependencies {
92+
implementation(project(":sdk-extensions:incubator"))
93+
implementation(project(":exporters:logging"))
94+
implementation(project(":sdk:testing"))
95+
}
96+
}
8997
}
9098
}
9199

sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,21 @@ public AutoConfiguredOpenTelemetrySdk build() {
445445
}
446446

447447
private AutoConfiguredOpenTelemetrySdk buildImpl() {
448+
AutoConfiguredOpenTelemetrySdk fromFileConfiguration =
449+
maybeConfigureFromFile(
450+
this.config != null
451+
? this.config
452+
: DefaultConfigProperties.create(Collections.emptyMap(), componentLoader),
453+
componentLoader);
454+
if (fromFileConfiguration != null) {
455+
maybeRegisterShutdownHook(fromFileConfiguration.getOpenTelemetrySdk());
456+
Object configProvider = fromFileConfiguration.getConfigProvider();
457+
if (setResultAsGlobal && INCUBATOR_AVAILABLE && configProvider != null) {
458+
IncubatingUtil.setGlobalConfigProvider(configProvider);
459+
}
460+
return fromFileConfiguration;
461+
}
462+
448463
SpiHelper spiHelper = SpiHelper.create(componentLoader);
449464
if (!customized) {
450465
customized = true;
@@ -454,20 +469,8 @@ private AutoConfiguredOpenTelemetrySdk buildImpl() {
454469
customizer.customize(this);
455470
}
456471
}
457-
458472
ConfigProperties config = getConfig();
459473

460-
AutoConfiguredOpenTelemetrySdk fromFileConfiguration =
461-
maybeConfigureFromFile(config, componentLoader);
462-
if (fromFileConfiguration != null) {
463-
maybeRegisterShutdownHook(fromFileConfiguration.getOpenTelemetrySdk());
464-
Object configProvider = fromFileConfiguration.getConfigProvider();
465-
if (setResultAsGlobal && INCUBATOR_AVAILABLE && configProvider != null) {
466-
IncubatingUtil.setGlobalConfigProvider(configProvider);
467-
}
468-
return fromFileConfiguration;
469-
}
470-
471474
Resource resource =
472475
ResourceConfiguration.configureResource(config, spiHelper, resourceCustomizer);
473476

@@ -571,6 +574,14 @@ void configureSdk(
571574
@Nullable
572575
private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile(
573576
ConfigProperties config, ComponentLoader componentLoader) {
577+
if (INCUBATOR_AVAILABLE) {
578+
AutoConfiguredOpenTelemetrySdk sdk = IncubatingUtil.configureFromSpi(componentLoader);
579+
if (sdk != null) {
580+
logger.fine("Autoconfigured from SPI by opentelemetry-sdk-extension-incubator");
581+
return sdk;
582+
}
583+
}
584+
574585
String otelConfigFile = config.getString("otel.config.file");
575586
if (otelConfigFile != null && !otelConfigFile.isEmpty()) {
576587
logger.warning(

sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/IncubatingUtil.java

Lines changed: 89 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
package io.opentelemetry.sdk.autoconfigure;
77

8+
import static java.util.Objects.requireNonNull;
9+
810
import io.opentelemetry.api.incubator.config.ConfigProvider;
911
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
1012
import io.opentelemetry.api.incubator.config.GlobalConfigProvider;
@@ -18,8 +20,8 @@
1820
import java.io.InputStream;
1921
import java.lang.reflect.InvocationTargetException;
2022
import java.lang.reflect.Method;
21-
import java.util.Objects;
2223
import java.util.logging.Logger;
24+
import javax.annotation.Nullable;
2325

2426
/**
2527
* Utilities for interacting with incubating components ({@code
@@ -32,54 +34,111 @@ final class IncubatingUtil {
3234

3335
private IncubatingUtil() {}
3436

37+
// Visible for testing
38+
interface Factory {
39+
@Nullable
40+
AutoConfiguredOpenTelemetrySdk create()
41+
throws ClassNotFoundException,
42+
NoSuchMethodException,
43+
IllegalAccessException,
44+
InvocationTargetException;
45+
}
46+
3547
static AutoConfiguredOpenTelemetrySdk configureFromFile(
3648
Logger logger, String configurationFile, ComponentLoader componentLoader) {
3749
logger.fine("Autoconfiguring from configuration file: " + configurationFile);
3850
try (FileInputStream fis = new FileInputStream(configurationFile)) {
39-
Class<?> declarativeConfiguration =
40-
Class.forName(
41-
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration");
42-
Method parse = declarativeConfiguration.getMethod("parse", InputStream.class);
43-
Object model = parse.invoke(null, fis);
44-
Class<?> openTelemetryConfiguration =
45-
Class.forName(
46-
"io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel");
47-
Method create =
48-
declarativeConfiguration.getMethod(
49-
"create", openTelemetryConfiguration, ComponentLoader.class);
50-
OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader);
51-
Class<?> sdkConfigProvider =
52-
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider");
53-
Method createFileConfigProvider =
54-
sdkConfigProvider.getMethod("create", openTelemetryConfiguration, ComponentLoader.class);
55-
ConfigProvider configProvider =
56-
(ConfigProvider) createFileConfigProvider.invoke(null, model, componentLoader);
57-
// Note: can't access file configuration resource without reflection so setting a dummy
58-
// resource
59-
return AutoConfiguredOpenTelemetrySdk.create(
60-
sdk, Resource.getDefault(), null, configProvider);
51+
return requireNonNull(
52+
createWithFactory(
53+
"file",
54+
() ->
55+
getOpenTelemetrySdk(
56+
Class.forName(
57+
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration")
58+
.getMethod("parse", InputStream.class)
59+
.invoke(null, fis),
60+
componentLoader)));
6161
} catch (FileNotFoundException e) {
6262
throw new ConfigurationException("Configuration file not found", e);
63+
} catch (IOException e) {
64+
// IOException (other than FileNotFoundException which is caught above) is only thrown
65+
// above by FileInputStream.close()
66+
throw new ConfigurationException("Error closing file", e);
67+
}
68+
}
69+
70+
@Nullable
71+
public static AutoConfiguredOpenTelemetrySdk configureFromSpi(ComponentLoader componentLoader) {
72+
return createWithFactory(
73+
"SPI",
74+
() -> {
75+
Class<?> providerClass =
76+
Class.forName(
77+
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider");
78+
Method getConfigurationModel = providerClass.getMethod("getConfigurationModel");
79+
80+
for (Object configProvider : componentLoader.load(providerClass)) {
81+
Object model = getConfigurationModel.invoke(configProvider);
82+
if (model != null) {
83+
return getOpenTelemetrySdk(model, componentLoader);
84+
}
85+
}
86+
return null;
87+
});
88+
}
89+
90+
private static AutoConfiguredOpenTelemetrySdk getOpenTelemetrySdk(
91+
Object model, ComponentLoader componentLoader)
92+
throws IllegalAccessException,
93+
InvocationTargetException,
94+
ClassNotFoundException,
95+
NoSuchMethodException {
96+
97+
Class<?> openTelemetryConfiguration =
98+
Class.forName(
99+
"io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel");
100+
Class<?> declarativeConfiguration =
101+
Class.forName(
102+
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration");
103+
Method create =
104+
declarativeConfiguration.getMethod(
105+
"create", openTelemetryConfiguration, ComponentLoader.class);
106+
107+
OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader);
108+
Class<?> sdkConfigProvider =
109+
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider");
110+
Method createFileConfigProvider =
111+
sdkConfigProvider.getMethod("create", openTelemetryConfiguration, ComponentLoader.class);
112+
ConfigProvider configProvider =
113+
(ConfigProvider) createFileConfigProvider.invoke(null, model, componentLoader);
114+
// Note: can't access file configuration resource without reflection so setting a dummy
115+
// resource
116+
return AutoConfiguredOpenTelemetrySdk.create(sdk, Resource.getDefault(), null, configProvider);
117+
}
118+
119+
// Visible for testing
120+
@Nullable
121+
static AutoConfiguredOpenTelemetrySdk createWithFactory(String name, Factory factory) {
122+
try {
123+
return factory.create();
63124
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
64125
throw new ConfigurationException(
65-
"Error configuring from file. Is opentelemetry-sdk-extension-incubator on the classpath?",
126+
String.format(
127+
"Error configuring from %s. Is opentelemetry-sdk-extension-incubator on the classpath?",
128+
name),
66129
e);
67130
} catch (InvocationTargetException e) {
68131
Throwable cause = e.getCause();
69132
if (cause instanceof DeclarativeConfigException) {
70133
throw toConfigurationException((DeclarativeConfigException) cause);
71134
}
72-
throw new ConfigurationException("Unexpected error configuring from file", e);
73-
} catch (IOException e) {
74-
// IOException (other than FileNotFoundException which is caught above) is only thrown
75-
// above by FileInputStream.close()
76-
throw new ConfigurationException("Error closing file", e);
135+
throw new ConfigurationException("Unexpected error configuring from " + name, e);
77136
}
78137
}
79138

80139
private static ConfigurationException toConfigurationException(
81140
DeclarativeConfigException exception) {
82-
String message = Objects.requireNonNull(exception.getMessage());
141+
String message = requireNonNull(exception.getMessage());
83142
return new ConfigurationException(message, exception);
84143
}
85144

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.autoconfigure;
7+
8+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
9+
import static org.mockito.ArgumentMatchers.any;
10+
import static org.mockito.Mockito.doReturn;
11+
import static org.mockito.Mockito.spy;
12+
13+
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
14+
import io.opentelemetry.internal.testing.CleanupExtension;
15+
import io.opentelemetry.sdk.OpenTelemetrySdk;
16+
import io.opentelemetry.sdk.resources.Resource;
17+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
18+
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.RegisterExtension;
21+
22+
class DeclarativeConfigurationSpiTest {
23+
24+
@RegisterExtension private static final CleanupExtension cleanup = new CleanupExtension();
25+
26+
@Test
27+
void configFromSpi() {
28+
OpenTelemetrySdk expectedSdk =
29+
OpenTelemetrySdk.builder()
30+
.setTracerProvider(
31+
SdkTracerProvider.builder()
32+
.setResource(
33+
Resource.getDefault().toBuilder().put("service.name", "test").build())
34+
.addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
35+
.build())
36+
.build();
37+
cleanup.addCloseable(expectedSdk);
38+
AutoConfiguredOpenTelemetrySdkBuilder builder = spy(AutoConfiguredOpenTelemetrySdk.builder());
39+
Thread thread = new Thread();
40+
doReturn(thread).when(builder).shutdownHook(any());
41+
42+
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk = builder.build();
43+
cleanup.addCloseable(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk());
44+
45+
assertThat(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk().toString())
46+
.isEqualTo(expectedSdk.toString());
47+
}
48+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.autoconfigure;
7+
8+
import static org.assertj.core.api.Assertions.assertThatCode;
9+
10+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
11+
import java.lang.reflect.InvocationTargetException;
12+
import org.junit.jupiter.api.Test;
13+
14+
class IncubatingUtilTest {
15+
16+
@Test
17+
void classNotFoundException() {
18+
assertThatCode(
19+
() ->
20+
IncubatingUtil.createWithFactory(
21+
"test",
22+
() -> {
23+
Class.forName("foo");
24+
return null;
25+
}))
26+
.isInstanceOf(ConfigurationException.class)
27+
.hasMessage(
28+
"Error configuring from test. Is opentelemetry-sdk-extension-incubator on the classpath?");
29+
}
30+
31+
@Test
32+
void invocationTargetException() {
33+
assertThatCode(
34+
() ->
35+
IncubatingUtil.createWithFactory(
36+
"test",
37+
() -> {
38+
throw new InvocationTargetException(new RuntimeException("test exception"));
39+
}))
40+
.isInstanceOf(ConfigurationException.class)
41+
.hasMessage("Unexpected error configuring from test")
42+
.hasRootCauseMessage("test exception");
43+
}
44+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.autoconfigure;
7+
8+
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration;
9+
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider;
10+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
11+
import java.io.ByteArrayInputStream;
12+
import java.nio.charset.StandardCharsets;
13+
14+
public class TestDeclarativeConfigurationProvider implements DeclarativeConfigurationProvider {
15+
@Override
16+
public OpenTelemetryConfigurationModel getConfigurationModel() {
17+
String yaml =
18+
"file_format: \"1.0-rc.1\"\n"
19+
+ "resource:\n"
20+
+ " attributes:\n"
21+
+ " - name: service.name\n"
22+
+ " value: test\n"
23+
+ "tracer_provider:\n"
24+
+ " processors:\n"
25+
+ " - simple:\n"
26+
+ " exporter:\n"
27+
+ " console: {}\n";
28+
29+
return DeclarativeConfiguration.parse(
30+
new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)));
31+
}
32+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.opentelemetry.sdk.autoconfigure.TestDeclarativeConfigurationProvider

sdk-extensions/autoconfigure/src/testIncubating/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,9 @@ void configFile_fileNotFound() {
9696
assertThatThrownBy(
9797
() ->
9898
AutoConfiguredOpenTelemetrySdk.builder()
99-
.addPropertiesSupplier(() -> singletonMap("otel.config.file", "foo"))
100-
.addPropertiesSupplier(
101-
() -> singletonMap("otel.experimental.config.file", "foo"))
102-
.addPropertiesSupplier(() -> singletonMap("otel.sdk.disabled", "true"))
99+
.setConfig(
100+
DefaultConfigProperties.createFromMap(
101+
Collections.singletonMap("otel.experimental.config.file", "foo")))
103102
.build())
104103
.isInstanceOf(ConfigurationException.class)
105104
.hasMessageContaining("Configuration file not found");
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.extension.incubator.fileconfig;
7+
8+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
9+
import javax.annotation.Nullable;
10+
11+
/** A service provider interface (SPI) for providing a declarative configuration model. */
12+
public interface DeclarativeConfigurationProvider {
13+
/**
14+
* Returns an OpenTelemetry configuration model to be used when configuring the SDK, or {@code
15+
* null} if no configuration is provided by this provider.
16+
*/
17+
@Nullable
18+
OpenTelemetryConfigurationModel getConfigurationModel();
19+
}

0 commit comments

Comments
 (0)