Skip to content

Commit 136efcb

Browse files
make declarative config bridge usable by spring starter and contrib (#14497)
Co-authored-by: otelbot <[email protected]>
1 parent 99b89ee commit 136efcb

File tree

13 files changed

+191
-30
lines changed

13 files changed

+191
-30
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# OpenTelemetry Instrumentation API Incubator
2+
3+
Instrumentation API Incubator is a collection of libraries that provide additional functionality
4+
for OpenTelemetry instrumentation and auto-configuration. It is intended to be used by
5+
instrumentation authors and auto-configuration providers to enhance their capabilities and provide a
6+
more consistent experience when working with OpenTelemetry.
7+
8+
## Declarative Config Bridge
9+
10+
Declarative Config Bridge allows instrumentation authors to access configuration in a uniform way,
11+
regardless of the configuration source.
12+
13+
The bridge allows you to read configuration using the system property style when dealing with
14+
declarative configuration.
15+
16+
### Example
17+
18+
As an example, let's look at the inferred spans configuration.
19+
First, there is a configuration method that reads the properties and is unaware of the source of the
20+
configuration:
21+
22+
```java
23+
class InferredSpansConfig {
24+
static SpanProcessor create(ConfigProperties properties) {
25+
// read properties here
26+
boolean backupDiagnosticFiles =
27+
properties.getBoolean("otel.inferred.spans.backup.diagnostic.files", false);
28+
}
29+
}
30+
```
31+
32+
The auto configuration **without declarative config** passes the provided properties directly:
33+
34+
```java
35+
36+
@AutoService(AutoConfigurationCustomizerProvider.class)
37+
public class InferredSpansAutoConfig implements AutoConfigurationCustomizerProvider {
38+
39+
@Override
40+
public void customize(AutoConfigurationCustomizer config) {
41+
config.addTracerProviderCustomizer(
42+
(providerBuilder, properties) -> {
43+
providerBuilder.addSpanProcessor(InferredSpansConfig.create(properties));
44+
return providerBuilder;
45+
});
46+
}
47+
}
48+
```
49+
50+
The auto configuration **with declarative config** uses the Declarative Config Bridge to be able to
51+
use common configuration method:
52+
53+
Let's first look at the yaml file that is used to configure the inferred spans processor:
54+
55+
```yaml
56+
file_format: 1.0-rc.1
57+
tracer_provider:
58+
processors:
59+
- inferred_spans:
60+
backup:
61+
diagnostic:
62+
files: true
63+
```
64+
65+
And now the component provider that uses the Declarative Config Bridge:
66+
67+
```java
68+
69+
@AutoService(ComponentProvider.class)
70+
public class InferredSpansComponentProvider implements ComponentProvider<SpanProcessor> {
71+
72+
@Override
73+
public String getName() {
74+
return "inferred_spans";
75+
}
76+
77+
@Override
78+
public SpanProcessor create(DeclarativeConfigProperties config) {
79+
return InferredSpansConfig.create(
80+
new DeclarativeConfigPropertiesBridgeBuilder()
81+
// crop the prefix, because the properties are under the "inferred_spans" processor
82+
.addMapping("otel.inferred.spans.", "")
83+
.build(config));
84+
}
85+
86+
@Override
87+
public Class<SpanProcessor> getType() {
88+
return SpanProcessor.class;
89+
}
90+
}
91+
```

instrumentation-api-incubator/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ dependencies {
1414
api("io.opentelemetry.semconv:opentelemetry-semconv")
1515
api(project(":instrumentation-api"))
1616
api("io.opentelemetry:opentelemetry-api-incubator")
17+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
18+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator")
1719

1820
compileOnly("com.google.auto.value:auto-value-annotations")
1921
annotationProcessor("com.google.auto.value:auto-value")
@@ -22,6 +24,8 @@ dependencies {
2224
testImplementation("io.opentelemetry:opentelemetry-sdk")
2325
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
2426
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
27+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
28+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")
2529
}
2630

2731
tasks {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.incubator.sdk.config.bridge;
7+
8+
public final class ConfigPropertiesUtil {
9+
private ConfigPropertiesUtil() {}
10+
11+
public static String propertyYamlPath(String propertyName) {
12+
return yamlPath(propertyName);
13+
}
14+
15+
static String yamlPath(String property) {
16+
String[] segments = DeclarativeConfigPropertiesBridge.getSegments(property);
17+
if (segments.length == 0) {
18+
throw new IllegalArgumentException("Invalid property: " + property);
19+
}
20+
21+
return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'";
22+
}
23+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.extension.internal;
6+
package io.opentelemetry.instrumentation.api.incubator.sdk.config.bridge;
77

88
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
99

@@ -169,7 +169,7 @@ private <T> T getPropertyValue(
169169
return extractor.apply(target, lastPart);
170170
}
171171

172-
private static String[] getSegments(String property) {
172+
static String[] getSegments(String property) {
173173
if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) {
174174
property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length());
175175
}
Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.extension.internal;
6+
package io.opentelemetry.instrumentation.api.incubator.sdk.config.bridge;
77

88
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
99

@@ -21,9 +21,6 @@
2121
/**
2222
* A builder for {@link DeclarativeConfigPropertiesBridge} that allows adding translations and fixed
2323
* values for properties.
24-
*
25-
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
26-
* at any time.
2724
*/
2825
public class DeclarativeConfigPropertiesBridgeBuilder {
2926
/**
@@ -82,6 +79,17 @@ public ConfigProperties build(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenT
8279
"AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java");
8380
}
8481

82+
/**
83+
* Build {@link ConfigProperties} from the provided {@link DeclarativeConfigProperties} node.
84+
*
85+
* @param node the declarative config properties to build from
86+
* @return a new instance of {@link ConfigProperties}
87+
*/
88+
public ConfigProperties build(@Nullable DeclarativeConfigProperties node) {
89+
return new DeclarativeConfigPropertiesBridge(
90+
node == null ? empty() : node, mappings, overrideValues);
91+
}
92+
8593
/**
8694
* Build {@link ConfigProperties} from the {@link DeclarativeConfigProperties} provided by the
8795
* instrumentation configuration.
@@ -94,12 +102,7 @@ public ConfigProperties build(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenT
94102
*/
95103
public ConfigProperties buildFromInstrumentationConfig(
96104
@Nullable DeclarativeConfigProperties instrumentationConfig) {
97-
// leave the name "build" for a future method that builds from a DeclarativeConfigProperties
98-
// instance that doesn't come from the top-level instrumentation config
99-
if (instrumentationConfig == null) {
100-
instrumentationConfig = DeclarativeConfigProperties.empty();
101-
}
102-
return new DeclarativeConfigPropertiesBridge(
103-
instrumentationConfig.getStructured("java", empty()), mappings, overrideValues);
105+
return build(
106+
instrumentationConfig == null ? null : instrumentationConfig.getStructured("java"));
104107
}
105108
}
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.instrumentation.api.incubator.sdk.config.bridge;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
class ConfigPropertiesUtilTest {
13+
@Test
14+
void propertyYamlPath() {
15+
assertThat(ConfigPropertiesUtil.propertyYamlPath("google.otel.auth.target.signals"))
16+
.isEqualTo(
17+
"'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / 'signals'");
18+
}
19+
}
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.extension.internal;
6+
package io.opentelemetry.instrumentation.api.incubator.sdk.config.bridge;
77

88
import static org.assertj.core.api.Assertions.assertThat;
9-
import static org.mockito.ArgumentMatchers.any;
109
import static org.mockito.ArgumentMatchers.eq;
1110
import static org.mockito.Mockito.mock;
1211
import static org.mockito.Mockito.when;
@@ -47,7 +46,7 @@ void shouldUseConfigProviderForDeclarativeConfiguration() {
4746
when(javaNodeMock.getString(propertyName)).thenReturn(expectedValue);
4847

4948
DeclarativeConfigProperties instrumentationConfigMock = mock(DeclarativeConfigProperties.class);
50-
when(instrumentationConfigMock.getStructured(eq("java"), any())).thenReturn(javaNodeMock);
49+
when(instrumentationConfigMock.getStructured(eq("java"))).thenReturn(javaNodeMock);
5150

5251
ConfigProvider configProviderMock = mock(ConfigProvider.class);
5352
when(configProviderMock.getInstrumentationConfig()).thenReturn(instrumentationConfigMock);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.extension.internal;
6+
package io.opentelemetry.instrumentation.api.incubator.sdk.config.bridge;
77

88
import static org.assertj.core.api.Assertions.assertThat;
99

javaagent-extension-api/src/test/resources/config.yaml renamed to instrumentation-api-incubator/src/test/resources/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
file_format: 0.4
1+
file_format: 1.0-rc.1
22
instrumentation/development:
33
java:
44
acme:

javaagent-tooling/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies {
2020

2121
implementation("io.opentelemetry:opentelemetry-api")
2222
implementation("io.opentelemetry:opentelemetry-sdk")
23+
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
2324
implementation("io.opentelemetry:opentelemetry-extension-kotlin")
2425
implementation("io.opentelemetry:opentelemetry-extension-trace-propagators")
2526
// the incubator's ViewConfigCustomizer is used to support loading yaml-based metric views

0 commit comments

Comments
 (0)