Introduce ConfigProvider API (#6549)

This commit is contained in:
jack-berg 2025-03-04 17:21:19 -06:00 committed by GitHub
parent b3e3fff83c
commit 42056f57c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
95 changed files with 1542 additions and 746 deletions

View File

@ -14,6 +14,9 @@ dependencies {
annotationProcessor("com.google.auto.value:auto-value")
// To use parsed config file as input for InstrumentationConfigUtilTest
testImplementation(project(":sdk-extensions:incubator"))
testImplementation(project(":sdk:testing"))
testImplementation(project(":api:testing-internal"))

View File

@ -0,0 +1,37 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
* A registry for accessing declarative configuration.
*
* <p>The name <i>Provider</i> is for consistency with other languages and it is <b>NOT</b> loaded
* using reflection.
*
* <p>See {@link InstrumentationConfigUtil} for convenience methods for extracting config from
* {@link ConfigProvider}.
*/
@ThreadSafe
public interface ConfigProvider {
/**
* Returns the {@link DeclarativeConfigProperties} corresponding to <a
* href="https://github.com/open-telemetry/opentelemetry-configuration/blob/main/schema/instrumentation.json">instrumentation
* config</a>, or {@code null} if unavailable.
*
* @return the instrumentation {@link DeclarativeConfigProperties}
*/
@Nullable
DeclarativeConfigProperties getInstrumentationConfig();
/** Returns a no-op {@link ConfigProvider}. */
static ConfigProvider noop() {
return () -> null;
}
}

View File

@ -0,0 +1,22 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
/** An exception that is thrown when errors occur with declarative configuration. */
public final class DeclarativeConfigException extends RuntimeException {
private static final long serialVersionUID = 3036584181551130522L;
/** Create a new configuration exception with specified {@code message} and without a cause. */
public DeclarativeConfigException(String message) {
super(message);
}
/** Create a new configuration exception with specified {@code message} and {@code cause}. */
public DeclarativeConfigException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -3,20 +3,18 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.autoconfigure.spi.internal;
package io.opentelemetry.api.incubator.config;
import static io.opentelemetry.api.internal.ConfigUtil.defaultIfNull;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
/**
* An interface for accessing structured configuration data.
* An interface for accessing declarative configuration data.
*
* <p>An instance of {@link StructuredConfigProperties} is equivalent to a <a
* <p>An instance of {@link DeclarativeConfigProperties} is equivalent to a <a
* href="https://yaml.org/spec/1.2.2/#3211-nodes">YAML mapping node</a>. It has accessors for
* reading scalar properties, {@link #getStructured(String)} for reading children which are
* themselves mappings, and {@link #getStructuredList(String)} for reading children which are
@ -25,24 +23,24 @@ import javax.annotation.Nullable;
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public interface StructuredConfigProperties {
public interface DeclarativeConfigProperties {
/**
* Return an empty {@link StructuredConfigProperties} instance.
* Return an empty {@link DeclarativeConfigProperties} instance.
*
* <p>Useful for walking the tree without checking for null. For example, to access a string key
* nested at .foo.bar.baz, call: {@code config.getStructured("foo", empty()).getStructured("bar",
* empty()).getString("baz")}.
*/
static StructuredConfigProperties empty() {
return EmptyStructuredConfigProperties.getInstance();
static DeclarativeConfigProperties empty() {
return EmptyDeclarativeConfigProperties.getInstance();
}
/**
* Returns a {@link String} configuration property.
*
* @return null if the property has not been configured
* @throws ConfigurationException if the property is not a valid scalar string
* @throws DeclarativeConfigException if the property is not a valid scalar string
*/
@Nullable
String getString(String name);
@ -52,7 +50,7 @@ public interface StructuredConfigProperties {
*
* @return a {@link String} configuration property or {@code defaultValue} if a property with
* {@code name} has not been configured
* @throws ConfigurationException if the property is not a valid scalar string
* @throws DeclarativeConfigException if the property is not a valid scalar string
*/
default String getString(String name, String defaultValue) {
return defaultIfNull(getString(name), defaultValue);
@ -63,7 +61,7 @@ public interface StructuredConfigProperties {
* {@link Boolean#parseBoolean(String)} for handling the values.
*
* @return null if the property has not been configured
* @throws ConfigurationException if the property is not a valid scalar boolean
* @throws DeclarativeConfigException if the property is not a valid scalar boolean
*/
@Nullable
Boolean getBoolean(String name);
@ -73,7 +71,7 @@ public interface StructuredConfigProperties {
*
* @return a {@link Boolean} configuration property or {@code defaultValue} if a property with
* {@code name} has not been configured
* @throws ConfigurationException if the property is not a valid scalar boolean
* @throws DeclarativeConfigException if the property is not a valid scalar boolean
*/
default boolean getBoolean(String name, boolean defaultValue) {
return defaultIfNull(getBoolean(name), defaultValue);
@ -86,7 +84,7 @@ public interface StructuredConfigProperties {
* {@link Long#intValue()} which may result in loss of precision.
*
* @return null if the property has not been configured
* @throws ConfigurationException if the property is not a valid scalar integer
* @throws DeclarativeConfigException if the property is not a valid scalar integer
*/
@Nullable
Integer getInt(String name);
@ -99,7 +97,7 @@ public interface StructuredConfigProperties {
*
* @return a {@link Integer} configuration property or {@code defaultValue} if a property with
* {@code name} has not been configured
* @throws ConfigurationException if the property is not a valid scalar integer
* @throws DeclarativeConfigException if the property is not a valid scalar integer
*/
default int getInt(String name, int defaultValue) {
return defaultIfNull(getInt(name), defaultValue);
@ -109,7 +107,7 @@ public interface StructuredConfigProperties {
* Returns a {@link Long} configuration property.
*
* @return null if the property has not been configured
* @throws ConfigurationException if the property is not a valid scalar long
* @throws DeclarativeConfigException if the property is not a valid scalar long
*/
@Nullable
Long getLong(String name);
@ -119,7 +117,7 @@ public interface StructuredConfigProperties {
*
* @return a {@link Long} configuration property or {@code defaultValue} if a property with {@code
* name} has not been configured
* @throws ConfigurationException if the property is not a valid scalar long
* @throws DeclarativeConfigException if the property is not a valid scalar long
*/
default long getLong(String name, long defaultValue) {
return defaultIfNull(getLong(name), defaultValue);
@ -129,7 +127,7 @@ public interface StructuredConfigProperties {
* Returns a {@link Double} configuration property.
*
* @return null if the property has not been configured
* @throws ConfigurationException if the property is not a valid scalar double
* @throws DeclarativeConfigException if the property is not a valid scalar double
*/
@Nullable
Double getDouble(String name);
@ -139,7 +137,7 @@ public interface StructuredConfigProperties {
*
* @return a {@link Double} configuration property or {@code defaultValue} if a property with
* {@code name} has not been configured
* @throws ConfigurationException if the property is not a valid scalar double
* @throws DeclarativeConfigException if the property is not a valid scalar double
*/
default double getDouble(String name, double defaultValue) {
return defaultIfNull(getDouble(name), defaultValue);
@ -153,8 +151,8 @@ public interface StructuredConfigProperties {
* @param scalarType the scalar type, one of {@link String}, {@link Boolean}, {@link Long} or
* {@link Double}
* @return a {@link List} configuration property, or null if the property has not been configured
* @throws ConfigurationException if the property is not a valid sequence of scalars, or if {@code
* scalarType} is not supported
* @throws DeclarativeConfigException if the property is not a valid sequence of scalars, or if
* {@code scalarType} is not supported
*/
@Nullable
<T> List<T> getScalarList(String name, Class<T> scalarType);
@ -163,56 +161,58 @@ public interface StructuredConfigProperties {
* Returns a {@link List} configuration property. Entries which are not strings are converted to
* their string representation.
*
* @see ConfigProperties#getList(String name)
* @param name the property name
* @param scalarType the scalar type, one of {@link String}, {@link Boolean}, {@link Long} or
* {@link Double}
* @return a {@link List} configuration property or {@code defaultValue} if a property with {@code
* name} has not been configured
* @throws ConfigurationException if the property is not a valid sequence of scalars
* @throws DeclarativeConfigException if the property is not a valid sequence of scalars
*/
default <T> List<T> getScalarList(String name, Class<T> scalarType, List<T> defaultValue) {
return defaultIfNull(getScalarList(name, scalarType), defaultValue);
}
/**
* Returns a {@link StructuredConfigProperties} configuration property.
* Returns a {@link DeclarativeConfigProperties} configuration property.
*
* @return a map-valued configuration property, or {@code null} if {@code name} has not been
* configured
* @throws ConfigurationException if the property is not a mapping
* @throws DeclarativeConfigException if the property is not a mapping
*/
@Nullable
StructuredConfigProperties getStructured(String name);
DeclarativeConfigProperties getStructured(String name);
/**
* Returns a {@link StructuredConfigProperties} configuration property.
* Returns a list of {@link DeclarativeConfigProperties} configuration property.
*
* @return a map-valued configuration property, or {@code defaultValue} if {@code name} has not
* been configured
* @throws ConfigurationException if the property is not a mapping
* @throws DeclarativeConfigException if the property is not a mapping
*/
default StructuredConfigProperties getStructured(
String name, StructuredConfigProperties defaultValue) {
default DeclarativeConfigProperties getStructured(
String name, DeclarativeConfigProperties defaultValue) {
return defaultIfNull(getStructured(name), defaultValue);
}
/**
* Returns a list of {@link StructuredConfigProperties} configuration property.
* Returns a list of {@link DeclarativeConfigProperties} configuration property.
*
* @return a list of map-valued configuration property, or {@code null} if {@code name} has not
* been configured
* @throws ConfigurationException if the property is not a sequence of mappings
* @throws DeclarativeConfigException if the property is not a sequence of mappings
*/
@Nullable
List<StructuredConfigProperties> getStructuredList(String name);
List<DeclarativeConfigProperties> getStructuredList(String name);
/**
* Returns a list of {@link StructuredConfigProperties} configuration property.
* Returns a list of {@link DeclarativeConfigProperties} configuration property.
*
* @return a list of map-valued configuration property, or {@code defaultValue} if {@code name}
* has not been configured
* @throws ConfigurationException if the property is not a sequence of mappings
* @throws DeclarativeConfigException if the property is not a sequence of mappings
*/
default List<StructuredConfigProperties> getStructuredList(
String name, List<StructuredConfigProperties> defaultValue) {
default List<DeclarativeConfigProperties> getStructuredList(
String name, List<DeclarativeConfigProperties> defaultValue) {
return defaultIfNull(getStructuredList(name), defaultValue);
}

View File

@ -3,22 +3,22 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.autoconfigure.spi.internal;
package io.opentelemetry.api.incubator.config;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
/** Empty instance of {@link StructuredConfigProperties}. */
final class EmptyStructuredConfigProperties implements StructuredConfigProperties {
/** Empty instance of {@link DeclarativeConfigProperties}. */
final class EmptyDeclarativeConfigProperties implements DeclarativeConfigProperties {
private static final EmptyStructuredConfigProperties INSTANCE =
new EmptyStructuredConfigProperties();
private static final EmptyDeclarativeConfigProperties INSTANCE =
new EmptyDeclarativeConfigProperties();
private EmptyStructuredConfigProperties() {}
private EmptyDeclarativeConfigProperties() {}
static EmptyStructuredConfigProperties getInstance() {
static EmptyDeclarativeConfigProperties getInstance() {
return INSTANCE;
}
@ -60,13 +60,13 @@ final class EmptyStructuredConfigProperties implements StructuredConfigPropertie
@Nullable
@Override
public StructuredConfigProperties getStructured(String name) {
public DeclarativeConfigProperties getStructured(String name) {
return null;
}
@Nullable
@Override
public List<StructuredConfigProperties> getStructuredList(String name) {
public List<DeclarativeConfigProperties> getStructuredList(String name) {
return null;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import io.opentelemetry.api.GlobalOpenTelemetry;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
* This class provides a temporary global accessor for {@link ConfigProvider} until the
* instrumentation config API is marked stable. It will eventually be merged into {@link
* GlobalOpenTelemetry}.
*/
// We intentionally assign to be used for error reporting.
@SuppressWarnings("StaticAssignmentOfThrowable")
public final class GlobalConfigProvider {
private static final AtomicReference<ConfigProvider> instance =
new AtomicReference<>(ConfigProvider.noop());
@SuppressWarnings("NonFinalStaticField")
@Nullable
private static volatile Throwable setInstanceCaller;
private GlobalConfigProvider() {}
/** Returns the globally registered {@link ConfigProvider}. */
// instance cannot be set to null
@SuppressWarnings("NullAway")
public static ConfigProvider get() {
return instance.get();
}
/**
* Sets the global {@link ConfigProvider}. Future calls to {@link #get()} will return the provided
* {@link ConfigProvider} instance. This should be called once as early as possible in your
* application initialization logic.
*
* @throws IllegalStateException when called more than once
*/
public static void set(ConfigProvider configProvider) {
boolean changed = instance.compareAndSet(ConfigProvider.noop(), configProvider);
if (!changed && (configProvider != ConfigProvider.noop())) {
throw new IllegalStateException(
"GlobalConfigProvider.set has already been called. GlobalConfigProvider.set "
+ "must be called only once before any calls to GlobalConfigProvider.get. "
+ "Previous invocation set to cause of this exception.",
setInstanceCaller);
}
setInstanceCaller = new Throwable();
}
/**
* Unsets the global {@link ConfigProvider}. This is only meant to be used from tests which need
* to reconfigure {@link ConfigProvider}.
*/
public static void resetForTest() {
instance.set(ConfigProvider.noop());
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nullable;
/**
* A collection of convenience methods to extract instrumentation config from {@link
* ConfigProvider#getInstrumentationConfig()}.
*/
public class InstrumentationConfigUtil {
/**
* Return a map representation of the peer service map entries in {@code
* .instrumentation.general.peer.service_mapping}, or null if none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static Map<String, String> peerServiceMapping(ConfigProvider configProvider) {
List<DeclarativeConfigProperties> serviceMappingList =
getOrNull(
configProvider,
config -> config.getStructuredList("service_mapping"),
"general",
"peer");
if (serviceMappingList == null) {
return null;
}
Map<String, String> serviceMapping = new LinkedHashMap<>();
serviceMappingList.forEach(
entry -> {
String peer = entry.getString("peer");
String service = entry.getString("service");
if (peer != null && service != null) {
serviceMapping.put(peer, service);
}
});
return serviceMapping.isEmpty() ? null : serviceMapping;
}
/**
* Return {@code .instrumentation.general.http.client.request_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpClientRequestCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("request_captured_headers", String.class),
"general",
"http",
"client");
}
/**
* Return {@code .instrumentation.general.http.client.response_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpClientResponseCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("response_captured_headers", String.class),
"general",
"http",
"client");
}
/**
* Return {@code .instrumentation.general.http.server.request_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpServerRequestCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("request_captured_headers", String.class),
"general",
"http",
"server");
}
/**
* Return {@code .instrumentation.general.http.server.response_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpSeverResponseCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("response_captured_headers", String.class),
"general",
"http",
"server");
}
/**
* Return {@code .instrumentation.java.<instrumentationName>}, or null if none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static DeclarativeConfigProperties javaInstrumentationConfig(
ConfigProvider configProvider, String instrumentationName) {
return getOrNull(configProvider, config -> config.getStructured(instrumentationName), "java");
}
/**
* Walk down the {@code segments} of {@link ConfigProvider#getInstrumentationConfig()} and call
* {@code accessor} on the terminal node. Returns null if {@link
* ConfigProvider#getInstrumentationConfig()} is null, or if null is encountered walking the
* {@code segments}, or if {@code accessor} returns null.
*
* <p>See other methods in {@link InstrumentationConfigUtil} for usage examples.
*/
@Nullable
public static <T> T getOrNull(
ConfigProvider configProvider,
Function<DeclarativeConfigProperties, T> accessor,
String... segments) {
DeclarativeConfigProperties config = configProvider.getInstrumentationConfig();
if (config == null) {
return null;
}
for (String segment : segments) {
config = config.getStructured(segment);
if (config == null) {
return null;
}
}
return accessor.apply(config);
}
private InstrumentationConfigUtil() {}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import org.junit.jupiter.api.Test;
class ConfigProviderTest {
@Test
void noopEquality() {
ConfigProvider noop = ConfigProvider.noop();
assertThat(ConfigProvider.noop()).isSameAs(noop);
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class GlobalConfigProviderTest {
@BeforeAll
static void beforeClass() {
GlobalConfigProvider.resetForTest();
}
@AfterEach
void after() {
GlobalConfigProvider.resetForTest();
}
@Test
void setAndGet() {
assertThat(GlobalConfigProvider.get()).isEqualTo(ConfigProvider.noop());
ConfigProvider configProvider = DeclarativeConfigProperties::empty;
GlobalConfigProvider.set(configProvider);
assertThat(GlobalConfigProvider.get()).isSameAs(configProvider);
}
@Test
void setThenSet() {
ConfigProvider configProvider = DeclarativeConfigProperties::empty;
GlobalConfigProvider.set(configProvider);
assertThatThrownBy(() -> GlobalConfigProvider.set(configProvider))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("GlobalConfigProvider.set has already been called")
.hasStackTraceContaining("setThenSet");
}
}

View File

@ -0,0 +1,169 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration;
import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.YamlDeclarativeConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class InstrumentationConfigUtilTest {
/**
* See <a
* href="https://github.com/open-telemetry/opentelemetry-configuration/blob/main/examples/kitchen-sink.yaml">kitchen-sink.yaml</a>.
*/
private static final String kitchenSinkInstrumentationConfig =
"instrumentation:\n"
+ " general:\n"
+ " peer:\n"
+ " service_mapping:\n"
+ " - peer: 1.2.3.4\n"
+ " service: FooService\n"
+ " - peer: 2.3.4.5\n"
+ " service: BarService\n"
+ " http:\n"
+ " client:\n"
+ " request_captured_headers:\n"
+ " - client-request-header1\n"
+ " - client-request-header2\n"
+ " response_captured_headers:\n"
+ " - client-response-header1\n"
+ " - client-response-header2\n"
+ " server:\n"
+ " request_captured_headers:\n"
+ " - server-request-header1\n"
+ " - server-request-header2\n"
+ " response_captured_headers:\n"
+ " - server-response-header1\n"
+ " - server-response-header2\n"
+ " java:\n"
+ " example:\n"
+ " property: \"value\"";
private static final ConfigProvider kitchenSinkConfigProvider =
toConfigProvider(kitchenSinkInstrumentationConfig);
private static final ConfigProvider emptyInstrumentationConfigProvider =
toConfigProvider("instrumentation:\n");
private static final ConfigProvider emptyGeneralConfigProvider =
toConfigProvider("instrumentation:\n general:\n");
private static final ConfigProvider emptyHttpConfigProvider =
toConfigProvider("instrumentation:\n general:\n http:\n");
private static ConfigProvider toConfigProvider(String configYaml) {
OpenTelemetryConfigurationModel configuration =
DeclarativeConfiguration.parse(
new ByteArrayInputStream(configYaml.getBytes(StandardCharsets.UTF_8)));
return SdkConfigProvider.create(configuration);
}
@Test
void peerServiceMapping() {
assertThat(InstrumentationConfigUtil.peerServiceMapping(kitchenSinkConfigProvider))
.isEqualTo(ImmutableMap.of("1.2.3.4", "FooService", "2.3.4.5", "BarService"));
assertThat(InstrumentationConfigUtil.peerServiceMapping(emptyInstrumentationConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.peerServiceMapping(emptyGeneralConfigProvider)).isNull();
assertThat(InstrumentationConfigUtil.peerServiceMapping(emptyHttpConfigProvider)).isNull();
}
@Test
void httpClientRequestCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("client-request-header1", "client-request-header2"));
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpClientRequestCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void httpClientResponseCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("client-response-header1", "client-response-header2"));
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpClientResponseCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void httpServerRequestCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("server-request-header1", "server-request-header2"));
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpServerRequestCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void httpServerResponseCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpSeverResponseCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("server-response-header1", "server-response-header2"));
assertThat(
InstrumentationConfigUtil.httpSeverResponseCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpSeverResponseCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpSeverResponseCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void javaInstrumentationConfig() {
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(
kitchenSinkConfigProvider, "example"))
.isNotNull()
.isInstanceOfSatisfying(
YamlDeclarativeConfigProperties.class,
exampleConfig ->
assertThat(exampleConfig.toMap()).isEqualTo(ImmutableMap.of("property", "value")));
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(kitchenSinkConfigProvider, "foo"))
.isNull();
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(
emptyInstrumentationConfigProvider, "example"))
.isNull();
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(
emptyGeneralConfigProvider, "example"))
.isNull();
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(emptyHttpConfigProvider, "example"))
.isNull();
}
}

View File

@ -13,6 +13,7 @@ dependencies {
api(project(":api:all"))
api(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":api:incubator"))
compileOnly(project(":sdk:common"))
compileOnly(project(":exporters:common:compile-stub"))

View File

@ -9,7 +9,6 @@ import static io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
@ -63,22 +62,6 @@ public final class ExporterBuilderUtil {
memoryModeConsumer.accept(memoryMode);
}
/** Invoke the {@code memoryModeConsumer} with the configured {@link MemoryMode}. */
public static void configureExporterMemoryMode(
StructuredConfigProperties config, Consumer<MemoryMode> memoryModeConsumer) {
String memoryModeStr = config.getString("memory_mode");
if (memoryModeStr == null) {
return;
}
MemoryMode memoryMode;
try {
memoryMode = MemoryMode.valueOf(memoryModeStr.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Unrecognized memory_mode: " + memoryModeStr, e);
}
memoryModeConsumer.accept(memoryMode);
}
/**
* Invoke the {@code defaultAggregationSelectorConsumer} with the configured {@link
* DefaultAggregationSelector}.
@ -126,30 +109,6 @@ public final class ExporterBuilderUtil {
aggregationTemporalitySelectorConsumer.accept(temporalitySelector);
}
public static void configureOtlpAggregationTemporality(
StructuredConfigProperties config,
Consumer<AggregationTemporalitySelector> aggregationTemporalitySelectorConsumer) {
String temporalityStr = config.getString("temporality_preference");
if (temporalityStr == null) {
return;
}
AggregationTemporalitySelector temporalitySelector;
switch (temporalityStr.toLowerCase(Locale.ROOT)) {
case "cumulative":
temporalitySelector = AggregationTemporalitySelector.alwaysCumulative();
break;
case "delta":
temporalitySelector = AggregationTemporalitySelector.deltaPreferred();
break;
case "lowmemory":
temporalitySelector = AggregationTemporalitySelector.lowMemory();
break;
default:
throw new ConfigurationException("Unrecognized temporality_preference: " + temporalityStr);
}
aggregationTemporalitySelectorConsumer.accept(temporalitySelector);
}
/**
* Invoke the {@code defaultAggregationSelectorConsumer} with the configured {@link
* DefaultAggregationSelector}.
@ -165,28 +124,5 @@ public final class ExporterBuilderUtil {
}
}
/**
* Invoke the {@code defaultAggregationSelectorConsumer} with the configured {@link
* DefaultAggregationSelector}.
*/
public static void configureOtlpHistogramDefaultAggregation(
StructuredConfigProperties config,
Consumer<DefaultAggregationSelector> defaultAggregationSelectorConsumer) {
String defaultHistogramAggregation = config.getString("default_histogram_aggregation");
if (defaultHistogramAggregation == null) {
return;
}
if (AggregationUtil.aggregationName(Aggregation.base2ExponentialBucketHistogram())
.equalsIgnoreCase(defaultHistogramAggregation)) {
defaultAggregationSelectorConsumer.accept(
DefaultAggregationSelector.getDefault()
.with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram()));
} else if (!AggregationUtil.aggregationName(explicitBucketHistogram())
.equalsIgnoreCase(defaultHistogramAggregation)) {
throw new ConfigurationException(
"Unrecognized default_histogram_aggregation: " + defaultHistogramAggregation);
}
}
private ExporterBuilderUtil() {}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.internal;
import static io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector;
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregationUtil;
import java.util.Locale;
import java.util.function.Consumer;
/**
* Utilities for exporter builders.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public final class IncubatingExporterBuilderUtil {
/** Invoke the {@code memoryModeConsumer} with the configured {@link MemoryMode}. */
public static void configureExporterMemoryMode(
DeclarativeConfigProperties config, Consumer<MemoryMode> memoryModeConsumer) {
String memoryModeStr = config.getString("memory_mode");
if (memoryModeStr == null) {
return;
}
MemoryMode memoryMode;
try {
memoryMode = MemoryMode.valueOf(memoryModeStr.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Unrecognized memory_mode: " + memoryModeStr, e);
}
memoryModeConsumer.accept(memoryMode);
}
public static void configureOtlpAggregationTemporality(
DeclarativeConfigProperties config,
Consumer<AggregationTemporalitySelector> aggregationTemporalitySelectorConsumer) {
String temporalityStr = config.getString("temporality_preference");
if (temporalityStr == null) {
return;
}
AggregationTemporalitySelector temporalitySelector;
switch (temporalityStr.toLowerCase(Locale.ROOT)) {
case "cumulative":
temporalitySelector = AggregationTemporalitySelector.alwaysCumulative();
break;
case "delta":
temporalitySelector = AggregationTemporalitySelector.deltaPreferred();
break;
case "lowmemory":
temporalitySelector = AggregationTemporalitySelector.lowMemory();
break;
default:
throw new ConfigurationException("Unrecognized temporality_preference: " + temporalityStr);
}
aggregationTemporalitySelectorConsumer.accept(temporalitySelector);
}
/**
* Invoke the {@code defaultAggregationSelectorConsumer} with the configured {@link
* DefaultAggregationSelector}.
*/
public static void configureOtlpHistogramDefaultAggregation(
DeclarativeConfigProperties config,
Consumer<DefaultAggregationSelector> defaultAggregationSelectorConsumer) {
String defaultHistogramAggregation = config.getString("default_histogram_aggregation");
if (defaultHistogramAggregation == null) {
return;
}
if (AggregationUtil.aggregationName(Aggregation.base2ExponentialBucketHistogram())
.equalsIgnoreCase(defaultHistogramAggregation)) {
defaultAggregationSelectorConsumer.accept(
DefaultAggregationSelector.getDefault()
.with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram()));
} else if (!AggregationUtil.aggregationName(explicitBucketHistogram())
.equalsIgnoreCase(defaultHistogramAggregation)) {
throw new ConfigurationException(
"Unrecognized default_histogram_aggregation: " + defaultHistogramAggregation);
}
}
private IncubatingExporterBuilderUtil() {}
}

View File

@ -14,10 +14,12 @@ dependencies {
implementation(project(":sdk:logs"))
implementation(project(":exporters:otlp:common"))
compileOnly(project(":api:incubator"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
implementation("com.fasterxml.jackson.core:jackson-core")
testImplementation(project(":api:incubator"))
testImplementation(project(":sdk:testing"))
testImplementation("com.google.guava:guava")

View File

@ -5,9 +5,9 @@
package io.opentelemetry.exporter.logging.otlp.internal.logs;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.internal.IncubatingExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
/**
@ -30,9 +30,9 @@ public final class OtlpStdoutLogRecordExporterComponentProvider
}
@Override
public LogRecordExporter create(StructuredConfigProperties config) {
public LogRecordExporter create(DeclarativeConfigProperties config) {
OtlpStdoutLogRecordExporterBuilder builder = OtlpStdoutLogRecordExporter.builder();
ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode);
IncubatingExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode);
return builder.build();
}
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.exporter.logging.otlp.internal.metrics;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.internal.IncubatingExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
/**
@ -30,12 +30,12 @@ public final class OtlpStdoutMetricExporterComponentProvider
}
@Override
public MetricExporter create(StructuredConfigProperties config) {
public MetricExporter create(DeclarativeConfigProperties config) {
OtlpStdoutMetricExporterBuilder builder = OtlpStdoutMetricExporter.builder();
ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode);
ExporterBuilderUtil.configureOtlpAggregationTemporality(
IncubatingExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode);
IncubatingExporterBuilderUtil.configureOtlpAggregationTemporality(
config, builder::setAggregationTemporalitySelector);
ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
IncubatingExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
config, builder::setDefaultAggregationSelector);
return builder.build();
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.exporter.logging.otlp.internal.traces;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.internal.IncubatingExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.trace.export.SpanExporter;
/**
@ -30,9 +30,9 @@ public final class OtlpStdoutSpanExporterComponentProvider
}
@Override
public SpanExporter create(StructuredConfigProperties config) {
public SpanExporter create(DeclarativeConfigProperties config) {
OtlpStdoutSpanExporterBuilder builder = OtlpStdoutSpanExporter.builder();
ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode);
IncubatingExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode);
return builder.build();
}
}

View File

@ -15,10 +15,10 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
@ -306,7 +306,7 @@ abstract class AbstractOtlpStdoutExporterTest<T> {
@Test
void componentProviderConfig() {
StructuredConfigProperties properties = mock(StructuredConfigProperties.class);
DeclarativeConfigProperties properties = mock(DeclarativeConfigProperties.class);
T exporter = exporterFromComponentProvider(properties);
assertThat(exporter).extracting("wrapperJsonObject").isEqualTo(true);
@ -328,7 +328,7 @@ abstract class AbstractOtlpStdoutExporterTest<T> {
}
@SuppressWarnings("unchecked")
protected T exporterFromComponentProvider(StructuredConfigProperties properties) {
protected T exporterFromComponentProvider(DeclarativeConfigProperties properties) {
return (T)
((ComponentProvider<?>)
loadSpi(ComponentProvider.class)

View File

@ -11,10 +11,10 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.logging.otlp.internal.metrics.OtlpStdoutMetricExporter;
import io.opentelemetry.exporter.logging.otlp.internal.metrics.OtlpStdoutMetricExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
@ -81,7 +81,7 @@ class OtlpStdoutMetricExporterTest
@Test
void componentProviderMetricConfig() {
StructuredConfigProperties properties = mock(StructuredConfigProperties.class);
DeclarativeConfigProperties properties = mock(DeclarativeConfigProperties.class);
when(properties.getString("temporality_preference")).thenReturn("DELTA");
when(properties.getString("default_histogram_aggregation"))
.thenReturn("BASE2_EXPONENTIAL_BUCKET_HISTOGRAM");

View File

@ -12,6 +12,7 @@ dependencies {
api(project(":sdk:all"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":api:incubator"))
testImplementation(project(":sdk:testing"))
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.exporter.logging.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
/**
@ -30,7 +30,7 @@ public final class ConsoleLogRecordExporterComponentProvider
}
@Override
public LogRecordExporter create(StructuredConfigProperties config) {
public LogRecordExporter create(DeclarativeConfigProperties config) {
return SystemOutLogRecordExporter.create();
}
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.exporter.logging.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
/**
@ -30,7 +30,7 @@ public final class ConsoleMetricExporterComponentProvider
}
@Override
public MetricExporter create(StructuredConfigProperties config) {
public MetricExporter create(DeclarativeConfigProperties config) {
return LoggingMetricExporter.create();
}
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.exporter.logging.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.trace.export.SpanExporter;
/**
@ -29,7 +29,7 @@ public final class ConsoleSpanExporterComponentProvider implements ComponentProv
}
@Override
public SpanExporter create(StructuredConfigProperties config) {
public SpanExporter create(DeclarativeConfigProperties config) {
return LoggingSpanExporter.create();
}
}

View File

@ -20,6 +20,8 @@ dependencies {
implementation(project(":exporters:sender:okhttp"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":api:incubator"))
compileOnly("io.grpc:grpc-stub")
testImplementation(project(":exporters:otlp:testing-internal"))

View File

@ -8,8 +8,6 @@ package io.opentelemetry.exporter.otlp.internal;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.RetryPolicy;
import java.io.File;
@ -20,8 +18,6 @@ import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@ -52,18 +48,6 @@ public final class OtlpConfigUtil {
return config.getString("otel.exporter.otlp.protocol", PROTOCOL_GRPC);
}
/** Determine the configured OTLP protocol for the {@code dataType}. */
public static String getStructuredConfigOtlpProtocol(StructuredConfigProperties config) {
// NOTE: The default OTLP protocol is different for declarative config than for env var / system
// property based config. This is intentional. OpenTelemetry changed the default protocol
// recommendation from grpc to http/protobuf, but the autoconfigure's env var / system property
// based config did not update to reflect this before stabilizing, and changing is a breaking
// change requiring a major version bump. Declarative config is not yet stable and therefore can
// switch to the current default recommendation, which aligns also aligns with the behavior of
// the OpenTelemetry Java Agent 2.x+.
return config.getString("protocol", PROTOCOL_HTTP_PROTOBUF);
}
/** Invoke the setters with the OTLP configuration for the {@code dataType}. */
@SuppressWarnings("TooManyParameters")
public static void configureOtlpExporterBuilder(
@ -164,81 +148,7 @@ public final class OtlpConfigUtil {
ExporterBuilderUtil.configureExporterMemoryMode(config, setMemoryMode);
}
/** Invoke the setters with the OTLP configuration for the {@code dataType}. */
@SuppressWarnings("TooManyParameters")
public static void configureOtlpExporterBuilder(
String dataType,
StructuredConfigProperties config,
Consumer<String> setEndpoint,
BiConsumer<String, String> addHeader,
Consumer<String> setCompression,
Consumer<Duration> setTimeout,
Consumer<byte[]> setTrustedCertificates,
BiConsumer<byte[], byte[]> setClientTls,
Consumer<RetryPolicy> setRetryPolicy,
Consumer<MemoryMode> setMemoryMode) {
String protocol = getStructuredConfigOtlpProtocol(config);
boolean isHttpProtobuf = protocol.equals(PROTOCOL_HTTP_PROTOBUF);
URL endpoint = validateEndpoint(config.getString("endpoint"), isHttpProtobuf);
if (endpoint != null) {
setEndpoint.accept(endpoint.toString());
}
String headerList = config.getString("headers_list");
if (headerList != null) {
ConfigProperties headersListConfig =
DefaultConfigProperties.createFromMap(
Collections.singletonMap("otel.exporter.otlp.headers", headerList));
configureOtlpHeaders(headersListConfig, dataType, addHeader);
}
List<StructuredConfigProperties> headers = config.getStructuredList("headers");
if (headers != null) {
headers.forEach(
header -> {
String name = header.getString("name");
String value = header.getString("value");
if (name != null && value != null) {
addHeader.accept(name, value);
}
});
}
String compression = config.getString("compression");
if (compression != null) {
setCompression.accept(compression);
}
Integer timeoutMs = config.getInt("timeout");
if (timeoutMs != null) {
setTimeout.accept(Duration.ofMillis(timeoutMs));
}
String certificatePath = config.getString("certificate");
String clientKeyPath = config.getString("client_key");
String clientKeyChainPath = config.getString("client_certificate");
if (clientKeyPath != null && clientKeyChainPath == null) {
throw new ConfigurationException(
"client_key provided without client_certificate - both client_key and client_certificate must be set");
} else if (clientKeyPath == null && clientKeyChainPath != null) {
throw new ConfigurationException(
"client_certificate provided without client_key - both client_key and client_certificate must be set");
}
byte[] certificateBytes = readFileBytes(certificatePath);
if (certificateBytes != null) {
setTrustedCertificates.accept(certificateBytes);
}
byte[] clientKeyBytes = readFileBytes(clientKeyPath);
byte[] clientKeyChainBytes = readFileBytes(clientKeyChainPath);
if (clientKeyBytes != null && clientKeyChainBytes != null) {
setClientTls.accept(clientKeyBytes, clientKeyChainBytes);
}
ExporterBuilderUtil.configureExporterMemoryMode(config, setMemoryMode);
}
private static void configureOtlpHeaders(
static void configureOtlpHeaders(
ConfigProperties config, String dataType, BiConsumer<String, String> addHeader) {
Map<String, String> headers = config.getMap("otel.exporter.otlp." + dataType + ".headers");
if (headers.isEmpty()) {
@ -266,7 +176,7 @@ public final class OtlpConfigUtil {
}
@Nullable
private static URL validateEndpoint(@Nullable String endpoint, boolean isHttpProtobuf) {
static URL validateEndpoint(@Nullable String endpoint, boolean isHttpProtobuf) {
if (endpoint == null) {
return null;
}
@ -314,7 +224,7 @@ public final class OtlpConfigUtil {
}
@Nullable
private static byte[] readFileBytes(@Nullable String filePath) {
static byte[] readFileBytes(@Nullable String filePath) {
if (filePath == null) {
return null;
}

View File

@ -0,0 +1,120 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.internal;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.configureOtlpHeaders;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.readFileBytes;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.validateEndpoint;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.internal.IncubatingExporterBuilderUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.RetryPolicy;
import java.net.URL;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class OtlpDeclarativeConfigUtil {
/** Determine the configured OTLP protocol for the {@code dataType}. */
public static String getStructuredConfigOtlpProtocol(DeclarativeConfigProperties config) {
// NOTE: The default OTLP protocol is different for declarative config than for env var / system
// property based config. This is intentional. OpenTelemetry changed the default protocol
// recommendation from grpc to http/protobuf, but the autoconfigure's env var / system property
// based config did not update to reflect this before stabilizing, and changing is a breaking
// change requiring a major version bump. Declarative config is not yet stable and therefore can
// switch to the current default recommendation, which aligns also aligns with the behavior of
// the OpenTelemetry Java Agent 2.x+.
return config.getString("protocol", PROTOCOL_HTTP_PROTOBUF);
}
/** Invoke the setters with the OTLP configuration for the {@code dataType}. */
@SuppressWarnings("TooManyParameters")
public static void configureOtlpExporterBuilder(
String dataType,
DeclarativeConfigProperties config,
Consumer<String> setEndpoint,
BiConsumer<String, String> addHeader,
Consumer<String> setCompression,
Consumer<Duration> setTimeout,
Consumer<byte[]> setTrustedCertificates,
BiConsumer<byte[], byte[]> setClientTls,
Consumer<RetryPolicy> setRetryPolicy,
Consumer<MemoryMode> setMemoryMode) {
String protocol = getStructuredConfigOtlpProtocol(config);
boolean isHttpProtobuf = protocol.equals(PROTOCOL_HTTP_PROTOBUF);
URL endpoint = validateEndpoint(config.getString("endpoint"), isHttpProtobuf);
if (endpoint != null) {
setEndpoint.accept(endpoint.toString());
}
String headerList = config.getString("headers_list");
if (headerList != null) {
ConfigProperties headersListConfig =
DefaultConfigProperties.createFromMap(
Collections.singletonMap("otel.exporter.otlp.headers", headerList));
configureOtlpHeaders(headersListConfig, dataType, addHeader);
}
List<DeclarativeConfigProperties> headers = config.getStructuredList("headers");
if (headers != null) {
headers.forEach(
header -> {
String name = header.getString("name");
String value = header.getString("value");
if (name != null && value != null) {
addHeader.accept(name, value);
}
});
}
String compression = config.getString("compression");
if (compression != null) {
setCompression.accept(compression);
}
Integer timeoutMs = config.getInt("timeout");
if (timeoutMs != null) {
setTimeout.accept(Duration.ofMillis(timeoutMs));
}
String certificatePath = config.getString("certificate");
String clientKeyPath = config.getString("client_key");
String clientKeyChainPath = config.getString("client_certificate");
if (clientKeyPath != null && clientKeyChainPath == null) {
throw new ConfigurationException(
"client_key provided without client_certificate - both client_key and client_certificate must be set");
} else if (clientKeyPath == null && clientKeyChainPath != null) {
throw new ConfigurationException(
"client_certificate provided without client_key - both client_key and client_certificate must be set");
}
byte[] certificateBytes = readFileBytes(certificatePath);
if (certificateBytes != null) {
setTrustedCertificates.accept(certificateBytes);
}
byte[] clientKeyBytes = readFileBytes(clientKeyPath);
byte[] clientKeyChainBytes = readFileBytes(clientKeyChainPath);
if (clientKeyBytes != null && clientKeyChainBytes != null) {
setClientTls.accept(clientKeyBytes, clientKeyChainBytes);
}
IncubatingExporterBuilderUtil.configureExporterMemoryMode(config, setMemoryMode);
}
private OtlpDeclarativeConfigUtil() {}
}

View File

@ -9,13 +9,13 @@ import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.DATA_TYPE_L
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_GRPC;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
/**
@ -39,13 +39,13 @@ public class OtlpLogRecordExporterComponentProvider
}
@Override
public LogRecordExporter create(StructuredConfigProperties config) {
String protocol = OtlpConfigUtil.getStructuredConfigOtlpProtocol(config);
public LogRecordExporter create(DeclarativeConfigProperties config) {
String protocol = OtlpDeclarativeConfigUtil.getStructuredConfigOtlpProtocol(config);
if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) {
OtlpHttpLogRecordExporterBuilder builder = httpBuilder();
OtlpConfigUtil.configureOtlpExporterBuilder(
OtlpDeclarativeConfigUtil.configureOtlpExporterBuilder(
DATA_TYPE_LOGS,
config,
builder::setEndpoint,
@ -61,7 +61,7 @@ public class OtlpLogRecordExporterComponentProvider
} else if (protocol.equals(PROTOCOL_GRPC)) {
OtlpGrpcLogRecordExporterBuilder builder = grpcBuilder();
OtlpConfigUtil.configureOtlpExporterBuilder(
OtlpDeclarativeConfigUtil.configureOtlpExporterBuilder(
DATA_TYPE_LOGS,
config,
builder::setEndpoint,

View File

@ -9,14 +9,14 @@ import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.DATA_TYPE_M
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_GRPC;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.internal.IncubatingExporterBuilderUtil;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
/**
@ -39,13 +39,13 @@ public class OtlpMetricExporterComponentProvider implements ComponentProvider<Me
}
@Override
public MetricExporter create(StructuredConfigProperties config) {
String protocol = OtlpConfigUtil.getStructuredConfigOtlpProtocol(config);
public MetricExporter create(DeclarativeConfigProperties config) {
String protocol = OtlpDeclarativeConfigUtil.getStructuredConfigOtlpProtocol(config);
if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) {
OtlpHttpMetricExporterBuilder builder = httpBuilder();
OtlpConfigUtil.configureOtlpExporterBuilder(
OtlpDeclarativeConfigUtil.configureOtlpExporterBuilder(
DATA_TYPE_METRICS,
config,
builder::setEndpoint,
@ -56,16 +56,16 @@ public class OtlpMetricExporterComponentProvider implements ComponentProvider<Me
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
ExporterBuilderUtil.configureOtlpAggregationTemporality(
IncubatingExporterBuilderUtil.configureOtlpAggregationTemporality(
config, builder::setAggregationTemporalitySelector);
ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
IncubatingExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
config, builder::setDefaultAggregationSelector);
return builder.build();
} else if (protocol.equals(PROTOCOL_GRPC)) {
OtlpGrpcMetricExporterBuilder builder = grpcBuilder();
OtlpConfigUtil.configureOtlpExporterBuilder(
OtlpDeclarativeConfigUtil.configureOtlpExporterBuilder(
DATA_TYPE_METRICS,
config,
builder::setEndpoint,
@ -76,9 +76,9 @@ public class OtlpMetricExporterComponentProvider implements ComponentProvider<Me
builder::setClientTls,
builder::setRetryPolicy,
builder::setMemoryMode);
ExporterBuilderUtil.configureOtlpAggregationTemporality(
IncubatingExporterBuilderUtil.configureOtlpAggregationTemporality(
config, builder::setAggregationTemporalitySelector);
ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
IncubatingExporterBuilderUtil.configureOtlpHistogramDefaultAggregation(
config, builder::setDefaultAggregationSelector);
return builder.build();

View File

@ -9,13 +9,13 @@ import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.DATA_TYPE_T
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_GRPC;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.trace.export.SpanExporter;
/**
@ -38,13 +38,13 @@ public class OtlpSpanExporterComponentProvider implements ComponentProvider<Span
}
@Override
public SpanExporter create(StructuredConfigProperties config) {
String protocol = OtlpConfigUtil.getStructuredConfigOtlpProtocol(config);
public SpanExporter create(DeclarativeConfigProperties config) {
String protocol = OtlpDeclarativeConfigUtil.getStructuredConfigOtlpProtocol(config);
if (protocol.equals(PROTOCOL_HTTP_PROTOBUF)) {
OtlpHttpSpanExporterBuilder builder = httpBuilder();
OtlpConfigUtil.configureOtlpExporterBuilder(
OtlpDeclarativeConfigUtil.configureOtlpExporterBuilder(
DATA_TYPE_TRACES,
config,
builder::setEndpoint,
@ -60,7 +60,7 @@ public class OtlpSpanExporterComponentProvider implements ComponentProvider<Span
} else if (protocol.equals(PROTOCOL_GRPC)) {
OtlpGrpcSpanExporterBuilder builder = grpcBuilder();
OtlpConfigUtil.configureOtlpExporterBuilder(
OtlpDeclarativeConfigUtil.configureOtlpExporterBuilder(
DATA_TYPE_TRACES,
config,
builder::setEndpoint,

View File

@ -9,6 +9,7 @@ otelJava.moduleName.set("io.opentelemetry.exporter.prometheus")
dependencies {
api(project(":sdk:metrics"))
compileOnly(project(":api:incubator"))
implementation(project(":exporters:common"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
implementation("io.prometheus:prometheus-metrics-exporter-httpserver")

View File

@ -5,10 +5,10 @@
package io.opentelemetry.exporter.prometheus.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServerBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.metrics.export.MetricReader;
/**
@ -30,7 +30,7 @@ public class PrometheusComponentProvider implements ComponentProvider<MetricRead
}
@Override
public MetricReader create(StructuredConfigProperties config) {
public MetricReader create(DeclarativeConfigProperties config) {
PrometheusHttpServerBuilder prometheusBuilder = PrometheusHttpServer.builder();
Integer port = config.getInt("port");

View File

@ -15,6 +15,7 @@ dependencies {
implementation(project(":exporters:common"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":api:incubator"))
implementation("io.zipkin.reporter2:zipkin-sender-okhttp3")

View File

@ -5,10 +5,10 @@
package io.opentelemetry.exporter.zipkin.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.time.Duration;
@ -30,7 +30,7 @@ public class ZipkinSpanExporterComponentProvider implements ComponentProvider<Sp
}
@Override
public SpanExporter create(StructuredConfigProperties config) {
public SpanExporter create(DeclarativeConfigProperties config) {
ZipkinSpanExporterBuilder builder = ZipkinSpanExporter.builder();
String endpoint = config.getString("endpoint");

View File

@ -12,6 +12,7 @@ otelJava.moduleName.set("io.opentelemetry.extension.trace.propagation")
dependencies {
api(project(":api:all"))
compileOnly(project(":api:incubator"))
compileOnly(project(":sdk-extensions:autoconfigure-spi"))
testImplementation("io.jaegertracing:jaeger-client")

View File

@ -5,10 +5,10 @@
package io.opentelemetry.extension.trace.propagation.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
/**
* Declarative configuration SPI implementation for {@link B3Propagator} which allows enables the
@ -30,7 +30,7 @@ public final class B3ComponentProvider implements ComponentProvider<TextMapPropa
}
@Override
public TextMapPropagator create(StructuredConfigProperties config) {
public TextMapPropagator create(DeclarativeConfigProperties config) {
return B3Propagator.injectingSingleHeader();
}
}

View File

@ -5,10 +5,10 @@
package io.opentelemetry.extension.trace.propagation.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
/**
* Declarative configuration SPI implementation for {@link B3Propagator} which allows enables the
@ -30,7 +30,7 @@ public final class B3MultiComponentProvider implements ComponentProvider<TextMap
}
@Override
public TextMapPropagator create(StructuredConfigProperties config) {
public TextMapPropagator create(DeclarativeConfigProperties config) {
return B3Propagator.injectingMultiHeaders();
}
}

View File

@ -5,10 +5,10 @@
package io.opentelemetry.extension.trace.propagation.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.JaegerPropagator;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
/**
* Declarative configuration SPI implementation for {@link JaegerPropagator}.
@ -29,7 +29,7 @@ public final class JaegerComponentProvider implements ComponentProvider<TextMapP
}
@Override
public TextMapPropagator create(StructuredConfigProperties config) {
public TextMapPropagator create(DeclarativeConfigProperties config) {
return JaegerPropagator.getInstance();
}
}

View File

@ -5,11 +5,11 @@
package io.opentelemetry.extension.trace.propagation.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.extension.trace.propagation.OtTracePropagator;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
/**
* Declarative configuration SPI implementation for {@link B3Propagator}.
@ -30,7 +30,7 @@ public final class OtTraceComponentProvider implements ComponentProvider<TextMap
}
@Override
public TextMapPropagator create(StructuredConfigProperties config) {
public TextMapPropagator create(DeclarativeConfigProperties config) {
return OtTracePropagator.getInstance();
}
}

View File

@ -8,4 +8,5 @@ otelJava.moduleName.set("io.opentelemetry.sdk.autoconfigure.spi")
dependencies {
api(project(":sdk:all"))
compileOnly(project(":api:incubator"))
}

View File

@ -5,6 +5,7 @@
package io.opentelemetry.sdk.autoconfigure.spi.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.sdk.logs.LogRecordProcessor;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
@ -20,8 +21,8 @@ import io.opentelemetry.sdk.trace.samplers.Sampler;
* configuration.
*
* <p>NOTE: when {@link #getType()} is {@link Resource}, the {@link #getName()} is not (currently)
* used, and {@link #create(StructuredConfigProperties)} is (currently) called with an empty {@link
* StructuredConfigProperties}.
* used, and {@link #create(DeclarativeConfigProperties)} is (currently) called with an empty {@link
* DeclarativeConfigProperties}.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
@ -58,5 +59,5 @@ public interface ComponentProvider<T> {
*/
// TODO (jack-berg): consider dynamic configuration use case before stabilizing in case that
// affects any API decisions
T create(StructuredConfigProperties config);
T create(DeclarativeConfigProperties config);
}

View File

@ -10,6 +10,8 @@ dependencies {
api(project(":sdk:all"))
api(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":api:incubator"))
annotationProcessor("com.google.auto.value:auto-value")
testImplementation(project(":sdk:trace-shaded-deps"))
@ -45,7 +47,6 @@ testing {
}
register<JvmTestSuite>("testFullConfig") {
dependencies {
implementation(project(":api:incubator"))
implementation(project(":extensions:trace-propagators"))
implementation(project(":exporters:logging"))
implementation(project(":exporters:logging-otlp"))
@ -78,6 +79,13 @@ testing {
}
}
}
register<JvmTestSuite>("testIncubating") {
dependencies {
implementation(project(":sdk-extensions:incubator"))
implementation(project(":exporters:logging"))
implementation(project(":sdk:testing"))
}
}
}
}

View File

@ -8,9 +8,10 @@ package io.opentelemetry.sdk.autoconfigure;
import com.google.auto.value.AutoValue;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@ -48,9 +49,8 @@ public abstract class AutoConfiguredOpenTelemetrySdk {
OpenTelemetrySdk sdk,
Resource resource,
@Nullable ConfigProperties config,
@Nullable StructuredConfigProperties structuredConfigProperties) {
return new AutoValue_AutoConfiguredOpenTelemetrySdk(
sdk, resource, config, structuredConfigProperties);
@Nullable Object configProvider) {
return new AutoValue_AutoConfiguredOpenTelemetrySdk(sdk, resource, config, configProvider);
}
/**
@ -70,19 +70,24 @@ public abstract class AutoConfiguredOpenTelemetrySdk {
* Returns the {@link ConfigProperties} used for auto-configuration, or {@code null} if
* declarative configuration was used.
*
* @see #getStructuredConfig()
* <p>This method is experimental so not public. You may reflectively call it using {@link
* AutoConfigureUtil#getConfig(AutoConfiguredOpenTelemetrySdk)}.
*
* @see #getConfigProvider()
*/
@Nullable
abstract ConfigProperties getConfig();
/**
* Returns the {@link StructuredConfigProperties} used for auto-configuration, or {@code null} if
* declarative configuration was not used.
* Returns the {@link ConfigProvider}, or {@code null} if declarative configuration was not used.
*
* <p>This method is experimental so not public. You may reflectively call it using {@link
* AutoConfigureUtil#getConfigProvider(AutoConfiguredOpenTelemetrySdk)}.
*
* @see #getConfig()
*/
@Nullable
abstract StructuredConfigProperties getStructuredConfig();
abstract Object getConfigProvider();
AutoConfiguredOpenTelemetrySdk() {}
}

View File

@ -20,7 +20,6 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.logs.LogRecordProcessor;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
@ -36,12 +35,7 @@ import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -65,6 +59,18 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
private static final Logger logger =
Logger.getLogger(AutoConfiguredOpenTelemetrySdkBuilder.class.getName());
private static final boolean INCUBATOR_AVAILABLE;
static {
boolean incubatorAvailable = false;
try {
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration");
incubatorAvailable = true;
} catch (ClassNotFoundException e) {
// Not available
}
INCUBATOR_AVAILABLE = incubatorAvailable;
}
@Nullable private ConfigProperties config;
@ -431,7 +437,8 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
maybeConfigureFromFile(config, componentLoader);
if (fromFileConfiguration != null) {
maybeRegisterShutdownHook(fromFileConfiguration.getOpenTelemetrySdk());
maybeSetAsGlobal(fromFileConfiguration.getOpenTelemetrySdk());
maybeSetAsGlobal(
fromFileConfiguration.getOpenTelemetrySdk(), fromFileConfiguration.getConfigProvider());
return fromFileConfiguration;
}
@ -457,7 +464,7 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
OpenTelemetrySdk openTelemetrySdk = sdkBuilder.build();
maybeRegisterShutdownHook(openTelemetrySdk);
maybeSetAsGlobal(openTelemetrySdk);
maybeSetAsGlobal(openTelemetrySdk, null);
callAutoConfigureListeners(spiHelper, openTelemetrySdk);
return AutoConfiguredOpenTelemetrySdk.create(openTelemetrySdk, resource, config, null);
@ -548,44 +555,11 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
if (configurationFile == null || configurationFile.isEmpty()) {
return null;
}
logger.fine("Autoconfiguring from configuration file: " + configurationFile);
try (FileInputStream fis = new FileInputStream(configurationFile)) {
Class<?> configurationFactory =
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfiguration");
Method parse = configurationFactory.getMethod("parse", InputStream.class);
Object model = parse.invoke(null, fis);
Class<?> openTelemetryConfiguration =
Class.forName(
"io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel");
Method create =
configurationFactory.getMethod(
"create", openTelemetryConfiguration, ComponentLoader.class);
OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader);
Method toConfigProperties =
configurationFactory.getMethod("toConfigProperties", openTelemetryConfiguration);
StructuredConfigProperties structuredConfigProperties =
(StructuredConfigProperties) toConfigProperties.invoke(null, model);
// Note: can't access declarative configuration resource without reflection so setting a dummy
// resource
return AutoConfiguredOpenTelemetrySdk.create(
sdk, Resource.getDefault(), null, structuredConfigProperties);
} catch (FileNotFoundException e) {
throw new ConfigurationException("Configuration file not found", e);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
if (!INCUBATOR_AVAILABLE) {
throw new ConfigurationException(
"Error configuring from file. Is opentelemetry-sdk-extension-incubator on the classpath?",
e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof ConfigurationException) {
throw (ConfigurationException) cause;
}
throw new ConfigurationException("Unexpected error configuring from file", e);
} catch (IOException e) {
// IOException (other than FileNotFoundException which is caught above) is only thrown
// above by FileInputStream.close()
throw new ConfigurationException("Error closing file", e);
"Cannot autoconfigure from config file without opentelemetry-sdk-extension-incubator on the classpath");
}
return IncubatingUtil.configureFromFile(logger, configurationFile, componentLoader);
}
private void maybeRegisterShutdownHook(OpenTelemetrySdk openTelemetrySdk) {
@ -595,11 +569,15 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
Runtime.getRuntime().addShutdownHook(shutdownHook(openTelemetrySdk));
}
private void maybeSetAsGlobal(OpenTelemetrySdk openTelemetrySdk) {
private void maybeSetAsGlobal(
OpenTelemetrySdk openTelemetrySdk, @Nullable Object configProvider) {
if (!setResultAsGlobal) {
return;
}
GlobalOpenTelemetry.set(openTelemetrySdk);
if (INCUBATOR_AVAILABLE && configProvider != null) {
IncubatingUtil.setGlobalConfigProvider(configProvider);
}
logger.log(
Level.FINE, "Global OpenTelemetry set to {0} by autoconfiguration", openTelemetrySdk);
}

View File

@ -0,0 +1,88 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.autoconfigure;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.GlobalConfigProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.resources.Resource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.logging.Logger;
/**
* Utilities for interacting with incubating components ({@code
* io.opentelemetry:opentelemetry-api-incubator} and {@code
* io.opentelemetry:opentelemetry-sdk-extension-incubator}), which are not guaranteed to be present
* on the classpath. For all methods, callers MUST first separately reflectively confirm that the
* incubator is available on the classpath.
*/
final class IncubatingUtil {
private IncubatingUtil() {}
static AutoConfiguredOpenTelemetrySdk configureFromFile(
Logger logger, String configurationFile, ComponentLoader componentLoader) {
logger.fine("Autoconfiguring from configuration file: " + configurationFile);
try (FileInputStream fis = new FileInputStream(configurationFile)) {
Class<?> declarativeConfiguration =
Class.forName(
"io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration");
Method parse = declarativeConfiguration.getMethod("parse", InputStream.class);
Object model = parse.invoke(null, fis);
Class<?> openTelemetryConfiguration =
Class.forName(
"io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel");
Method create =
declarativeConfiguration.getMethod(
"create", openTelemetryConfiguration, ComponentLoader.class);
OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader);
Class<?> sdkConfigProvider =
Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider");
Method createFileConfigProvider =
sdkConfigProvider.getMethod("create", openTelemetryConfiguration);
ConfigProvider configProvider = (ConfigProvider) createFileConfigProvider.invoke(null, model);
// Note: can't access file configuration resource without reflection so setting a dummy
// resource
return AutoConfiguredOpenTelemetrySdk.create(
sdk, Resource.getDefault(), null, configProvider);
} catch (FileNotFoundException e) {
throw new ConfigurationException("Configuration file not found", e);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new ConfigurationException(
"Error configuring from file. Is opentelemetry-sdk-extension-incubator on the classpath?",
e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof DeclarativeConfigException) {
throw toConfigurationException((DeclarativeConfigException) cause);
}
throw new ConfigurationException("Unexpected error configuring from file", e);
} catch (IOException e) {
// IOException (other than FileNotFoundException which is caught above) is only thrown
// above by FileInputStream.close()
throw new ConfigurationException("Error closing file", e);
}
}
private static ConfigurationException toConfigurationException(
DeclarativeConfigException exception) {
String message = Objects.requireNonNull(exception.getMessage());
return new ConfigurationException(message, exception);
}
static void setGlobalConfigProvider(Object configProvider) {
GlobalConfigProvider.set((ConfigProvider) configProvider);
}
}

View File

@ -5,10 +5,10 @@
package io.opentelemetry.sdk.autoconfigure.internal;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;
@ -25,7 +25,7 @@ public final class AutoConfigureUtil {
/**
* Returns the {@link ConfigProperties} used for auto-configuration.
*
* @return the config properties, or {@code null} if file based configuration is used
* @return the config properties, or {@code null} if declarative configuration is used
*/
@Nullable
public static ConfigProperties getConfig(
@ -41,21 +41,21 @@ public final class AutoConfigureUtil {
}
/**
* Returns the {@link StructuredConfigProperties} used for auto-configuration when file based
* Returns the {@link ConfigProvider} resulting from auto-configuration when declarative
* configuration is used.
*
* @return the config properties, or {@code null} if file based configuration is NOT used
* @return the {@link ConfigProvider}, or {@code null} if declarative configuration is NOT used
*/
@Nullable
public static StructuredConfigProperties getStructuredConfig(
public static ConfigProvider getConfigProvider(
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) {
try {
Method method = AutoConfiguredOpenTelemetrySdk.class.getDeclaredMethod("getStructuredConfig");
Method method = AutoConfiguredOpenTelemetrySdk.class.getDeclaredMethod("getConfigProvider");
method.setAccessible(true);
return (StructuredConfigProperties) method.invoke(autoConfiguredOpenTelemetrySdk);
return (ConfigProvider) method.invoke(autoConfiguredOpenTelemetrySdk);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException(
"Error calling getStructuredConfig on AutoConfiguredOpenTelemetrySdk", e);
"Error calling getConfigProvider on AutoConfiguredOpenTelemetrySdk", e);
}
}

View File

@ -6,11 +6,8 @@
package io.opentelemetry.sdk.autoconfigure.internal;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -23,7 +20,6 @@ import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
@ -90,53 +86,6 @@ public final class SpiHelper {
return NamedSpiManager.create(nameToProvider);
}
/**
* Find a registered {@link ComponentProvider} with {@link ComponentProvider#getType()} matching
* {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link
* ComponentProvider#create(StructuredConfigProperties)} with the given {@code config}.
*
* @throws ConfigurationException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(StructuredConfigProperties)} throws
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> T loadComponent(Class<T> type, String name, StructuredConfigProperties config) {
// TODO(jack-berg): cache loaded component providers
List<ComponentProvider> componentProviders = load(ComponentProvider.class);
List<ComponentProvider<?>> matchedProviders =
componentProviders.stream()
.map(
(Function<ComponentProvider, ComponentProvider<?>>)
componentProvider -> componentProvider)
.filter(
componentProvider ->
componentProvider.getType() == type && name.equals(componentProvider.getName()))
.collect(Collectors.toList());
if (matchedProviders.isEmpty()) {
throw new ConfigurationException(
"No component provider detected for " + type.getName() + " with name \"" + name + "\".");
}
if (matchedProviders.size() > 1) {
throw new ConfigurationException(
"Component provider conflict. Multiple providers detected for "
+ type.getName()
+ " with name \""
+ name
+ "\": "
+ componentProviders.stream()
.map(provider -> provider.getClass().getName())
.collect(Collectors.joining(",", "[", "]")));
}
// Exactly one matching component provider
ComponentProvider<T> provider = (ComponentProvider<T>) matchedProviders.get(0);
try {
return provider.create(config);
} catch (Throwable throwable) {
throw new ConfigurationException(
"Error configuring " + type.getName() + " with name \"" + name + "\"", throwable);
}
}
/**
* Load implementations of an ordered SPI (i.e. implements {@link Ordered}).
*

View File

@ -69,7 +69,6 @@ import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -675,26 +674,4 @@ class AutoConfiguredOpenTelemetrySdkTest {
logs.assertContains("Error closing io.opentelemetry.sdk.trace.SdkTracerProvider: Error!");
}
@Test
@SuppressLogger(AutoConfiguredOpenTelemetrySdkBuilder.class)
void configurationError_fileNotFound() {
assertThatThrownBy(
() ->
AutoConfiguredOpenTelemetrySdk.builder()
.addPropertiesSupplier(() -> singletonMap("otel.config.file", "foo"))
.addPropertiesSupplier(
() -> singletonMap("otel.experimental.config.file", "foo"))
.addPropertiesSupplier(() -> singletonMap("otel.sdk.disabled", "true"))
.build())
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("Configuration file not found");
Assertions.assertDoesNotThrow(
() ->
AutoConfiguredOpenTelemetrySdk.builder()
.addPropertiesSupplier(() -> singletonMap("otel.experimental.config.file", ""))
.addPropertiesSupplier(() -> singletonMap("otel.sdk.disabled", "true"))
.build());
}
}

View File

@ -7,7 +7,6 @@ package io.opentelemetry.sdk.autoconfigure;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
@ -17,16 +16,9 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.slf4j.event.Level;
class FileConfigurationTest {
@RegisterExtension
static final LogCapturer logCapturer =
LogCapturer.create()
.captureForLogger(AutoConfiguredOpenTelemetrySdkBuilder.class.getName(), Level.TRACE);
class DeclarativeConfigurationTest {
@Test
void configFile(@TempDir Path tempDir) throws IOException {
@ -50,7 +42,6 @@ class FileConfigurationTest {
assertThatThrownBy(() -> AutoConfiguredOpenTelemetrySdk.builder().setConfig(config).build())
.isInstanceOf(ConfigurationException.class)
.hasMessage(
"Error configuring from file. Is opentelemetry-sdk-extension-incubator on the classpath?");
logCapturer.assertContains("Autoconfiguring from configuration file: " + path);
"Cannot autoconfigure from config file without opentelemetry-sdk-extension-incubator on the classpath");
}
}

View File

@ -18,8 +18,6 @@ import io.grpc.stub.StreamObserver;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.Value;
import io.opentelemetry.api.incubator.logs.ExtendedLogger;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.api.metrics.Meter;
@ -38,7 +36,6 @@ import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc;
import io.opentelemetry.proto.common.v1.AnyValue;
import io.opentelemetry.proto.common.v1.KeyValue;
import io.opentelemetry.proto.logs.v1.SeverityNumber;
import io.opentelemetry.proto.metrics.v1.Metric;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.util.ArrayList;
@ -204,13 +201,6 @@ public class FullConfigTest {
logger.logRecordBuilder().setBody("debug log message").setSeverity(Severity.DEBUG).emit();
logger.logRecordBuilder().setBody("info log message").setSeverity(Severity.INFO).emit();
((ExtendedLogger) logger)
.logRecordBuilder()
.setEventName("namespace.test-name")
.setSeverity(Severity.INFO)
.setBody(Value.of(io.opentelemetry.api.common.KeyValue.of("cow", Value.of("moo"))))
.emit();
openTelemetrySdk.getSdkTracerProvider().forceFlush().join(10, TimeUnit.SECONDS);
openTelemetrySdk.getSdkLoggerProvider().forceFlush().join(10, TimeUnit.SECONDS);
openTelemetrySdk.getSdkMeterProvider().forceFlush().join(10, TimeUnit.SECONDS);
@ -297,17 +287,6 @@ public class FullConfigTest {
assertThat(logRecord.getBody().getStringValue()).isEqualTo("info log message");
assertThat(logRecord.getSeverityNumberValue())
.isEqualTo(Severity.INFO.getSeverityNumber());
},
logRecord -> {
assertThat(logRecord.getBody().getKvlistValue().getValuesList())
.containsExactlyInAnyOrder(
KeyValue.newBuilder()
.setKey("cow")
.setValue(AnyValue.newBuilder().setStringValue("moo").build())
.build());
assertThat(logRecord.getSeverityNumber())
.isEqualTo(SeverityNumber.SEVERITY_NUMBER_INFO);
assertThat(logRecord.getEventName()).isEqualTo("namespace.test-name");
});
}

View File

@ -6,6 +6,8 @@
package io.opentelemetry.sdk.autoconfigure;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
@ -17,13 +19,18 @@ import static org.mockito.Mockito.verify;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.api.incubator.config.GlobalConfigProvider;
import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
@ -31,14 +38,16 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.slf4j.event.Level;
class FileConfigurationTest {
class DeclarativeConfigurationTest {
@RegisterExtension private static final CleanupExtension cleanup = new CleanupExtension();
@ -63,13 +72,43 @@ class FileConfigurationTest {
+ " - simple:\n"
+ " exporter:\n"
+ " console: {}\n"
+ "other:\n"
+ " str_key: str_value\n"
+ " map_key:\n"
+ " str_key1: str_value1\n";
+ "instrumentation:\n"
+ " general:\n"
+ " http:\n"
+ " client:\n"
+ " request_captured_headers:\n"
+ " - Content-Type\n"
+ " - Accept\n"
+ " java:\n"
+ " example:\n"
+ " key: value\n";
configFilePath = tempDir.resolve("otel-config.yaml");
Files.write(configFilePath, yaml.getBytes(StandardCharsets.UTF_8));
GlobalOpenTelemetry.resetForTest();
GlobalConfigProvider.resetForTest();
}
@Test
@SuppressLogger(AutoConfiguredOpenTelemetrySdkBuilder.class)
void configFile_fileNotFound() {
assertThatThrownBy(
() ->
AutoConfiguredOpenTelemetrySdk.builder()
.addPropertiesSupplier(() -> singletonMap("otel.config.file", "foo"))
.addPropertiesSupplier(
() -> singletonMap("otel.experimental.config.file", "foo"))
.addPropertiesSupplier(() -> singletonMap("otel.sdk.disabled", "true"))
.build())
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("Configuration file not found");
assertThatCode(
() ->
AutoConfiguredOpenTelemetrySdk.builder()
.addPropertiesSupplier(() -> singletonMap("otel.experimental.config.file", ""))
.addPropertiesSupplier(() -> singletonMap("otel.sdk.disabled", "true"))
.build())
.doesNotThrowAnyException();
}
@Test
@ -95,13 +134,14 @@ class FileConfigurationTest {
builder.setConfig(config).build();
cleanup.addCloseable(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk());
assertThat(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk().toString())
Assertions.assertThat(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk().toString())
.isEqualTo(expectedSdk.toString());
// AutoConfiguredOpenTelemetrySdk#getResource() is set to a dummy value when configuring from
// file
assertThat(autoConfiguredOpenTelemetrySdk.getResource()).isEqualTo(Resource.getDefault());
Assertions.assertThat(autoConfiguredOpenTelemetrySdk.getResource())
.isEqualTo(Resource.getDefault());
verify(builder, times(1)).shutdownHook(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk());
assertThat(Runtime.getRuntime().removeShutdownHook(thread)).isTrue();
Assertions.assertThat(Runtime.getRuntime().removeShutdownHook(thread)).isTrue();
logCapturer.assertContains("Autoconfiguring from configuration file: " + configFilePath);
}
@ -131,7 +171,11 @@ class FileConfigurationTest {
OpenTelemetrySdk openTelemetrySdk = autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk();
cleanup.addCloseable(openTelemetrySdk);
assertThat(GlobalOpenTelemetry.get()).extracting("delegate").isNotSameAs(openTelemetrySdk);
Assertions.assertThat(GlobalOpenTelemetry.get())
.extracting("delegate")
.isNotSameAs(openTelemetrySdk);
assertThat(GlobalConfigProvider.get())
.isNotSameAs(autoConfiguredOpenTelemetrySdk.getConfigProvider());
}
@Test
@ -145,7 +189,11 @@ class FileConfigurationTest {
OpenTelemetrySdk openTelemetrySdk = autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk();
cleanup.addCloseable(openTelemetrySdk);
assertThat(GlobalOpenTelemetry.get()).extracting("delegate").isSameAs(openTelemetrySdk);
Assertions.assertThat(GlobalOpenTelemetry.get())
.extracting("delegate")
.isSameAs(openTelemetrySdk);
assertThat(GlobalConfigProvider.get())
.isSameAs(autoConfiguredOpenTelemetrySdk.getConfigProvider());
}
@Test
@ -174,7 +222,7 @@ class FileConfigurationTest {
}
@Test
void configFile_StructuredConfigProperties() {
void configFile_ConfigProvider() {
ConfigProperties config =
DefaultConfigProperties.createFromMap(
Collections.singletonMap("otel.experimental.config.file", configFilePath.toString()));
@ -185,14 +233,19 @@ class FileConfigurationTest {
cleanup.addCloseable(openTelemetrySdk);
// getConfig() should return ExtendedConfigProperties generic representation of the config file
StructuredConfigProperties structuredConfigProps =
autoConfiguredOpenTelemetrySdk.getStructuredConfig();
assertThat(structuredConfigProps).isNotNull();
StructuredConfigProperties otherProps = structuredConfigProps.getStructured("other");
assertThat(otherProps).isNotNull();
assertThat(otherProps.getString("str_key")).isEqualTo("str_value");
StructuredConfigProperties otherMapKeyProps = otherProps.getStructured("map_key");
assertThat(otherMapKeyProps).isNotNull();
assertThat(otherMapKeyProps.getString("str_key1")).isEqualTo("str_value1");
ConfigProvider globalConfigProvider = GlobalConfigProvider.get();
assertThat(globalConfigProvider)
.isNotNull()
.isSameAs(AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk));
DeclarativeConfigProperties instrumentationConfig =
globalConfigProvider.getInstrumentationConfig();
assertThat(instrumentationConfig).isNotNull();
// Extract instrumentation config from ConfigProvider
assertThat(InstrumentationConfigUtil.httpClientRequestCapturedHeaders(globalConfigProvider))
.isEqualTo(Arrays.asList("Content-Type", "Accept"));
assertThat(InstrumentationConfigUtil.javaInstrumentationConfig(globalConfigProvider, "example"))
.isNotNull()
.satisfies(exampleConfig -> assertThat(exampleConfig.getString("key")).isEqualTo("value"));
}
}

View File

@ -25,6 +25,7 @@ dependencies {
implementation("org.snakeyaml:snakeyaml-engine")
// io.opentelemetry.sdk.extension.incubator.fileconfig
api(project(":api:incubator"))
implementation("com.fasterxml.jackson.core:jackson-databind")
api("com.fasterxml.jackson.core:jackson-annotations")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml")
@ -39,7 +40,8 @@ dependencies {
testImplementation(project(":sdk-extensions:jaeger-remote-sampler"))
testImplementation(project(":extensions:trace-propagators"))
// As a part of the tests we check that we can parse examples without error. The https://github.com/open-telemetry/opentelemetry-configuration/blob/main/examples/kitchen-sink.yam contains a reference to the xray propagator
testImplementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
// TODO: add when updated to reflect new API locations
// testImplementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
testImplementation("com.linecorp.armeria:armeria-junit5")
testImplementation("com.google.guava:guava-testlib")

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Base2ExponentialBucketHistogramModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramModel;
@ -50,7 +50,7 @@ final class AggregationFactory implements Factory<AggregationModel, Aggregation>
try {
return Aggregation.base2ExponentialBucketHistogram(maxSize, maxScale);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Invalid exponential bucket histogram", e);
throw new DeclarativeConfigException("Invalid exponential bucket histogram", e);
}
}
ExplicitBucketHistogramModel explicitBucketHistogram = model.getExplicitBucketHistogram();
@ -62,7 +62,7 @@ final class AggregationFactory implements Factory<AggregationModel, Aggregation>
try {
return Aggregation.explicitBucketHistogram(boundaries);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Invalid explicit bucket histogram", e);
throw new DeclarativeConfigException("Invalid explicit bucket histogram", e);
}
}

View File

@ -10,8 +10,8 @@ import static java.util.stream.Collectors.toList;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import java.io.Closeable;
import java.util.List;
@ -115,7 +115,7 @@ final class AttributeListFactory implements Factory<List<AttributeNameValueModel
}
break;
}
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Error processing attribute with name \""
+ name
+ "\": value did not match type "

View File

@ -9,12 +9,12 @@ import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel;
import io.opentelemetry.sdk.trace.samplers.Sampler;
@ -42,18 +42,20 @@ import org.snakeyaml.engine.v2.nodes.ScalarNode;
import org.snakeyaml.engine.v2.schema.CoreSchema;
/**
* Configure {@link OpenTelemetrySdk} from YAML configuration files conforming to the schema in <a
* href="https://github.com/open-telemetry/opentelemetry-configuration">open-telemetry/opentelemetry-configuration</a>.
*
* @see #parseAndCreate(InputStream)
* Configure {@link OpenTelemetrySdk} using <a
* href="https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/configuration#declarative-configuration">declarative
* configuration</a>. For most users, this means calling {@link #parseAndCreate(InputStream)} with a
* <a
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/data-model.md#yaml-file-format">YAML
* configuration file</a>.
*/
public final class FileConfiguration {
public final class DeclarativeConfiguration {
private static final Logger logger = Logger.getLogger(FileConfiguration.class.getName());
private static final Logger logger = Logger.getLogger(DeclarativeConfiguration.class.getName());
private static final Pattern ENV_VARIABLE_REFERENCE =
Pattern.compile("\\$\\{([a-zA-Z_][a-zA-Z0-9_]*)(:-([^\n}]*))?}");
private static final ComponentLoader DEFAULT_COMPONENT_LOADER =
SpiHelper.serviceComponentLoader(FileConfiguration.class.getClassLoader());
SpiHelper.serviceComponentLoader(DeclarativeConfiguration.class.getClassLoader());
private static final ObjectMapper MAPPER;
@ -70,12 +72,12 @@ public final class FileConfiguration {
MAPPER.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
}
private FileConfiguration() {}
private DeclarativeConfiguration() {}
/**
* Combines {@link #parse(InputStream)} and {@link #create(OpenTelemetryConfigurationModel)}.
*
* @throws ConfigurationException if unable to parse or interpret
* @throws DeclarativeConfigException if unable to parse or interpret
*/
public static OpenTelemetrySdk parseAndCreate(InputStream inputStream) {
OpenTelemetryConfigurationModel configurationModel = parse(inputStream);
@ -88,7 +90,7 @@ public final class FileConfiguration {
*
* @param configurationModel the configuration model
* @return the {@link OpenTelemetrySdk}
* @throws ConfigurationException if unable to interpret
* @throws DeclarativeConfigException if unable to interpret
*/
public static OpenTelemetrySdk create(OpenTelemetryConfigurationModel configurationModel) {
return create(configurationModel, DEFAULT_COMPONENT_LOADER);
@ -102,7 +104,7 @@ public final class FileConfiguration {
* @param componentLoader the component loader used to load {@link ComponentProvider}
* implementations
* @return the {@link OpenTelemetrySdk}
* @throws ConfigurationException if unable to interpret
* @throws DeclarativeConfigException if unable to interpret
*/
public static OpenTelemetrySdk create(
OpenTelemetryConfigurationModel configurationModel, ComponentLoader componentLoader) {
@ -118,13 +120,13 @@ public final class FileConfiguration {
* <p>Before parsing, environment variable substitution is performed as described in {@link
* EnvSubstitutionConstructor}.
*
* @throws ConfigurationException if unable to parse
* @throws DeclarativeConfigException if unable to parse
*/
public static OpenTelemetryConfigurationModel parse(InputStream configuration) {
try {
return parse(configuration, System.getenv());
} catch (RuntimeException e) {
throw new ConfigurationException("Unable to parse configuration input stream", e);
throw new DeclarativeConfigException("Unable to parse configuration input stream", e);
}
}
@ -143,35 +145,35 @@ public final class FileConfiguration {
}
/**
* Convert the {@code model} to a generic {@link StructuredConfigProperties}.
* Convert the {@code model} to a generic {@link DeclarativeConfigProperties}.
*
* @param model the configuration model
* @return a generic {@link StructuredConfigProperties} representation of the model
* @return a generic {@link DeclarativeConfigProperties} representation of the model
*/
public static StructuredConfigProperties toConfigProperties(
public static DeclarativeConfigProperties toConfigProperties(
OpenTelemetryConfigurationModel model) {
return toConfigProperties(model, DEFAULT_COMPONENT_LOADER);
}
/**
* Convert the {@code configuration} YAML to a generic {@link StructuredConfigProperties}.
* Convert the {@code configuration} YAML to a generic {@link DeclarativeConfigProperties}.
*
* @param configuration configuration YAML
* @return a generic {@link StructuredConfigProperties} representation of the model
* @return a generic {@link DeclarativeConfigProperties} representation of the model
*/
public static StructuredConfigProperties toConfigProperties(InputStream configuration) {
public static DeclarativeConfigProperties toConfigProperties(InputStream configuration) {
Object yamlObj = loadYaml(configuration, System.getenv());
return toConfigProperties(yamlObj, DEFAULT_COMPONENT_LOADER);
}
static StructuredConfigProperties toConfigProperties(
static DeclarativeConfigProperties toConfigProperties(
Object model, ComponentLoader componentLoader) {
Map<String, Object> configurationMap =
MAPPER.convertValue(model, new TypeReference<Map<String, Object>>() {});
if (configurationMap == null) {
configurationMap = Collections.emptyMap();
}
return YamlStructuredConfigProperties.create(configurationMap, componentLoader);
return YamlDeclarativeConfigProperties.create(configurationMap, componentLoader);
}
/**
@ -179,33 +181,33 @@ public final class FileConfiguration {
*
* <p>This is used when samplers are composed, with one sampler accepting one or more additional
* samplers as config properties. The {@link ComponentProvider} implementation can call this to
* configure a delegate {@link SamplerModel} from the {@link StructuredConfigProperties}
* configure a delegate {@link SamplerModel} from the {@link DeclarativeConfigProperties}
* corresponding to a particular config property.
*/
// TODO(jack-berg): add create methods for all SDK extension components supported by
// ComponentProvider
public static Sampler createSampler(StructuredConfigProperties genericSamplerModel) {
YamlStructuredConfigProperties yamlStructuredConfigProperties =
requireYamlStructuredConfigProperties(genericSamplerModel);
SamplerModel samplerModel = convertToModel(yamlStructuredConfigProperties, SamplerModel.class);
public static Sampler createSampler(DeclarativeConfigProperties genericSamplerModel) {
YamlDeclarativeConfigProperties yamlDeclarativeConfigProperties =
requireYamlDeclarativeConfigProperties(genericSamplerModel);
SamplerModel samplerModel = convertToModel(yamlDeclarativeConfigProperties, SamplerModel.class);
return createAndMaybeCleanup(
SamplerFactory.getInstance(),
SpiHelper.create(yamlStructuredConfigProperties.getComponentLoader()),
SpiHelper.create(yamlDeclarativeConfigProperties.getComponentLoader()),
samplerModel);
}
private static YamlStructuredConfigProperties requireYamlStructuredConfigProperties(
StructuredConfigProperties structuredConfigProperties) {
if (!(structuredConfigProperties instanceof YamlStructuredConfigProperties)) {
throw new ConfigurationException(
"Only YamlStructuredConfigProperties can be converted to model");
private static YamlDeclarativeConfigProperties requireYamlDeclarativeConfigProperties(
DeclarativeConfigProperties declarativeConfigProperties) {
if (!(declarativeConfigProperties instanceof YamlDeclarativeConfigProperties)) {
throw new DeclarativeConfigException(
"Only YamlDeclarativeConfigProperties can be converted to model");
}
return (YamlStructuredConfigProperties) structuredConfigProperties;
return (YamlDeclarativeConfigProperties) declarativeConfigProperties;
}
static <T> T convertToModel(
YamlStructuredConfigProperties structuredConfigProperties, Class<T> modelType) {
return MAPPER.convertValue(structuredConfigProperties.toMap(), modelType);
YamlDeclarativeConfigProperties yamlDeclarativeConfigProperties, Class<T> modelType) {
return MAPPER.convertValue(yamlDeclarativeConfigProperties.toMap(), modelType);
}
static <M, R> R createAndMaybeCleanup(Factory<M, R> factory, SpiHelper spiHelper, M model) {
@ -223,10 +225,10 @@ public final class FileConfiguration {
"Error closing " + closeable.getClass().getName() + ": " + ex.getMessage());
}
}
if (e instanceof ConfigurationException) {
if (e instanceof DeclarativeConfigException) {
throw e;
}
throw new ConfigurationException("Unexpected configuration error", e);
throw new DeclarativeConfigException("Unexpected configuration error", e);
}
}

View File

@ -5,12 +5,14 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import java.io.Closeable;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
final class FileConfigUtil {
@ -34,7 +36,7 @@ final class FileConfigUtil {
static <T> T requireNonNull(@Nullable T object, String description) {
if (object == null) {
throw new ConfigurationException(description + " is required but is null");
throw new DeclarativeConfigException(description + " is required but is null");
}
return object;
}
@ -42,15 +44,63 @@ final class FileConfigUtil {
/**
* Find a registered {@link ComponentProvider} which {@link ComponentProvider#getType()} matching
* {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link
* ComponentProvider#create(StructuredConfigProperties)} with the given {@code model}.
* ComponentProvider#create(DeclarativeConfigProperties)} with the given {@code model}.
*
* @throws ConfigurationException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(StructuredConfigProperties)} throws
* @throws DeclarativeConfigException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(DeclarativeConfigProperties)} throws
*/
static <T> T loadComponent(SpiHelper spiHelper, Class<T> type, String name, Object model) {
// Map model to generic structured config properties
StructuredConfigProperties config =
FileConfiguration.toConfigProperties(model, spiHelper.getComponentLoader());
return spiHelper.loadComponent(type, name, config);
DeclarativeConfigProperties config =
DeclarativeConfiguration.toConfigProperties(model, spiHelper.getComponentLoader());
return loadComponentHelper(spiHelper, type, name, config);
}
/**
* Find a registered {@link ComponentProvider} with {@link ComponentProvider#getType()} matching
* {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link
* ComponentProvider#create(DeclarativeConfigProperties)} with the given {@code config}.
*
* @throws DeclarativeConfigException if no matching providers are found, or if multiple are found
* (i.e. conflict), or if {@link ComponentProvider#create(DeclarativeConfigProperties)} throws
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private static <T> T loadComponentHelper(
SpiHelper spiHelper, Class<T> type, String name, DeclarativeConfigProperties config) {
// TODO(jack-berg): cache loaded component providers
List<ComponentProvider> componentProviders = spiHelper.load(ComponentProvider.class);
List<ComponentProvider<?>> matchedProviders =
componentProviders.stream()
.map(
(Function<ComponentProvider, ComponentProvider<?>>)
componentProvider -> componentProvider)
.filter(
componentProvider ->
componentProvider.getType() == type && name.equals(componentProvider.getName()))
.collect(Collectors.toList());
if (matchedProviders.isEmpty()) {
throw new DeclarativeConfigException(
"No component provider detected for " + type.getName() + " with name \"" + name + "\".");
}
if (matchedProviders.size() > 1) {
throw new DeclarativeConfigException(
"Component provider conflict. Multiple providers detected for "
+ type.getName()
+ " with name \""
+ name
+ "\": "
+ componentProviders.stream()
.map(provider -> provider.getClass().getName())
.collect(Collectors.joining(",", "[", "]")));
}
// Exactly one matching component provider
ComponentProvider<T> provider = (ComponentProvider<T>) matchedProviders.get(0);
try {
return provider.create(config);
} catch (Throwable throwable) {
throw new DeclarativeConfigException(
"Error configuring " + type.getName() + " with name \"" + name + "\"", throwable);
}
}
}

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SelectorModel;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.InstrumentSelectorBuilder;
@ -36,7 +36,7 @@ final class InstrumentSelectorFactory implements Factory<SelectorModel, Instrume
try {
instrumentType = InstrumentType.valueOf(model.getInstrumentType().name());
} catch (IllegalArgumentException e) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Unrecognized instrument type: " + model.getInstrumentType(), e);
}
builder.setType(instrumentType);
@ -54,7 +54,7 @@ final class InstrumentSelectorFactory implements Factory<SelectorModel, Instrume
try {
return builder.build();
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Invalid selector", e);
throw new DeclarativeConfigException("Invalid selector", e);
}
}
}

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
@ -43,7 +43,7 @@ final class LogRecordExporterFactory implements Factory<LogRecordExporterModel,
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Invalid configuration - multiple log record exporters set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
@ -61,7 +61,7 @@ final class LogRecordExporterFactory implements Factory<LogRecordExporterModel,
exporterKeyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, logRecordExporter);
} else {
throw new ConfigurationException("log exporter must be set");
throw new DeclarativeConfigException("log exporter must be set");
}
}
}

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel;
@ -75,7 +75,7 @@ final class LogRecordProcessorFactory
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Invalid configuration - multiple log record processors set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
@ -93,7 +93,7 @@ final class LogRecordProcessorFactory
processorKeyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, logRecordProcessor);
} else {
throw new ConfigurationException("log processor must be set");
throw new DeclarativeConfigException("log processor must be set");
}
}
}

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
@ -41,7 +41,7 @@ final class MetricExporterFactory implements Factory<PushMetricExporterModel, Me
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Invalid configuration - multiple metric exporters set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
@ -59,7 +59,7 @@ final class MetricExporterFactory implements Factory<PushMetricExporterModel, Me
exporterKeyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, metricExporter);
} else {
throw new ConfigurationException("metric exporter must be set");
throw new DeclarativeConfigException("metric exporter must be set");
}
}
}

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigUtil.requireNonNull;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PrometheusModel;
@ -62,9 +62,10 @@ final class MetricReaderFactory implements Factory<MetricReaderModel, MetricRead
return FileConfigUtil.addAndReturn(closeables, metricReader);
}
throw new ConfigurationException("prometheus is the only currently supported pull reader");
throw new DeclarativeConfigException(
"prometheus is the only currently supported pull reader");
}
throw new ConfigurationException("reader must be set");
throw new DeclarativeConfigException("reader must be set");
}
}

View File

@ -5,10 +5,10 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import io.opentelemetry.sdk.resources.Resource;
import java.io.Closeable;
@ -32,7 +32,8 @@ final class OpenTelemetryConfigurationFactory
OpenTelemetryConfigurationModel model, SpiHelper spiHelper, List<Closeable> closeables) {
OpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();
if (!"0.3".equals(model.getFileFormat())) {
throw new ConfigurationException("Unsupported file format. Supported formats include: 0.3");
throw new DeclarativeConfigException(
"Unsupported file format. Supported formats include: 0.3");
}
if (Objects.equals(Boolean.TRUE, model.getDisabled())) {

View File

@ -7,13 +7,13 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.internal.GlobUtil.toGlobPatternPredicate;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.ResourceConfiguration;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorAttributesModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DetectorsModel;
@ -31,10 +31,6 @@ import javax.annotation.Nullable;
final class ResourceFactory implements Factory<ResourceModel, Resource> {
private static final StructuredConfigProperties EMPTY_CONFIG =
FileConfiguration.toConfigProperties(
Collections.emptyMap(),
SpiHelper.serviceComponentLoader(ResourceFactory.class.getClassLoader()));
private static final ResourceFactory INSTANCE = new ResourceFactory();
private ResourceFactory() {}
@ -86,7 +82,7 @@ final class ResourceFactory implements Factory<ResourceModel, Resource> {
* <p>In declarative configuration, a resource detector is a {@link ComponentProvider} with {@link
* ComponentProvider#getType()} set to {@link Resource}. Unlike other {@link ComponentProvider}s,
* the resource detector version does not use {@link ComponentProvider#getName()} (except for
* debug messages), and {@link ComponentProvider#create(StructuredConfigProperties)} is called
* debug messages), and {@link ComponentProvider#create(DeclarativeConfigProperties)} is called
* with an empty instance. Additionally, the {@link Ordered#order()} value is respected for
* resource detectors which implement {@link Ordered}.
*/
@ -100,9 +96,9 @@ final class ResourceFactory implements Factory<ResourceModel, Resource> {
}
Resource resource;
try {
resource = (Resource) componentProvider.create(EMPTY_CONFIG);
resource = (Resource) componentProvider.create(DeclarativeConfigProperties.empty());
} catch (Throwable throwable) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Error configuring "
+ Resource.class.getName()
+ " with name \""

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.JaegerRemoteModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ParentBasedModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel;
@ -81,7 +81,7 @@ final class SamplerFactory implements Factory<SamplerModel, Sampler> {
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Invalid configuration - multiple samplers exporters set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
@ -95,7 +95,7 @@ final class SamplerFactory implements Factory<SamplerModel, Sampler> {
spiHelper, Sampler.class, exporterKeyValue.getKey(), exporterKeyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, sampler);
} else {
throw new ConfigurationException("sampler must be set");
throw new DeclarativeConfigException("sampler must be set");
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import javax.annotation.Nullable;
/** SDK implementation of {@link ConfigProvider}. */
public final class SdkConfigProvider implements ConfigProvider {
@Nullable private final DeclarativeConfigProperties instrumentationConfig;
private SdkConfigProvider(OpenTelemetryConfigurationModel model) {
DeclarativeConfigProperties configProperties =
DeclarativeConfiguration.toConfigProperties(model);
this.instrumentationConfig = configProperties.getStructured("instrumentation");
}
/**
* Create a {@link SdkConfigProvider} from the {@code model}.
*
* @param model the configuration model
* @return the {@link SdkConfigProvider}
*/
public static SdkConfigProvider create(OpenTelemetryConfigurationModel model) {
return new SdkConfigProvider(model);
}
@Nullable
@Override
public DeclarativeConfigProperties getInstrumentationConfig() {
return instrumentationConfig;
}
}

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ZipkinModel;
@ -47,7 +47,7 @@ final class SpanExporterFactory implements Factory<SpanExporterModel, SpanExport
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Invalid configuration - multiple span exporters set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
@ -65,7 +65,7 @@ final class SpanExporterFactory implements Factory<SpanExporterModel, SpanExport
exporterKeyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, spanExporter);
} else {
throw new ConfigurationException("span exporter must be set");
throw new DeclarativeConfigException("span exporter must be set");
}
}
}

View File

@ -7,8 +7,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel;
@ -71,7 +71,7 @@ final class SpanProcessorFactory implements Factory<SpanProcessorModel, SpanProc
if (!model.getAdditionalProperties().isEmpty()) {
Map<String, Object> additionalProperties = model.getAdditionalProperties();
if (additionalProperties.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Invalid configuration - multiple span processors set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
@ -89,7 +89,7 @@ final class SpanProcessorFactory implements Factory<SpanProcessorModel, SpanProc
processorKeyValue.getValue());
return FileConfigUtil.addAndReturn(closeables, spanProcessor);
} else {
throw new ConfigurationException("span processor must be set");
throw new DeclarativeConfigException("span processor must be set");
}
}
}

View File

@ -6,10 +6,10 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Arrays;
@ -35,7 +35,7 @@ final class TextMapPropagatorFactory implements Factory<List<String>, TextMapPro
if (model.contains("none")) {
if (model.size() > 1) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"propagators contains \"none\" along with other propagators");
}
return TextMapPropagator.noop();

View File

@ -8,14 +8,15 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -24,27 +25,35 @@ import java.util.StringJoiner;
import javax.annotation.Nullable;
/**
* Implementation of {@link StructuredConfigProperties} which uses a declarative configuration model
* as a source.
* Implementation of {@link DeclarativeConfigProperties} which uses a file configuration model as a
* source.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*
* @see #getStructured(String) Accessing nested maps
* @see #getStructuredList(String) Accessing lists of maps
* @see FileConfiguration#toConfigProperties(Object, ComponentLoader) Converting configuration model
* to properties
* @see DeclarativeConfiguration#toConfigProperties(Object, ComponentLoader) Converting
* configuration model to properties
*/
final class YamlStructuredConfigProperties implements StructuredConfigProperties {
public final class YamlDeclarativeConfigProperties implements DeclarativeConfigProperties {
private static final Set<Class<?>> SUPPORTED_SCALAR_TYPES =
Collections.unmodifiableSet(
new LinkedHashSet<>(
Arrays.asList(String.class, Boolean.class, Long.class, Double.class)));
/** Values are {@link #isPrimitive(Object)}, {@link List} of scalars. */
private final Map<String, Object> simpleEntries;
private final Map<String, List<YamlStructuredConfigProperties>> listEntries;
private final Map<String, YamlStructuredConfigProperties> mapEntries;
private final Map<String, List<YamlDeclarativeConfigProperties>> listEntries;
private final Map<String, YamlDeclarativeConfigProperties> mapEntries;
private final ComponentLoader componentLoader;
private YamlStructuredConfigProperties(
private YamlDeclarativeConfigProperties(
Map<String, Object> simpleEntries,
Map<String, List<YamlStructuredConfigProperties>> listEntries,
Map<String, YamlStructuredConfigProperties> mapEntries,
Map<String, List<YamlDeclarativeConfigProperties>> listEntries,
Map<String, YamlDeclarativeConfigProperties> mapEntries,
ComponentLoader componentLoader) {
this.simpleEntries = simpleEntries;
this.listEntries = listEntries;
@ -53,20 +62,20 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
}
/**
* Create a {@link YamlStructuredConfigProperties} from the {@code properties} map.
* Create a {@link YamlDeclarativeConfigProperties} from the {@code properties} map.
*
* <p>{@code properties} is expected to be the output of YAML parsing (i.e. with Jackson {@link
* <p>{@code properties} is expected to be the output of YAML parsing (i.e. with Jackson {@code
* com.fasterxml.jackson.databind.ObjectMapper}), and have values which are scalars, lists of
* scalars, lists of maps, and maps.
*
* @see FileConfiguration#toConfigProperties(OpenTelemetryConfigurationModel)
* @see DeclarativeConfiguration#toConfigProperties(OpenTelemetryConfigurationModel)
*/
@SuppressWarnings("unchecked")
static YamlStructuredConfigProperties create(
static YamlDeclarativeConfigProperties create(
Map<String, Object> properties, ComponentLoader componentLoader) {
Map<String, Object> simpleEntries = new HashMap<>();
Map<String, List<YamlStructuredConfigProperties>> listEntries = new HashMap<>();
Map<String, YamlStructuredConfigProperties> mapEntries = new HashMap<>();
Map<String, Object> simpleEntries = new LinkedHashMap<>();
Map<String, List<YamlDeclarativeConfigProperties>> listEntries = new LinkedHashMap<>();
Map<String, YamlDeclarativeConfigProperties> mapEntries = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : properties.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
@ -79,34 +88,34 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
continue;
}
if (isListOfMaps(value)) {
List<YamlStructuredConfigProperties> list =
List<YamlDeclarativeConfigProperties> list =
((List<Map<String, Object>>) value)
.stream()
.map(map -> YamlStructuredConfigProperties.create(map, componentLoader))
.map(map -> YamlDeclarativeConfigProperties.create(map, componentLoader))
.collect(toList());
listEntries.put(key, list);
continue;
}
if (isMap(value)) {
YamlStructuredConfigProperties configProperties =
YamlStructuredConfigProperties.create((Map<String, Object>) value, componentLoader);
YamlDeclarativeConfigProperties configProperties =
YamlDeclarativeConfigProperties.create((Map<String, Object>) value, componentLoader);
mapEntries.put(key, configProperties);
continue;
}
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Unable to initialize ExtendedConfigProperties. Key \""
+ key
+ "\" has unrecognized object type "
+ value.getClass().getName());
}
return new YamlStructuredConfigProperties(
return new YamlDeclarativeConfigProperties(
simpleEntries, listEntries, mapEntries, componentLoader);
}
private static boolean isPrimitiveList(Object object) {
if (object instanceof List) {
List<?> list = (List<?>) object;
return list.stream().allMatch(YamlStructuredConfigProperties::isPrimitive);
return list.stream().allMatch(YamlDeclarativeConfigProperties::isPrimitive);
}
return false;
}
@ -178,16 +187,12 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
return doubleOrNull(simpleEntries.get(name));
}
private static final Set<Class<?>> SUPPORTED_SCALAR_TYPES =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(String.class, Boolean.class, Long.class, Double.class)));
@Nullable
@Override
@SuppressWarnings("unchecked")
public <T> List<T> getScalarList(String name, Class<T> scalarType) {
if (!SUPPORTED_SCALAR_TYPES.contains(scalarType)) {
throw new ConfigurationException(
throw new DeclarativeConfigException(
"Unsupported scalar type "
+ scalarType.getName()
+ ". Supported types include "
@ -259,14 +264,14 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
@Nullable
@Override
public StructuredConfigProperties getStructured(String name) {
public DeclarativeConfigProperties getStructured(String name) {
return mapEntries.get(name);
}
@Nullable
@Override
public List<StructuredConfigProperties> getStructuredList(String name) {
List<YamlStructuredConfigProperties> value = listEntries.get(name);
public List<DeclarativeConfigProperties> getStructuredList(String name) {
List<YamlDeclarativeConfigProperties> value = listEntries.get(name);
if (value != null) {
return Collections.unmodifiableList(value);
}
@ -275,7 +280,7 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
@Override
public Set<String> getPropertyKeys() {
Set<String> keys = new HashSet<>();
Set<String> keys = new LinkedHashSet<>();
keys.addAll(simpleEntries.keySet());
keys.addAll(listEntries.keySet());
keys.addAll(mapEntries.keySet());
@ -284,7 +289,7 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(", ", "YamlStructuredConfigProperties{", "}");
StringJoiner joiner = new StringJoiner(", ", "YamlDeclarativeConfigProperties{", "}");
simpleEntries.forEach((key, value) -> joiner.add(key + "=" + value));
listEntries.forEach((key, value) -> joiner.add(key + "=" + value));
mapEntries.forEach((key, value) -> joiner.add(key + "=" + value));
@ -297,7 +302,7 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties
listEntries.forEach(
(key, value) ->
result.put(
key, value.stream().map(YamlStructuredConfigProperties::toMap).collect(toList())));
key, value.stream().map(YamlDeclarativeConfigProperties::toMap).collect(toList())));
mapEntries.forEach((key, value) -> result.put(key, value.toMap()));
return Collections.unmodifiableMap(result);
}

View File

@ -10,8 +10,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import java.util.Arrays;
import java.util.Collections;
@ -31,7 +31,7 @@ class AttributeListFactoryTest {
() ->
AttributeListFactory.getInstance()
.create(model, mock(SpiHelper.class), Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessageContaining(expectedMessage);
}

View File

@ -12,8 +12,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
@ -28,7 +28,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.slf4j.event.Level;
class FileConfigurationCreateTest {
class DeclarativeConfigurationCreateTest {
@RegisterExtension
static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension();
@ -40,12 +40,12 @@ class FileConfigurationCreateTest {
@RegisterExtension
LogCapturer logCapturer =
LogCapturer.create().captureForLogger(FileConfiguration.class.getName(), Level.TRACE);
LogCapturer.create().captureForLogger(DeclarativeConfiguration.class.getName(), Level.TRACE);
/**
* Verify each example in <a
* href="https://github.com/open-telemetry/opentelemetry-configuration/tree/main/examples">open-telemetry/opentelemetry-configuration/examples</a>
* can pass {@link FileConfiguration#parseAndCreate(InputStream)}.
* can pass {@link DeclarativeConfiguration#parseAndCreate(InputStream)}.
*/
@Test
void parseAndCreate_Examples(@TempDir Path tempDir)
@ -90,12 +90,15 @@ class FileConfigurationCreateTest {
"client_certificate: .*\n",
"client_certificate: "
+ clientCertificatePath.replace("\\", "\\\\")
+ System.lineSeparator());
+ System.lineSeparator())
// TODO: remove once updated ComponentProvider SPI contract implemented in
// https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/aws-xray-propagator
.replaceAll("xray,", "");
InputStream is =
new ByteArrayInputStream(rewrittenExampleContent.getBytes(StandardCharsets.UTF_8));
// Verify that file can be parsed and interpreted without error
assertThatCode(() -> cleanup.addCloseable(FileConfiguration.parseAndCreate(is)))
assertThatCode(() -> cleanup.addCloseable(DeclarativeConfiguration.parseAndCreate(is)))
.as("Example file: " + example.getName())
.doesNotThrowAnyException();
}
@ -119,9 +122,9 @@ class FileConfigurationCreateTest {
assertThatThrownBy(
() ->
FileConfiguration.parseAndCreate(
DeclarativeConfiguration.parseAndCreate(
new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.logs.export.LogRecordExporter with name \"foo\".");
logCapturer.assertContains(
@ -144,9 +147,8 @@ class FileConfigurationCreateTest {
assertThatCode(
() ->
FileConfiguration.parseAndCreate(
DeclarativeConfiguration.parseAndCreate(
new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))))
.doesNotThrowAnyException();
;
}
}

View File

@ -8,7 +8,7 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOffModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnModel;
@ -76,15 +76,15 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class FileConfigurationParseTest {
class DeclarativeConfigurationParseTest {
@Test
void parse_BadInputStream() {
assertThatThrownBy(
() ->
FileConfiguration.parseAndCreate(
DeclarativeConfiguration.parseAndCreate(
new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8))))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("Unable to parse configuration input stream");
}
@ -446,7 +446,7 @@ class FileConfigurationParseTest {
try (FileInputStream configExampleFile =
new FileInputStream(System.getenv("CONFIG_EXAMPLE_DIR") + "/kitchen-sink.yaml")) {
OpenTelemetryConfigurationModel config = FileConfiguration.parse(configExampleFile);
OpenTelemetryConfigurationModel config = DeclarativeConfiguration.parse(configExampleFile);
// General config
assertThat(config.getFileFormat()).isEqualTo("0.3");
@ -499,7 +499,7 @@ class FileConfigurationParseTest {
+ " aggregation:\n"
+ " drop: {}\n";
OpenTelemetryConfigurationModel objectPlaceholderModel =
FileConfiguration.parse(
DeclarativeConfiguration.parse(
new ByteArrayInputStream(objectPlaceholderString.getBytes(StandardCharsets.UTF_8)));
String noOjbectPlaceholderString =
@ -517,7 +517,7 @@ class FileConfigurationParseTest {
+ " aggregation:\n"
+ " drop:\n";
OpenTelemetryConfigurationModel noObjectPlaceholderModel =
FileConfiguration.parse(
DeclarativeConfiguration.parse(
new ByteArrayInputStream(noOjbectPlaceholderString.getBytes(StandardCharsets.UTF_8)));
SpanExporterModel exporter =
@ -551,7 +551,8 @@ class FileConfigurationParseTest {
+ " ratio:\n"; // Double
OpenTelemetryConfigurationModel model =
FileConfiguration.parse(new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)));
DeclarativeConfiguration.parse(
new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)));
assertThat(model.getFileFormat()).isNull();
assertThat(model.getDisabled()).isNull();
@ -573,7 +574,7 @@ class FileConfigurationParseTest {
@MethodSource("coreSchemaValuesArgs")
void coreSchemaValues(String rawYaml, Object expectedYamlResult) {
Object yaml =
FileConfiguration.loadYaml(
DeclarativeConfiguration.loadYaml(
new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)),
Collections.emptyMap());
assertThat(yaml).isEqualTo(expectedYamlResult);
@ -601,7 +602,7 @@ class FileConfigurationParseTest {
environmentVariables.put("HEX", "0xdeadbeef");
Object yaml =
FileConfiguration.loadYaml(
DeclarativeConfiguration.loadYaml(
new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)),
environmentVariables);
assertThat(yaml).isEqualTo(expectedYamlResult);
@ -689,7 +690,7 @@ class FileConfigurationParseTest {
Map<String, String> envVars = new HashMap<>();
envVars.put("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector:4317");
OpenTelemetryConfigurationModel model =
FileConfiguration.parse(
DeclarativeConfiguration.parse(
new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), envVars);
assertThat(model)
.isEqualTo(

View File

@ -9,8 +9,8 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.asser
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SelectorModel;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.InstrumentType;
@ -25,7 +25,7 @@ class InstrumentSelectorFactoryTest {
() ->
InstrumentSelectorFactory.getInstance()
.create(new SelectorModel(), mock(SpiHelper.class), Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("Invalid selector");
}

View File

@ -8,17 +8,18 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
@ -31,12 +32,16 @@ import java.security.cert.CertificateEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ -53,12 +58,36 @@ class LogRecordExporterFactoryTest {
@RegisterExtension CleanupExtension cleanup = new CleanupExtension();
private SpiHelper spiHelper =
SpiHelper.create(LogRecordExporterFactoryTest.class.getClassLoader());
private final SpiHelper spiHelper =
spy(SpiHelper.create(SpanExporterFactoryTest.class.getClassLoader()));
private List<ComponentProvider<?>> loadedComponentProviders = Collections.emptyList();
@BeforeEach
@SuppressWarnings("unchecked")
void setup() {
when(spiHelper.load(ComponentProvider.class))
.thenAnswer(
invocation -> {
List<ComponentProvider<?>> result =
(List<ComponentProvider<?>>) invocation.callRealMethod();
loadedComponentProviders =
result.stream().map(Mockito::spy).collect(Collectors.toList());
return loadedComponentProviders;
});
}
private ComponentProvider<?> getComponentProvider(String name, Class<?> type) {
return loadedComponentProviders.stream()
.filter(
componentProvider ->
componentProvider.getName().equals(name)
&& componentProvider.getType().equals(type))
.findFirst()
.orElseThrow(IllegalStateException::new);
}
@Test
void create_OtlpDefaults() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
OtlpHttpLogRecordExporter expectedExporter = OtlpHttpLogRecordExporter.getDefault();
cleanup.addCloseable(expectedExporter);
@ -78,11 +107,11 @@ class LogRecordExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper)
.loadComponent(eq(LogRecordExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("otlp", LogRecordExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isNull();
assertThat(configProperties.getString("endpoint")).isNull();
assertThat(configProperties.getStructured("headers")).isNull();
@ -96,7 +125,6 @@ class LogRecordExporterFactoryTest {
@Test
void create_OtlpConfigured(@TempDir Path tempDir)
throws CertificateEncodingException, IOException {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
OtlpHttpLogRecordExporter expectedExporter =
OtlpHttpLogRecordExporter.builder()
@ -147,14 +175,14 @@ class LogRecordExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper)
.loadComponent(eq(LogRecordExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("otlp", LogRecordExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isEqualTo("http/protobuf");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/logs");
List<StructuredConfigProperties> headers = configProperties.getStructuredList("headers");
List<DeclarativeConfigProperties> headers = configProperties.getStructuredList("headers");
assertThat(headers)
.isNotNull()
.satisfiesExactly(
@ -187,7 +215,7 @@ class LogRecordExporterFactoryTest {
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.logs.export.LogRecordExporter with name \"unknown_key\".");
cleanup.addCloseables(closeables);

View File

@ -9,10 +9,10 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.asser
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordProcessorComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
@ -44,7 +44,7 @@ class LogRecordProcessorFactoryTest {
new LogRecordProcessorModel().withBatch(new BatchLogRecordProcessorModel()),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("batch log record processor exporter is required but is null");
}
@ -112,7 +112,7 @@ class LogRecordProcessorFactoryTest {
.withSimple(new SimpleLogRecordProcessorModel()),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("simple log record processor exporter is required but is null");
}
@ -150,7 +150,7 @@ class LogRecordProcessorFactoryTest {
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.logs.LogRecordProcessor with name \"unknown_key\".");
}

View File

@ -8,18 +8,19 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
@ -36,12 +37,16 @@ import java.security.cert.CertificateEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ -58,11 +63,36 @@ class MetricExporterFactoryTest {
@RegisterExtension CleanupExtension cleanup = new CleanupExtension();
private SpiHelper spiHelper = SpiHelper.create(MetricExporterFactoryTest.class.getClassLoader());
private final SpiHelper spiHelper =
spy(SpiHelper.create(SpanExporterFactoryTest.class.getClassLoader()));
private List<ComponentProvider<?>> loadedComponentProviders = Collections.emptyList();
@BeforeEach
@SuppressWarnings("unchecked")
void setup() {
when(spiHelper.load(ComponentProvider.class))
.thenAnswer(
invocation -> {
List<ComponentProvider<?>> result =
(List<ComponentProvider<?>>) invocation.callRealMethod();
loadedComponentProviders =
result.stream().map(Mockito::spy).collect(Collectors.toList());
return loadedComponentProviders;
});
}
private ComponentProvider<?> getComponentProvider(String name, Class<?> type) {
return loadedComponentProviders.stream()
.filter(
componentProvider ->
componentProvider.getName().equals(name)
&& componentProvider.getType().equals(type))
.findFirst()
.orElseThrow(IllegalStateException::new);
}
@Test
void create_OtlpDefaults() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
OtlpHttpMetricExporter expectedExporter = OtlpHttpMetricExporter.getDefault();
cleanup.addCloseable(expectedExporter);
@ -80,10 +110,11 @@ class MetricExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper).loadComponent(eq(MetricExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("otlp", MetricExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isNull();
assertThat(configProperties.getString("endpoint")).isNull();
assertThat(configProperties.getStructured("headers")).isNull();
@ -99,7 +130,6 @@ class MetricExporterFactoryTest {
@Test
void create_OtlpConfigured(@TempDir Path tempDir)
throws CertificateEncodingException, IOException {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
OtlpHttpMetricExporter expectedExporter =
OtlpHttpMetricExporter.builder()
@ -158,13 +188,14 @@ class MetricExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper).loadComponent(eq(MetricExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("otlp", MetricExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isEqualTo("http/protobuf");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/metrics");
List<StructuredConfigProperties> headers = configProperties.getStructuredList("headers");
List<DeclarativeConfigProperties> headers = configProperties.getStructuredList("headers");
assertThat(headers)
.isNotNull()
.satisfiesExactly(
@ -188,7 +219,6 @@ class MetricExporterFactoryTest {
@Test
void create_Console() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
LoggingMetricExporter expectedExporter = LoggingMetricExporter.create();
cleanup.addCloseable(expectedExporter);
@ -219,7 +249,7 @@ class MetricExporterFactoryTest {
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.metrics.export.MetricExporter with name \"unknown_key\".");
}

View File

@ -11,11 +11,11 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpMetricModel;
@ -40,7 +40,7 @@ class MetricReaderFactoryTest {
@RegisterExtension
LogCapturer logCapturer =
LogCapturer.create().captureForLogger(FileConfiguration.class.getName());
LogCapturer.create().captureForLogger(DeclarativeConfiguration.class.getName());
private SpiHelper spiHelper = SpiHelper.create(MetricReaderFactoryTest.class.getClassLoader());
@ -53,7 +53,7 @@ class MetricReaderFactoryTest {
new MetricReaderModel().withPeriodic(new PeriodicMetricReaderModel()),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("periodic metric reader exporter is required but is null");
}
@ -179,7 +179,7 @@ class MetricReaderFactoryTest {
new MetricReaderModel().withPull(new PullMetricReaderModel()),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("pull metric reader exporter is required but is null");
assertThatThrownBy(
@ -192,7 +192,7 @@ class MetricReaderFactoryTest {
.withExporter(new PullMetricExporterModel())),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("prometheus is the only currently supported pull reader");
}

View File

@ -10,6 +10,7 @@ import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
@ -22,7 +23,6 @@ import io.opentelemetry.extension.trace.propagation.OtTracePropagator;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel;
@ -82,7 +82,7 @@ class OpenTelemetryConfigurationFactoryTest {
() ->
OpenTelemetryConfigurationFactory.getInstance()
.create(testCase, spiHelper, closeables))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("Unsupported file format. Supported formats include: 0.3");
cleanup.addCloseables(closeables);
}

View File

@ -26,7 +26,7 @@ import org.junit.jupiter.params.provider.MethodSource;
class ResourceFactoryTest {
private SpiHelper spiHelper = SpiHelper.create(MetricExporterFactoryTest.class.getClassLoader());
private SpiHelper spiHelper = SpiHelper.create(ResourceFactoryTest.class.getClassLoader());
@Test
void create() {

View File

@ -9,10 +9,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SamplerComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOffModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnModel;
@ -140,7 +140,7 @@ class SamplerFactoryTest {
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.trace.samplers.Sampler with name \"unknown_key\".");
cleanup.addCloseables(closeables);

View File

@ -8,19 +8,20 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
@ -34,12 +35,16 @@ import java.security.cert.CertificateEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ -56,11 +61,36 @@ class SpanExporterFactoryTest {
@RegisterExtension CleanupExtension cleanup = new CleanupExtension();
private SpiHelper spiHelper = SpiHelper.create(SpanExporterFactoryTest.class.getClassLoader());
private final SpiHelper spiHelper =
spy(SpiHelper.create(SpanExporterFactoryTest.class.getClassLoader()));
private List<ComponentProvider<?>> loadedComponentProviders = Collections.emptyList();
@BeforeEach
@SuppressWarnings("unchecked")
void setup() {
when(spiHelper.load(ComponentProvider.class))
.thenAnswer(
invocation -> {
List<ComponentProvider<?>> result =
(List<ComponentProvider<?>>) invocation.callRealMethod();
loadedComponentProviders =
result.stream().map(Mockito::spy).collect(Collectors.toList());
return loadedComponentProviders;
});
}
private ComponentProvider<?> getComponentProvider(String name, Class<?> type) {
return loadedComponentProviders.stream()
.filter(
componentProvider ->
componentProvider.getName().equals(name)
&& componentProvider.getType().equals(type))
.findFirst()
.orElseThrow(IllegalStateException::new);
}
@Test
void create_OtlpDefaults() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
OtlpHttpSpanExporter expectedExporter = OtlpHttpSpanExporter.getDefault();
cleanup.addCloseable(expectedExporter);
@ -78,10 +108,11 @@ class SpanExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper).loadComponent(eq(SpanExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("otlp", SpanExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isNull();
assertThat(configProperties.getString("endpoint")).isNull();
assertThat(configProperties.getStructured("headers")).isNull();
@ -95,7 +126,6 @@ class SpanExporterFactoryTest {
@Test
void create_OtlpConfigured(@TempDir Path tempDir)
throws CertificateEncodingException, IOException {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
OtlpHttpSpanExporter expectedExporter =
OtlpHttpSpanExporter.builder()
@ -146,13 +176,14 @@ class SpanExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper).loadComponent(eq(SpanExporter.class), eq("otlp"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("otlp", SpanExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("protocol")).isEqualTo("http/protobuf");
assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/traces");
List<StructuredConfigProperties> headers = configProperties.getStructuredList("headers");
List<DeclarativeConfigProperties> headers = configProperties.getStructuredList("headers");
assertThat(headers)
.isNotNull()
.satisfiesExactly(
@ -173,7 +204,6 @@ class SpanExporterFactoryTest {
@Test
void create_Console() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
LoggingSpanExporter expectedExporter = LoggingSpanExporter.create();
cleanup.addCloseable(expectedExporter);
@ -194,7 +224,6 @@ class SpanExporterFactoryTest {
@Test
void create_ZipkinDefaults() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
ZipkinSpanExporter expectedExporter = ZipkinSpanExporter.builder().build();
@ -213,17 +242,17 @@ class SpanExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper).loadComponent(eq(SpanExporter.class), eq("zipkin"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("zipkin", SpanExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("endpoint")).isNull();
assertThat(configProperties.getLong("timeout")).isNull();
}
@Test
void create_ZipkinConfigured() {
spiHelper = spy(spiHelper);
List<Closeable> closeables = new ArrayList<>();
ZipkinSpanExporter expectedExporter =
ZipkinSpanExporter.builder()
@ -248,10 +277,11 @@ class SpanExporterFactoryTest {
assertThat(exporter.toString()).isEqualTo(expectedExporter.toString());
ArgumentCaptor<StructuredConfigProperties> configCaptor =
ArgumentCaptor.forClass(StructuredConfigProperties.class);
verify(spiHelper).loadComponent(eq(SpanExporter.class), eq("zipkin"), configCaptor.capture());
StructuredConfigProperties configProperties = configCaptor.getValue();
ArgumentCaptor<DeclarativeConfigProperties> configCaptor =
ArgumentCaptor.forClass(DeclarativeConfigProperties.class);
ComponentProvider<?> componentProvider = getComponentProvider("zipkin", SpanExporter.class);
verify(componentProvider).create(configCaptor.capture());
DeclarativeConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("endpoint")).isEqualTo("http://zipkin:9411/v1/v2/spans");
assertThat(configProperties.getLong("timeout")).isEqualTo(15_000);
}
@ -270,7 +300,7 @@ class SpanExporterFactoryTest {
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.trace.export.SpanExporter with name \"unknown_key\".");
cleanup.addCloseables(closeables);

View File

@ -9,10 +9,10 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.asser
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.internal.testing.CleanupExtension;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanProcessorComponentProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpModel;
@ -44,7 +44,7 @@ class SpanProcessorFactoryTest {
new SpanProcessorModel().withBatch(new BatchSpanProcessorModel()),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("batch span processor exporter is required but is null");
}
@ -111,7 +111,7 @@ class SpanProcessorFactoryTest {
new SpanProcessorModel().withSimple(new SimpleSpanProcessorModel()),
spiHelper,
Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("simple span processor exporter is required but is null");
}
@ -149,7 +149,7 @@ class SpanProcessorFactoryTest {
"unknown_key", ImmutableMap.of("key1", "value1")),
spiHelper,
new ArrayList<>()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.sdk.trace.SpanProcessor with name \"unknown_key\".");
}

View File

@ -9,13 +9,13 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.asser
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.extension.trace.propagation.JaegerPropagator;
import io.opentelemetry.extension.trace.propagation.OtTracePropagator;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.component.TextMapPropagatorComponentProvider;
import java.util.ArrayList;
import java.util.Arrays;
@ -65,7 +65,7 @@ class TextMapPropagatorFactoryTest {
() ->
TextMapPropagatorFactory.getInstance()
.create(Arrays.asList("none", "foo"), spiHelper, Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage("propagators contains \"none\" along with other propagators");
}
@ -75,7 +75,7 @@ class TextMapPropagatorFactoryTest {
() ->
TextMapPropagatorFactory.getInstance()
.create(Collections.singletonList("foo"), spiHelper, Collections.emptyList()))
.isInstanceOf(ConfigurationException.class)
.isInstanceOf(DeclarativeConfigException.class)
.hasMessage(
"No component provider detected for io.opentelemetry.context.propagation.TextMapPropagator with name \"foo\".");
}
@ -91,7 +91,7 @@ class TextMapPropagatorFactoryTest {
testTextMapPropagator ->
assertThat(testTextMapPropagator.config)
.isInstanceOfSatisfying(
YamlStructuredConfigProperties.class,
YamlDeclarativeConfigProperties.class,
config -> assertThat(config.getPropertyKeys()).isEmpty()));
}
}

View File

@ -5,11 +5,11 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig;
import static io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties.empty;
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
@ -19,7 +19,7 @@ import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class YamlStructuredConfigPropertiesTest {
class YamlDeclarativeConfigPropertiesTest {
private static final String extendedSchema =
"file_format: \"0.3\"\n"
@ -56,23 +56,23 @@ class YamlStructuredConfigPropertiesTest {
+ " - str_key1: str_value1\n"
+ " int_key1: 2";
private StructuredConfigProperties structuredConfigProps;
private DeclarativeConfigProperties structuredConfigProps;
@BeforeEach
void setup() {
OpenTelemetryConfigurationModel configuration =
FileConfiguration.parse(
DeclarativeConfiguration.parse(
new ByteArrayInputStream(extendedSchema.getBytes(StandardCharsets.UTF_8)));
structuredConfigProps = FileConfiguration.toConfigProperties(configuration);
structuredConfigProps = DeclarativeConfiguration.toConfigProperties(configuration);
}
@Test
void configurationSchema() {
// Validate can read declarative configuration schema properties
assertThat(structuredConfigProps.getString("file_format")).isEqualTo("0.3");
StructuredConfigProperties resourceProps = structuredConfigProps.getStructured("resource");
DeclarativeConfigProperties resourceProps = structuredConfigProps.getStructured("resource");
assertThat(resourceProps).isNotNull();
List<StructuredConfigProperties> resourceAttributesList =
List<DeclarativeConfigProperties> resourceAttributesList =
resourceProps.getStructuredList("attributes");
assertThat(resourceAttributesList)
.isNotNull()
@ -90,7 +90,7 @@ class YamlStructuredConfigPropertiesTest {
// Validate can read properties not part of configuration schema
// .other
StructuredConfigProperties otherProps = structuredConfigProps.getStructured("other");
DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other");
assertThat(otherProps).isNotNull();
assertThat(otherProps.getPropertyKeys())
.isEqualTo(
@ -135,14 +135,15 @@ class YamlStructuredConfigPropertiesTest {
.isEqualTo(Collections.singletonList(true));
// .other.map_key
StructuredConfigProperties otherMapKeyProps = otherProps.getStructured("map_key");
DeclarativeConfigProperties otherMapKeyProps = otherProps.getStructured("map_key");
assertThat(otherMapKeyProps).isNotNull();
assertThat(otherMapKeyProps.getPropertyKeys())
.isEqualTo(ImmutableSet.of("str_key1", "int_key1", "map_key1"));
assertThat(otherMapKeyProps.getString("str_key1")).isEqualTo("str_value1");
assertThat(otherMapKeyProps.getInt("int_key1")).isEqualTo(2);
// other.map_key.map_key1
StructuredConfigProperties otherMapKeyMapKey1Props = otherMapKeyProps.getStructured("map_key1");
DeclarativeConfigProperties otherMapKeyMapKey1Props =
otherMapKeyProps.getStructured("map_key1");
assertThat(otherMapKeyMapKey1Props).isNotNull();
assertThat(otherMapKeyMapKey1Props.getPropertyKeys())
.isEqualTo(ImmutableSet.of("str_key2", "int_key2"));
@ -150,22 +151,22 @@ class YamlStructuredConfigPropertiesTest {
assertThat(otherMapKeyMapKey1Props.getInt("int_key2")).isEqualTo(3);
// .other.list_key
List<StructuredConfigProperties> listKey = otherProps.getStructuredList("list_key");
List<DeclarativeConfigProperties> listKey = otherProps.getStructuredList("list_key");
assertThat(listKey).hasSize(2);
StructuredConfigProperties listKeyProps1 = listKey.get(0);
DeclarativeConfigProperties listKeyProps1 = listKey.get(0);
assertThat(listKeyProps1.getPropertyKeys())
.isEqualTo(ImmutableSet.of("str_key1", "int_key1", "map_key1"));
assertThat(listKeyProps1.getString("str_key1")).isEqualTo("str_value1");
assertThat(listKeyProps1.getInt("int_key1")).isEqualTo(2);
// .other.list_key[0]
StructuredConfigProperties listKeyProps1MapKeyProps = listKeyProps1.getStructured("map_key1");
DeclarativeConfigProperties listKeyProps1MapKeyProps = listKeyProps1.getStructured("map_key1");
assertThat(listKeyProps1MapKeyProps).isNotNull();
assertThat(listKeyProps1MapKeyProps.getPropertyKeys())
.isEqualTo(ImmutableSet.of("str_key2", "int_key2"));
assertThat(listKeyProps1MapKeyProps.getString("str_key2")).isEqualTo("str_value2");
assertThat(listKeyProps1MapKeyProps.getInt("int_key2")).isEqualTo(3);
// .other.list_key[1]
StructuredConfigProperties listKeyProps2 = listKey.get(1);
DeclarativeConfigProperties listKeyProps2 = listKey.get(1);
assertThat(listKeyProps2.getPropertyKeys()).isEqualTo(ImmutableSet.of("str_key1", "int_key1"));
assertThat(listKeyProps2.getString("str_key1")).isEqualTo("str_value1");
assertThat(listKeyProps2.getInt("int_key1")).isEqualTo(2);
@ -213,7 +214,7 @@ class YamlStructuredConfigPropertiesTest {
@Test
void wrongType() {
StructuredConfigProperties otherProps = structuredConfigProps.getStructured("other");
DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other");
assertThat(otherProps).isNotNull();
assertThat(otherProps.getString("int_key")).isNull();

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.logs.data.LogRecordData;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
@ -24,15 +24,15 @@ public class LogRecordExporterComponentProvider implements ComponentProvider<Log
}
@Override
public LogRecordExporter create(StructuredConfigProperties config) {
public LogRecordExporter create(DeclarativeConfigProperties config) {
return new TestLogRecordExporter(config);
}
public static class TestLogRecordExporter implements LogRecordExporter {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestLogRecordExporter(StructuredConfigProperties config) {
private TestLogRecordExporter(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.logs.LogRecordProcessor;
import io.opentelemetry.sdk.logs.ReadWriteLogRecord;
@ -24,15 +24,15 @@ public class LogRecordProcessorComponentProvider implements ComponentProvider<Lo
}
@Override
public LogRecordProcessor create(StructuredConfigProperties config) {
public LogRecordProcessor create(DeclarativeConfigProperties config) {
return new TestLogRecordProcessor(config);
}
public static class TestLogRecordProcessor implements LogRecordProcessor {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestLogRecordProcessor(StructuredConfigProperties config) {
private TestLogRecordProcessor(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
@ -27,15 +27,15 @@ public class MetricExporterComponentProvider implements ComponentProvider<Metric
}
@Override
public MetricExporter create(StructuredConfigProperties config) {
public MetricExporter create(DeclarativeConfigProperties config) {
return new TestMetricExporter(config);
}
public static class TestMetricExporter implements MetricExporter {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestMetricExporter(StructuredConfigProperties config) {
private TestMetricExporter(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
public class ResourceComponentProvider implements ComponentProvider<Resource> {
@ -21,7 +21,7 @@ public class ResourceComponentProvider implements ComponentProvider<Resource> {
}
@Override
public Resource create(StructuredConfigProperties config) {
public Resource create(DeclarativeConfigProperties config) {
return Resource.builder().put("shape", "square").put("color", "red").build();
}
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
public class ResourceOrderedFirstComponentProvider implements ComponentProvider<Resource>, Ordered {
@ -22,7 +22,7 @@ public class ResourceOrderedFirstComponentProvider implements ComponentProvider<
}
@Override
public Resource create(StructuredConfigProperties config) {
public Resource create(DeclarativeConfigProperties config) {
return Resource.builder().put("order", "first").build();
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
public class ResourceOrderedSecondComponentProvider
@ -23,7 +23,7 @@ public class ResourceOrderedSecondComponentProvider
}
@Override
public Resource create(StructuredConfigProperties config) {
public Resource create(DeclarativeConfigProperties config) {
return Resource.builder().put("order", "second").build();
}

View File

@ -6,10 +6,10 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
@ -27,15 +27,15 @@ public class SamplerComponentProvider implements ComponentProvider<Sampler> {
}
@Override
public Sampler create(StructuredConfigProperties config) {
public Sampler create(DeclarativeConfigProperties config) {
return new TestSampler(config);
}
public static class TestSampler implements Sampler {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestSampler(StructuredConfigProperties config) {
private TestSampler(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
@ -24,15 +24,15 @@ public class SpanExporterComponentProvider implements ComponentProvider<SpanExpo
}
@Override
public SpanExporter create(StructuredConfigProperties config) {
public SpanExporter create(DeclarativeConfigProperties config) {
return new TestSpanExporter(config);
}
public static class TestSpanExporter implements SpanExporter {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestSpanExporter(StructuredConfigProperties config) {
private TestSpanExporter(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -5,9 +5,9 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
@ -25,15 +25,15 @@ public class SpanProcessorComponentProvider implements ComponentProvider<SpanPro
}
@Override
public SpanProcessor create(StructuredConfigProperties config) {
public SpanProcessor create(DeclarativeConfigProperties config) {
return new TestSpanProcessor(config);
}
public static class TestSpanProcessor implements SpanProcessor {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestSpanProcessor(StructuredConfigProperties config) {
private TestSpanProcessor(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -5,12 +5,12 @@
package io.opentelemetry.sdk.extension.incubator.fileconfig.component;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.Nullable;
@ -27,15 +27,15 @@ public class TextMapPropagatorComponentProvider implements ComponentProvider<Tex
}
@Override
public TextMapPropagator create(StructuredConfigProperties config) {
public TextMapPropagator create(DeclarativeConfigProperties config) {
return new TestTextMapPropagator(config);
}
public static class TestTextMapPropagator implements TextMapPropagator {
public final StructuredConfigProperties config;
public final DeclarativeConfigProperties config;
private TestTextMapPropagator(StructuredConfigProperties config) {
private TestTextMapPropagator(DeclarativeConfigProperties config) {
this.config = config;
}

View File

@ -12,6 +12,7 @@ otelJava.moduleName.set("io.opentelemetry.sdk.extension.trace.jaeger")
dependencies {
api(project(":sdk:all"))
compileOnly(project(":api:incubator"))
compileOnly(project(":sdk-extensions:autoconfigure"))
compileOnly(project(":sdk-extensions:incubator"))

View File

@ -5,9 +5,9 @@
package io.opentelemetry.sdk.extension.trace.jaeger.sampler.internal;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfiguration;
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration;
import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler;
import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSamplerBuilder;
import io.opentelemetry.sdk.trace.samplers.Sampler;
@ -31,7 +31,7 @@ public class JaegerRemoteSamplerComponentProvider implements ComponentProvider<S
}
@Override
public Sampler create(StructuredConfigProperties config) {
public Sampler create(DeclarativeConfigProperties config) {
JaegerRemoteSamplerBuilder builder = JaegerRemoteSampler.builder();
// Optional configuration
@ -43,9 +43,9 @@ public class JaegerRemoteSamplerComponentProvider implements ComponentProvider<S
if (pollingIntervalMs != null) {
builder.setPollingInterval(Duration.ofMillis(pollingIntervalMs));
}
StructuredConfigProperties initialSamplerModel = config.getStructured("initial_sampler");
DeclarativeConfigProperties initialSamplerModel = config.getStructured("initial_sampler");
if (initialSamplerModel != null) {
Sampler initialSampler = FileConfiguration.createSampler(initialSamplerModel);
Sampler initialSampler = DeclarativeConfiguration.createSampler(initialSamplerModel);
builder.setInitialSampler(initialSampler);
}