Skip to content

Commit d9cef81

Browse files
authored
Define dedicated file configuration SPI ComponentProvider (#6457)
1 parent 809457d commit d9cef81

File tree

14 files changed

+939
-66
lines changed

14 files changed

+939
-66
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.exporter.prometheus.internal;
7+
8+
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
9+
import io.opentelemetry.exporter.prometheus.PrometheusHttpServerBuilder;
10+
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
11+
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
12+
import io.opentelemetry.sdk.metrics.export.MetricReader;
13+
14+
/**
15+
* File configuration SPI implementation for {@link PrometheusHttpServer}.
16+
*
17+
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
18+
* at any time.
19+
*/
20+
public class PrometheusComponentProvider implements ComponentProvider<MetricReader> {
21+
22+
@Override
23+
public Class<MetricReader> getType() {
24+
return MetricReader.class;
25+
}
26+
27+
@Override
28+
public String getName() {
29+
return "prometheus";
30+
}
31+
32+
@Override
33+
public MetricReader create(StructuredConfigProperties config) {
34+
PrometheusHttpServerBuilder prometheusBuilder = PrometheusHttpServer.builder();
35+
36+
Integer port = config.getInt("port");
37+
if (port != null) {
38+
prometheusBuilder.setPort(port);
39+
}
40+
String host = config.getString("host");
41+
if (host != null) {
42+
prometheusBuilder.setHost(host);
43+
}
44+
45+
return prometheusBuilder.build();
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.opentelemetry.exporter.prometheus.internal.PrometheusComponentProvider
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.autoconfigure.spi.internal;
7+
8+
import io.opentelemetry.sdk.trace.export.SpanExporter;
9+
10+
/**
11+
* Provides configured instances of SDK extension components. {@link ComponentProvider} allows SDK
12+
* extension components which are not part of the core SDK to be referenced in file based
13+
* configuration.
14+
*
15+
* @param <T> the type of the SDK extension component. See {@link #getType()}.
16+
*/
17+
// TODO (jack-berg): list the specific types which are supported in file configuration
18+
public interface ComponentProvider<T> {
19+
20+
/**
21+
* The type of SDK extension component. For example, if providing instances of a custom span
22+
* exporter, the type would be {@link SpanExporter}.
23+
*/
24+
Class<T> getType();
25+
26+
/**
27+
* The name of the exporter, to be referenced in configuration files. For example, if providing
28+
* instances of a custom span exporter for the "acme" protocol, the name might be "acme".
29+
*
30+
* <p>This name MUST not be the same as any other component provider name which returns components
31+
* of the same {@link #getType() type}.
32+
*/
33+
String getName();
34+
35+
/**
36+
* Configure an instance of the SDK extension component according to the {@code config}.
37+
*
38+
* @param config the configuration provided where the component is referenced in a configuration
39+
* file.
40+
* @return an instance the SDK extension component
41+
*/
42+
// TODO (jack-berg): consider dynamic configuration use case before stabilizing in case that
43+
// affects any API decisions
44+
T create(StructuredConfigProperties config);
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.autoconfigure.spi.internal;
7+
8+
import static io.opentelemetry.api.internal.ConfigUtil.defaultIfNull;
9+
10+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
12+
import java.util.List;
13+
import java.util.Set;
14+
import javax.annotation.Nullable;
15+
16+
/**
17+
* An interface for accessing structured configuration data.
18+
*
19+
* <p>An instance of {@link StructuredConfigProperties} is equivalent to a <a
20+
* href="https://yaml.org/spec/1.2.2/#3211-nodes">YAML mapping node</a>. It has accessors for
21+
* reading scalar properties, {@link #getStructured(String)} for reading children which are
22+
* themselves mappings, and {@link #getStructuredList(String)} for reading children which are
23+
* sequences of mappings.
24+
*/
25+
public interface StructuredConfigProperties {
26+
27+
/**
28+
* Returns a {@link String} configuration property.
29+
*
30+
* @return null if the property has not been configured
31+
* @throws ConfigurationException if the property is not a valid scalar string
32+
*/
33+
@Nullable
34+
String getString(String name);
35+
36+
/**
37+
* Returns a {@link String} configuration property.
38+
*
39+
* @return a {@link String} configuration property or {@code defaultValue} if a property with
40+
* {@code name} has not been configured
41+
* @throws ConfigurationException if the property is not a valid scalar string
42+
*/
43+
default String getString(String name, String defaultValue) {
44+
return defaultIfNull(getString(name), defaultValue);
45+
}
46+
47+
/**
48+
* Returns a {@link Boolean} configuration property. Implementations should use the same rules as
49+
* {@link Boolean#parseBoolean(String)} for handling the values.
50+
*
51+
* @return null if the property has not been configured
52+
* @throws ConfigurationException if the property is not a valid scalar boolean
53+
*/
54+
@Nullable
55+
Boolean getBoolean(String name);
56+
57+
/**
58+
* Returns a {@link Boolean} configuration property.
59+
*
60+
* @return a {@link Boolean} configuration property or {@code defaultValue} if a property with
61+
* {@code name} has not been configured
62+
* @throws ConfigurationException if the property is not a valid scalar boolean
63+
*/
64+
default boolean getBoolean(String name, boolean defaultValue) {
65+
return defaultIfNull(getBoolean(name), defaultValue);
66+
}
67+
68+
/**
69+
* Returns a {@link Integer} configuration property.
70+
*
71+
* <p>If the underlying config property is {@link Long}, it is converted to {@link Integer} with
72+
* {@link Long#intValue()} which may result in loss of precision.
73+
*
74+
* @return null if the property has not been configured
75+
* @throws ConfigurationException if the property is not a valid scalar integer
76+
*/
77+
@Nullable
78+
Integer getInt(String name);
79+
80+
/**
81+
* Returns a {@link Integer} configuration property.
82+
*
83+
* <p>If the underlying config property is {@link Long}, it is converted to {@link Integer} with
84+
* {@link Long#intValue()} which may result in loss of precision.
85+
*
86+
* @return a {@link Integer} configuration property or {@code defaultValue} if a property with
87+
* {@code name} has not been configured
88+
* @throws ConfigurationException if the property is not a valid scalar integer
89+
*/
90+
default int getInt(String name, int defaultValue) {
91+
return defaultIfNull(getInt(name), defaultValue);
92+
}
93+
94+
/**
95+
* Returns a {@link Long} configuration property.
96+
*
97+
* @return null if the property has not been configured
98+
* @throws ConfigurationException if the property is not a valid scalar long
99+
*/
100+
@Nullable
101+
Long getLong(String name);
102+
103+
/**
104+
* Returns a {@link Long} configuration property.
105+
*
106+
* @return a {@link Long} configuration property or {@code defaultValue} if a property with {@code
107+
* name} has not been configured
108+
* @throws ConfigurationException if the property is not a valid scalar long
109+
*/
110+
default long getLong(String name, long defaultValue) {
111+
return defaultIfNull(getLong(name), defaultValue);
112+
}
113+
114+
/**
115+
* Returns a {@link Double} configuration property.
116+
*
117+
* @return null if the property has not been configured
118+
* @throws ConfigurationException if the property is not a valid scalar double
119+
*/
120+
@Nullable
121+
Double getDouble(String name);
122+
123+
/**
124+
* Returns a {@link Double} configuration property.
125+
*
126+
* @return a {@link Double} configuration property or {@code defaultValue} if a property with
127+
* {@code name} has not been configured
128+
* @throws ConfigurationException if the property is not a valid scalar double
129+
*/
130+
default double getDouble(String name, double defaultValue) {
131+
return defaultIfNull(getDouble(name), defaultValue);
132+
}
133+
134+
/**
135+
* Returns a {@link List} configuration property. Empty values and values which do not map to the
136+
* {@code scalarType} will be removed.
137+
*
138+
* @param name the property name
139+
* @param scalarType the scalar type, one of {@link String}, {@link Boolean}, {@link Long} or
140+
* {@link Double}
141+
* @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
144+
*/
145+
@Nullable
146+
<T> List<T> getScalarList(String name, Class<T> scalarType);
147+
148+
/**
149+
* Returns a {@link List} configuration property. Entries which are not strings are converted to
150+
* their string representation.
151+
*
152+
* @see ConfigProperties#getList(String name)
153+
* @return a {@link List} configuration property or {@code defaultValue} if a property with {@code
154+
* name} has not been configured
155+
* @throws ConfigurationException if the property is not a valid sequence of scalars
156+
*/
157+
default <T> List<T> getScalarList(String name, Class<T> scalarType, List<T> defaultValue) {
158+
return defaultIfNull(getScalarList(name, scalarType), defaultValue);
159+
}
160+
161+
/**
162+
* Returns a {@link StructuredConfigProperties} configuration property.
163+
*
164+
* @return a map-valued configuration property, or {@code null} if {@code name} has not been
165+
* configured
166+
* @throws ConfigurationException if the property is not a mapping
167+
*/
168+
@Nullable
169+
StructuredConfigProperties getStructured(String name);
170+
171+
/**
172+
* Returns a list of {@link StructuredConfigProperties} configuration property.
173+
*
174+
* @return a list of map-valued configuration property, or {@code null} if {@code name} has not
175+
* been configured
176+
* @throws ConfigurationException if the property is not a sequence of mappings
177+
*/
178+
@Nullable
179+
List<StructuredConfigProperties> getStructuredList(String name);
180+
181+
/**
182+
* Returns a set of all configuration property keys.
183+
*
184+
* @return the configuration property keys
185+
*/
186+
Set<String> getPropertyKeys();
187+
}

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import io.opentelemetry.api.OpenTelemetry;
1111
import io.opentelemetry.sdk.OpenTelemetrySdk;
1212
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
13+
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
1314
import io.opentelemetry.sdk.resources.Resource;
15+
import javax.annotation.Nullable;
1416
import javax.annotation.concurrent.Immutable;
1517

1618
/**
@@ -43,8 +45,12 @@ public static AutoConfiguredOpenTelemetrySdkBuilder builder() {
4345
}
4446

4547
static AutoConfiguredOpenTelemetrySdk create(
46-
OpenTelemetrySdk sdk, Resource resource, ConfigProperties config) {
47-
return new AutoValue_AutoConfiguredOpenTelemetrySdk(sdk, resource, config);
48+
OpenTelemetrySdk sdk,
49+
Resource resource,
50+
@Nullable ConfigProperties config,
51+
@Nullable StructuredConfigProperties structuredConfigProperties) {
52+
return new AutoValue_AutoConfiguredOpenTelemetrySdk(
53+
sdk, resource, config, structuredConfigProperties);
4854
}
4955

5056
/**
@@ -60,8 +66,23 @@ static AutoConfiguredOpenTelemetrySdk create(
6066
/** Returns the {@link Resource} that was auto-configured. */
6167
abstract Resource getResource();
6268

63-
/** Returns the {@link ConfigProperties} used for auto-configuration. */
69+
/**
70+
* Returns the {@link ConfigProperties} used for auto-configuration, or {@code null} if file
71+
* configuration was used.
72+
*
73+
* @see #getStructuredConfig()
74+
*/
75+
@Nullable
6476
abstract ConfigProperties getConfig();
6577

78+
/**
79+
* Returns the {@link StructuredConfigProperties} used for auto-configuration, or {@code null} if
80+
* file configuration was not used.
81+
*
82+
* @see #getConfig()
83+
*/
84+
@Nullable
85+
abstract StructuredConfigProperties getStructuredConfig();
86+
6687
AutoConfiguredOpenTelemetrySdk() {}
6788
}

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
2222
import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener;
2323
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
24+
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
2425
import io.opentelemetry.sdk.logs.LogRecordProcessor;
2526
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
2627
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
@@ -505,7 +506,7 @@ public AutoConfiguredOpenTelemetrySdk build() {
505506
maybeSetAsGlobal(openTelemetrySdk);
506507
callAutoConfigureListeners(spiHelper, openTelemetrySdk);
507508

508-
return AutoConfiguredOpenTelemetrySdk.create(openTelemetrySdk, resource, config);
509+
return AutoConfiguredOpenTelemetrySdk.create(openTelemetrySdk, resource, config, null);
509510
} catch (RuntimeException e) {
510511
logger.info(
511512
"Error encountered during autoconfiguration. Closing partially configured components.");
@@ -546,11 +547,21 @@ private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile(ConfigPrope
546547
try {
547548
Class<?> configurationFactory =
548549
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfiguration");
549-
Method parseAndCreate = configurationFactory.getMethod("parseAndCreate", InputStream.class);
550-
OpenTelemetrySdk sdk = (OpenTelemetrySdk) parseAndCreate.invoke(null, fis);
550+
Method parse = configurationFactory.getMethod("parse", InputStream.class);
551+
Object model = parse.invoke(null, fis);
552+
Class<?> openTelemetryConfiguration =
553+
Class.forName(
554+
"io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfiguration");
555+
Method create = configurationFactory.getMethod("create", openTelemetryConfiguration);
556+
OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model);
557+
Method toConfigProperties =
558+
configurationFactory.getMethod("toConfigProperties", openTelemetryConfiguration);
559+
StructuredConfigProperties structuredConfigProperties =
560+
(StructuredConfigProperties) toConfigProperties.invoke(null, model);
551561
// Note: can't access file configuration resource without reflection so setting a dummy
552562
// resource
553-
return AutoConfiguredOpenTelemetrySdk.create(sdk, Resource.getDefault(), config);
563+
return AutoConfiguredOpenTelemetrySdk.create(
564+
sdk, Resource.getDefault(), null, structuredConfigProperties);
554565
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
555566
throw new ConfigurationException(
556567
"Error configuring from file. Is opentelemetry-sdk-extension-incubator on the classpath?",

0 commit comments

Comments
 (0)