Skip to content

Commit c5cdc1c

Browse files
committed
Introduce ConfigProvider API
1 parent b56af03 commit c5cdc1c

File tree

49 files changed

+720
-161
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+720
-161
lines changed

api/incubator/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ dependencies {
1414

1515
annotationProcessor("com.google.auto.value:auto-value")
1616

17+
// To use parsed config file as input for YamlStructuredConfigPropertiesTest
18+
testImplementation(project(":sdk-extensions:incubator"))
19+
// TODO (jack-berg): Why is this dependency not brought in as transitive dependency of :sdk-extensions:incubator?
20+
testImplementation("com.fasterxml.jackson.core:jackson-databind")
21+
1722
testImplementation(project(":sdk:testing"))
1823

1924
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.config;
7+
8+
import javax.annotation.Nullable;
9+
import javax.annotation.concurrent.ThreadSafe;
10+
11+
/**
12+
* A registry for accessing configuration.
13+
*
14+
* <p>The name <i>Provider</i> is for consistency with other languages and it is <b>NOT</b> loaded
15+
* using reflection.
16+
*
17+
* <p>See {@link InstrumentationConfigUtil} for convenience methods for extracting config from
18+
* {@link ConfigProvider}.
19+
*/
20+
@ThreadSafe
21+
public interface ConfigProvider {
22+
23+
/**
24+
* Returns the {@link StructuredConfigProperties} corresponding to <a
25+
* href="https://github.com/open-telemetry/opentelemetry-configuration/blob/main/schema/instrumentation.json">instrumentation
26+
* config</a>, or {@code null} if file configuration is not used.
27+
*
28+
* @return the instrumentation {@link StructuredConfigProperties}
29+
*/
30+
@Nullable
31+
StructuredConfigProperties getInstrumentationConfig();
32+
33+
/** Returns a no-op {@link ConfigProvider}. */
34+
static ConfigProvider noop() {
35+
return () -> null;
36+
}
37+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.config;
7+
8+
import io.opentelemetry.api.GlobalOpenTelemetry;
9+
import java.util.concurrent.atomic.AtomicReference;
10+
import javax.annotation.Nullable;
11+
12+
/**
13+
* This class provides a temporary global accessor for {@link ConfigProvider} until the config API
14+
* is marked stable. It will eventually be merged into {@link GlobalOpenTelemetry}.
15+
*/
16+
// We intentionally assign to be used for error reporting.
17+
@SuppressWarnings("StaticAssignmentOfThrowable")
18+
public final class GlobalConfigProvider {
19+
20+
private static final AtomicReference<ConfigProvider> instance =
21+
new AtomicReference<>(ConfigProvider.noop());
22+
23+
@SuppressWarnings("NonFinalStaticField")
24+
@Nullable
25+
private static volatile Throwable setInstanceCaller;
26+
27+
private GlobalConfigProvider() {}
28+
29+
/** Returns the globally registered {@link ConfigProvider}. */
30+
// instance cannot be set to null
31+
@SuppressWarnings("NullAway")
32+
public static ConfigProvider get() {
33+
return instance.get();
34+
}
35+
36+
/**
37+
* Sets the global {@link ConfigProvider}. Future calls to {@link #get()} will return the provided
38+
* {@link ConfigProvider} instance. This should be called once as early as possible in your
39+
* application initialization logic.
40+
*/
41+
public static void set(ConfigProvider configProvider) {
42+
boolean changed = instance.compareAndSet(ConfigProvider.noop(), configProvider);
43+
if (!changed && (configProvider != ConfigProvider.noop())) {
44+
throw new IllegalStateException(
45+
"GlobalConfigProvider.set has already been called. GlobalConfigProvider.set "
46+
+ "must be called only once before any calls to GlobalConfigProvider.get. "
47+
+ "Previous invocation set to cause of this exception.",
48+
setInstanceCaller);
49+
}
50+
setInstanceCaller = new Throwable();
51+
}
52+
53+
/**
54+
* Unsets the global {@link ConfigProvider}. This is only meant to be used from tests which need
55+
* to reconfigure {@link ConfigProvider}.
56+
*/
57+
public static void resetForTest() {
58+
instance.set(ConfigProvider.noop());
59+
}
60+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.config;
7+
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.Optional;
12+
import javax.annotation.Nullable;
13+
14+
/**
15+
* A collection of convenience methods to extract instrumentation config from {@link
16+
* ConfigProvider#getInstrumentationConfig()}.
17+
*/
18+
public class InstrumentationConfigUtil {
19+
20+
// TODO (jack-berg): add helper function to access nested structures with dot notation
21+
22+
/**
23+
* Return a map representation of the peer service map entries in {@code
24+
* .instrumentation.general.peer.service_mapping}, or null if none is configured.
25+
*/
26+
@Nullable
27+
public static Map<String, String> peerServiceMapping(ConfigProvider configProvider) {
28+
Optional<List<StructuredConfigProperties>> optServiceMappingList =
29+
Optional.ofNullable(configProvider.getInstrumentationConfig())
30+
.map(instrumentationConfig -> instrumentationConfig.getStructured("general"))
31+
.map(generalConfig -> generalConfig.getStructured("peer"))
32+
.map(httpConfig -> httpConfig.getStructuredList("service_mapping"));
33+
if (!optServiceMappingList.isPresent()) {
34+
return null;
35+
}
36+
Map<String, String> serviceMapping = new HashMap<>();
37+
optServiceMappingList
38+
.get()
39+
.forEach(
40+
entry -> {
41+
String peer = entry.getString("peer");
42+
String service = entry.getString("service");
43+
if (peer != null && service != null) {
44+
serviceMapping.put(peer, service);
45+
}
46+
});
47+
return serviceMapping;
48+
}
49+
50+
/**
51+
* Return {@code .instrumentation.general.http.client.request_captured_headers}, or null if none
52+
* is configured.
53+
*/
54+
@Nullable
55+
public static List<String> httpClientRequestCapturedHeaders(ConfigProvider configProvider) {
56+
return Optional.ofNullable(configProvider.getInstrumentationConfig())
57+
.map(instrumentationConfig -> instrumentationConfig.getStructured("general"))
58+
.map(generalConfig -> generalConfig.getStructured("http"))
59+
.map(httpConfig -> httpConfig.getStructured("client"))
60+
.map(clientConfig -> clientConfig.getScalarList("request_captured_headers", String.class))
61+
.orElse(null);
62+
}
63+
64+
/**
65+
* Return {@code .instrumentation.general.http.client.response_captured_headers}, or null if none
66+
* is configured.
67+
*/
68+
@Nullable
69+
public static List<String> httpClientResponseCapturedHeaders(ConfigProvider configProvider) {
70+
return Optional.ofNullable(configProvider.getInstrumentationConfig())
71+
.map(instrumentationConfig -> instrumentationConfig.getStructured("general"))
72+
.map(generalConfig -> generalConfig.getStructured("http"))
73+
.map(httpConfig -> httpConfig.getStructured("client"))
74+
.map(clientConfig -> clientConfig.getScalarList("response_captured_headers", String.class))
75+
.orElse(null);
76+
}
77+
78+
/**
79+
* Return {@code .instrumentation.general.http.server.request_captured_headers}, or null if none
80+
* is configured.
81+
*/
82+
@Nullable
83+
public static List<String> httpServerRequestCapturedHeaders(ConfigProvider configProvider) {
84+
return Optional.ofNullable(configProvider.getInstrumentationConfig())
85+
.map(instrumentationConfig -> instrumentationConfig.getStructured("general"))
86+
.map(generalConfig -> generalConfig.getStructured("http"))
87+
.map(httpConfig -> httpConfig.getStructured("server"))
88+
.map(clientConfig -> clientConfig.getScalarList("request_captured_headers", String.class))
89+
.orElse(null);
90+
}
91+
92+
/**
93+
* Return {@code .instrumentation.general.http.server.response_captured_headers}, or null if none
94+
* is configured.
95+
*/
96+
@Nullable
97+
public static List<String> httpSeverResponseCapturedHeaders(ConfigProvider configProvider) {
98+
return Optional.ofNullable(configProvider.getInstrumentationConfig())
99+
.map(instrumentationConfig -> instrumentationConfig.getStructured("general"))
100+
.map(generalConfig -> generalConfig.getStructured("http"))
101+
.map(httpConfig -> httpConfig.getStructured("server"))
102+
.map(clientConfig -> clientConfig.getScalarList("response_captured_headers", String.class))
103+
.orElse(null);
104+
}
105+
106+
/** Return {@code .instrumentation.java.<instrumentationName>}, or null if none is configured. */
107+
@Nullable
108+
public static StructuredConfigProperties javaInstrumentationConfig(
109+
ConfigProvider configProvider, String instrumentationName) {
110+
return Optional.ofNullable(configProvider.getInstrumentationConfig())
111+
.map(instrumentationConfig -> instrumentationConfig.getStructured("java"))
112+
.map(generalConfig -> generalConfig.getStructured(instrumentationName))
113+
.orElse(null);
114+
}
115+
116+
private InstrumentationConfigUtil() {}
117+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.config;
7+
8+
/** An exception that is thrown if the user-provided file configuration is invalid. */
9+
public final class StructuredConfigException extends RuntimeException {
10+
11+
private static final long serialVersionUID = 3036584181551130522L;
12+
13+
/** Create a new configuration exception with specified {@code message} and without a cause. */
14+
public StructuredConfigException(String message) {
15+
super(message);
16+
}
17+
18+
/** Create a new configuration exception with specified {@code message} and {@code cause}. */
19+
public StructuredConfigException(String message, Throwable cause) {
20+
super(message, cause);
21+
}
22+
}

sdk-extensions/autoconfigure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/StructuredConfigProperties.java renamed to api/incubator/src/main/java/io/opentelemetry/api/incubator/config/StructuredConfigProperties.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.sdk.autoconfigure.spi.internal;
6+
package io.opentelemetry.api.incubator.config;
77

88
import static io.opentelemetry.api.internal.ConfigUtil.defaultIfNull;
99

10-
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11-
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
1210
import java.util.List;
1311
import java.util.Set;
1412
import javax.annotation.Nullable;
@@ -28,7 +26,7 @@ public interface StructuredConfigProperties {
2826
* Returns a {@link String} configuration property.
2927
*
3028
* @return null if the property has not been configured
31-
* @throws ConfigurationException if the property is not a valid scalar string
29+
* @throws StructuredConfigException if the property is not a valid scalar string
3230
*/
3331
@Nullable
3432
String getString(String name);
@@ -38,7 +36,7 @@ public interface StructuredConfigProperties {
3836
*
3937
* @return a {@link String} configuration property or {@code defaultValue} if a property with
4038
* {@code name} has not been configured
41-
* @throws ConfigurationException if the property is not a valid scalar string
39+
* @throws StructuredConfigException if the property is not a valid scalar string
4240
*/
4341
default String getString(String name, String defaultValue) {
4442
return defaultIfNull(getString(name), defaultValue);
@@ -49,7 +47,7 @@ default String getString(String name, String defaultValue) {
4947
* {@link Boolean#parseBoolean(String)} for handling the values.
5048
*
5149
* @return null if the property has not been configured
52-
* @throws ConfigurationException if the property is not a valid scalar boolean
50+
* @throws StructuredConfigException if the property is not a valid scalar boolean
5351
*/
5452
@Nullable
5553
Boolean getBoolean(String name);
@@ -59,7 +57,7 @@ default String getString(String name, String defaultValue) {
5957
*
6058
* @return a {@link Boolean} configuration property or {@code defaultValue} if a property with
6159
* {@code name} has not been configured
62-
* @throws ConfigurationException if the property is not a valid scalar boolean
60+
* @throws StructuredConfigException if the property is not a valid scalar boolean
6361
*/
6462
default boolean getBoolean(String name, boolean defaultValue) {
6563
return defaultIfNull(getBoolean(name), defaultValue);
@@ -72,7 +70,7 @@ default boolean getBoolean(String name, boolean defaultValue) {
7270
* {@link Long#intValue()} which may result in loss of precision.
7371
*
7472
* @return null if the property has not been configured
75-
* @throws ConfigurationException if the property is not a valid scalar integer
73+
* @throws StructuredConfigException if the property is not a valid scalar integer
7674
*/
7775
@Nullable
7876
Integer getInt(String name);
@@ -85,7 +83,7 @@ default boolean getBoolean(String name, boolean defaultValue) {
8583
*
8684
* @return a {@link Integer} configuration property or {@code defaultValue} if a property with
8785
* {@code name} has not been configured
88-
* @throws ConfigurationException if the property is not a valid scalar integer
86+
* @throws StructuredConfigException if the property is not a valid scalar integer
8987
*/
9088
default int getInt(String name, int defaultValue) {
9189
return defaultIfNull(getInt(name), defaultValue);
@@ -95,7 +93,7 @@ default int getInt(String name, int defaultValue) {
9593
* Returns a {@link Long} configuration property.
9694
*
9795
* @return null if the property has not been configured
98-
* @throws ConfigurationException if the property is not a valid scalar long
96+
* @throws StructuredConfigException if the property is not a valid scalar long
9997
*/
10098
@Nullable
10199
Long getLong(String name);
@@ -105,7 +103,7 @@ default int getInt(String name, int defaultValue) {
105103
*
106104
* @return a {@link Long} configuration property or {@code defaultValue} if a property with {@code
107105
* name} has not been configured
108-
* @throws ConfigurationException if the property is not a valid scalar long
106+
* @throws StructuredConfigException if the property is not a valid scalar long
109107
*/
110108
default long getLong(String name, long defaultValue) {
111109
return defaultIfNull(getLong(name), defaultValue);
@@ -115,7 +113,7 @@ default long getLong(String name, long defaultValue) {
115113
* Returns a {@link Double} configuration property.
116114
*
117115
* @return null if the property has not been configured
118-
* @throws ConfigurationException if the property is not a valid scalar double
116+
* @throws StructuredConfigException if the property is not a valid scalar double
119117
*/
120118
@Nullable
121119
Double getDouble(String name);
@@ -125,7 +123,7 @@ default long getLong(String name, long defaultValue) {
125123
*
126124
* @return a {@link Double} configuration property or {@code defaultValue} if a property with
127125
* {@code name} has not been configured
128-
* @throws ConfigurationException if the property is not a valid scalar double
126+
* @throws StructuredConfigException if the property is not a valid scalar double
129127
*/
130128
default double getDouble(String name, double defaultValue) {
131129
return defaultIfNull(getDouble(name), defaultValue);
@@ -139,8 +137,8 @@ default double getDouble(String name, double defaultValue) {
139137
* @param scalarType the scalar type, one of {@link String}, {@link Boolean}, {@link Long} or
140138
* {@link Double}
141139
* @return a {@link List} configuration property, or null if the property has not been configured
142-
* @throws ConfigurationException if the property is not a valid sequence of scalars, or if {@code
143-
* scalarType} is not supported
140+
* @throws StructuredConfigException if the property is not a valid sequence of scalars, or if
141+
* {@code scalarType} is not supported
144142
*/
145143
@Nullable
146144
<T> List<T> getScalarList(String name, Class<T> scalarType);
@@ -149,10 +147,12 @@ default double getDouble(String name, double defaultValue) {
149147
* Returns a {@link List} configuration property. Entries which are not strings are converted to
150148
* their string representation.
151149
*
152-
* @see ConfigProperties#getList(String name)
150+
* @param name the property name
151+
* @param scalarType the scalar type, one of {@link String}, {@link Boolean}, {@link Long} or
152+
* {@link Double}
153153
* @return a {@link List} configuration property or {@code defaultValue} if a property with {@code
154154
* name} has not been configured
155-
* @throws ConfigurationException if the property is not a valid sequence of scalars
155+
* @throws StructuredConfigException if the property is not a valid sequence of scalars
156156
*/
157157
default <T> List<T> getScalarList(String name, Class<T> scalarType, List<T> defaultValue) {
158158
return defaultIfNull(getScalarList(name, scalarType), defaultValue);
@@ -163,7 +163,7 @@ default <T> List<T> getScalarList(String name, Class<T> scalarType, List<T> defa
163163
*
164164
* @return a map-valued configuration property, or {@code null} if {@code name} has not been
165165
* configured
166-
* @throws ConfigurationException if the property is not a mapping
166+
* @throws StructuredConfigException if the property is not a mapping
167167
*/
168168
@Nullable
169169
StructuredConfigProperties getStructured(String name);
@@ -173,7 +173,7 @@ default <T> List<T> getScalarList(String name, Class<T> scalarType, List<T> defa
173173
*
174174
* @return a list of map-valued configuration property, or {@code null} if {@code name} has not
175175
* been configured
176-
* @throws ConfigurationException if the property is not a sequence of mappings
176+
* @throws StructuredConfigException if the property is not a sequence of mappings
177177
*/
178178
@Nullable
179179
List<StructuredConfigProperties> getStructuredList(String name);

0 commit comments

Comments
 (0)