Skip to content

Commit 5b81ef8

Browse files
committed
add spi to load a declarative config model
1 parent d024873 commit 5b81ef8

File tree

7 files changed

+179
-21
lines changed

7 files changed

+179
-21
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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,14 @@ void configureSdk(
574574
@Nullable
575575
private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile(
576576
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+
577585
String otelConfigFile = config.getString("otel.config.file");
578586
if (otelConfigFile != null && !otelConfigFile.isEmpty()) {
579587
logger.warning(

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

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.lang.reflect.Method;
2121
import java.util.Objects;
2222
import java.util.logging.Logger;
23+
import javax.annotation.Nullable;
2324

2425
/**
2526
* Utilities for interacting with incubating components ({@code
@@ -36,28 +37,12 @@ static AutoConfiguredOpenTelemetrySdk configureFromFile(
3637
Logger logger, String configurationFile, ComponentLoader componentLoader) {
3738
logger.fine("Autoconfiguring from configuration file: " + configurationFile);
3839
try (FileInputStream fis = new FileInputStream(configurationFile)) {
39-
Class<?> declarativeConfiguration =
40+
Object model =
4041
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);
42+
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration")
43+
.getMethod("parse", InputStream.class)
44+
.invoke(null, fis);
45+
return getOpenTelemetrySdk(model, componentLoader);
6146
} catch (FileNotFoundException e) {
6247
throw new ConfigurationException("Configuration file not found", e);
6348
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
@@ -77,6 +62,63 @@ static AutoConfiguredOpenTelemetrySdk configureFromFile(
7762
}
7863
}
7964

65+
@Nullable
66+
public static AutoConfiguredOpenTelemetrySdk configureFromSpi(ComponentLoader componentLoader) {
67+
try {
68+
Class<?> providerClass =
69+
Class.forName(
70+
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider");
71+
Method getConfigurationModel = providerClass.getMethod("getConfigurationModel");
72+
73+
for (Object configProvider : componentLoader.load(providerClass)) {
74+
Object model = getConfigurationModel.invoke(configProvider);
75+
if (model != null) {
76+
return getOpenTelemetrySdk(model, componentLoader);
77+
}
78+
}
79+
return null;
80+
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
81+
throw new ConfigurationException(
82+
"Error configuring from SPI. Is opentelemetry-sdk-extension-incubator on the classpath?",
83+
e);
84+
} catch (InvocationTargetException e) {
85+
Throwable cause = e.getCause();
86+
if (cause instanceof DeclarativeConfigException) {
87+
throw toConfigurationException((DeclarativeConfigException) cause);
88+
}
89+
throw new ConfigurationException("Unexpected error configuring from SPI", e);
90+
}
91+
}
92+
93+
private static AutoConfiguredOpenTelemetrySdk getOpenTelemetrySdk(
94+
Object model, ComponentLoader componentLoader)
95+
throws IllegalAccessException,
96+
InvocationTargetException,
97+
ClassNotFoundException,
98+
NoSuchMethodException {
99+
100+
Class<?> openTelemetryConfiguration =
101+
Class.forName(
102+
"io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel");
103+
Class<?> declarativeConfiguration =
104+
Class.forName(
105+
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration");
106+
Method create =
107+
declarativeConfiguration.getMethod(
108+
"create", openTelemetryConfiguration, ComponentLoader.class);
109+
110+
OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader);
111+
Class<?> sdkConfigProvider =
112+
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider");
113+
Method createFileConfigProvider =
114+
sdkConfigProvider.getMethod("create", openTelemetryConfiguration, ComponentLoader.class);
115+
ConfigProvider configProvider =
116+
(ConfigProvider) createFileConfigProvider.invoke(null, model, componentLoader);
117+
// Note: can't access file configuration resource without reflection so setting a dummy
118+
// resource
119+
return AutoConfiguredOpenTelemetrySdk.create(sdk, Resource.getDefault(), null, configProvider);
120+
}
121+
80122
private static ConfigurationException toConfigurationException(
81123
DeclarativeConfigException exception) {
82124
String message = Objects.requireNonNull(exception.getMessage());
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+
}
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.opentelemetry.sdk.autoconfigure.TestDeclarativeConfigurationProvider
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)