Add AutoConfigurationCustomizer#addPropertiesCustomizer() extension p… (#4608)

* Add AutoConfigurationCustomizer#addPropertiesCustomizer() extension point

* jApiCmp

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

Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com>

* since

Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com>
This commit is contained in:
Mateusz Rzeszutek 2022-08-07 22:57:33 +02:00 committed by GitHub
parent 1d63b2accd
commit 91bd17e09b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 16 deletions

View File

@ -1,4 +1,7 @@
Comparing source compatibility of against
***! MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++! NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer addPropertiesCustomizer(java.util.function.Function)
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW INTERFACE: io.opentelemetry.sdk.autoconfigure.spi.Ordered

View File

@ -16,6 +16,7 @@ import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/** A builder for customizing OpenTelemetry auto-configuration. */
@ -72,6 +73,21 @@ public interface AutoConfigurationCustomizer {
AutoConfigurationCustomizer addPropertiesSupplier(
Supplier<Map<String, String>> propertiesSupplier);
/**
* Adds a {@link Function} to invoke the with the {@link ConfigProperties} to allow customization.
* The return value of the {@link Function} will be merged into the {@link ConfigProperties}
* before it is used for auto-configuration, overwriting the properties that are already there.
*
* <p>Multiple calls will cause properties to be merged in order, with later ones overwriting
* duplicate keys in earlier ones.
*
* @since 1.17.0
*/
default AutoConfigurationCustomizer addPropertiesCustomizer(
Function<ConfigProperties, Map<String, String>> propertiesCustomizer) {
return this;
}
/**
* Adds a {@link BiFunction} to invoke the with the {@link SdkTracerProviderBuilder} to allow
* customization. The return value of the {@link BiFunction} will replace the passed-in argument.

View File

@ -36,6 +36,7 @@ import java.util.Optional;
import java.util.ServiceLoader;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -77,6 +78,9 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
private Supplier<Map<String, String>> propertiesSupplier = Collections::emptyMap;
private final List<Function<ConfigProperties, Map<String, String>>> propertiesCustomizers =
new ArrayList<>();
private ClassLoader serviceClassLoader =
AutoConfiguredOpenTelemetrySdkBuilder.class.getClassLoader();
@ -90,7 +94,8 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
/**
* Sets the {@link ConfigProperties} to use when resolving properties for auto-configuration.
* {@link #addPropertiesSupplier(Supplier)} will have no effect if this method is used.
* {@link #addPropertiesSupplier(Supplier)} and {@link #addPropertiesCustomizer(Function)} will
* have no effect if this method is used.
*/
AutoConfiguredOpenTelemetrySdkBuilder setConfig(ConfigProperties config) {
requireNonNull(config, "config");
@ -191,6 +196,22 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
return this;
}
/**
* Adds a {@link Function} to invoke the with the {@link ConfigProperties} to allow customization.
* The return value of the {@link Function} will be merged into the {@link ConfigProperties}
* before it is used for auto-configuration, overwriting the properties that are already there.
*
* <p>Multiple calls will cause properties to be merged in order, with later ones overwriting
* duplicate keys in earlier ones.
*/
@Override
public AutoConfiguredOpenTelemetrySdkBuilder addPropertiesCustomizer(
Function<ConfigProperties, Map<String, String>> propertiesCustomizer) {
requireNonNull(propertiesCustomizer, "propertiesCustomizer");
this.propertiesCustomizers.add(propertiesCustomizer);
return this;
}
/**
* Adds a {@link BiFunction} to invoke the with the {@link SdkMeterProviderBuilder} to allow
* customization. The return value of the {@link BiFunction} will replace the passed-in argument.
@ -396,11 +417,20 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
private ConfigProperties getConfig() {
ConfigProperties config = this.config;
if (config == null) {
config = DefaultConfigProperties.get(propertiesSupplier.get());
config = computeConfigProperties();
}
return config;
}
private ConfigProperties computeConfigProperties() {
DefaultConfigProperties properties = DefaultConfigProperties.get(propertiesSupplier.get());
for (Function<ConfigProperties, Map<String, String>> customizer : propertiesCustomizers) {
Map<String, String> overrides = customizer.apply(properties);
properties = DefaultConfigProperties.customize(properties, overrides);
}
return properties;
}
private static <I, O1, O2> BiFunction<I, ConfigProperties, O2> mergeCustomizer(
BiFunction<? super I, ConfigProperties, ? extends O1> first,
BiFunction<? super O1, ConfigProperties, ? extends O2> second) {

View File

@ -36,10 +36,15 @@ final class DefaultConfigProperties implements ConfigProperties {
private final Map<String, String> config;
static ConfigProperties get(Map<String, String> defaultProperties) {
static DefaultConfigProperties get(Map<String, String> defaultProperties) {
return new DefaultConfigProperties(System.getProperties(), System.getenv(), defaultProperties);
}
static DefaultConfigProperties customize(
DefaultConfigProperties previousProperties, Map<String, String> overrides) {
return new DefaultConfigProperties(previousProperties, overrides);
}
// Visible for testing
static ConfigProperties createForTest(Map<String, String> properties) {
return new DefaultConfigProperties(properties, Collections.emptyMap(), Collections.emptyMap());
@ -59,6 +64,15 @@ final class DefaultConfigProperties implements ConfigProperties {
this.config = config;
}
private DefaultConfigProperties(
DefaultConfigProperties previousProperties, Map<String, String> overrides) {
// previousProperties are already normalized, they can be copied as they are
Map<String, String> config = new HashMap<>(previousProperties.config);
overrides.forEach((name, value) -> config.put(normalize(name), value));
this.config = config;
}
@Override
@Nullable
public String getString(String name) {

View File

@ -6,6 +6,7 @@
package io.opentelemetry.sdk.autoconfigure;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
@ -114,8 +115,7 @@ class AutoConfiguredOpenTelemetrySdkTest {
OpenTelemetrySdk sdk =
builder
.addPropertiesSupplier(
() -> Collections.singletonMap("otel.propagators", "tracecontext"))
.addPropertiesSupplier(() -> singletonMap("otel.propagators", "tracecontext"))
.addPropagatorCustomizer(
(previous, config) -> {
assertThat(previous).isSameAs(W3CTraceContextPropagator.getInstance());
@ -205,12 +205,10 @@ class AutoConfiguredOpenTelemetrySdkTest {
void builder_addPropertiesSupplier() {
AutoConfiguredOpenTelemetrySdk autoConfigured =
builder
.addPropertiesSupplier(() -> Collections.singletonMap("key", "valueUnused"))
.addPropertiesSupplier(() -> Collections.singletonMap("key", "value"))
.addPropertiesSupplier(() -> Collections.singletonMap("otel-key", "otel-value"))
.addPropertiesSupplier(
() -> Collections.singletonMap("otel.service.name", "test-service"))
.setResultAsGlobal(false)
.addPropertiesSupplier(() -> singletonMap("key", "valueUnused"))
.addPropertiesSupplier(() -> singletonMap("key", "value"))
.addPropertiesSupplier(() -> singletonMap("otel-key", "otel-value"))
.addPropertiesSupplier(() -> singletonMap("otel.service.name", "test-service"))
.build();
assertThat(autoConfigured.getResource().getAttribute(ResourceAttributes.SERVICE_NAME))
@ -219,6 +217,31 @@ class AutoConfiguredOpenTelemetrySdkTest {
assertThat(autoConfigured.getConfig().getString("otel.key")).isEqualTo("otel-value");
}
@Test
void builder_addPropertiesCustomizer() {
AutoConfiguredOpenTelemetrySdk autoConfigured =
builder
.addPropertiesSupplier(() -> singletonMap("some-key", "defaultValue"))
.addPropertiesSupplier(() -> singletonMap("otel.service.name", "default-service-name"))
.addPropertiesCustomizer(
config -> {
Map<String, String> overrides = new HashMap<>();
overrides.put("some-key", "override");
overrides.put(
"otel.service.name",
config.getString("otel.service.name", "").replace("default", "overridden"));
return overrides;
})
.addPropertiesCustomizer(
config -> singletonMap("some-key", config.getString("some-key", "") + "-2"))
.build();
assertThat(autoConfigured.getResource().getAttribute(ResourceAttributes.SERVICE_NAME))
.isEqualTo("overridden-service-name");
assertThat(autoConfigured.getConfig().getString("some-key")).isEqualTo("override-2");
assertThat(autoConfigured.getConfig().getString("some.key")).isEqualTo("override-2");
}
@Test
void builder_addMeterProviderCustomizer() {
Mockito.lenient().when(metricReader.shutdown()).thenReturn(CompletableResultCode.ofSuccess());
@ -324,8 +347,7 @@ class AutoConfiguredOpenTelemetrySdkTest {
AutoConfiguredOpenTelemetrySdk autoConfiguredSdk =
AutoConfiguredOpenTelemetrySdk.builder()
.addPropertiesSupplier(
() -> Collections.singletonMap("otel.experimental.sdk.enabled", "false"))
.addPropertiesSupplier(() -> singletonMap("otel.experimental.sdk.enabled", "false"))
.addTracerProviderCustomizer(traceCustomizer)
.addMeterProviderCustomizer(metricCustomizer)
.addLogEmitterProviderCustomizer(logCustomizer)
@ -352,9 +374,9 @@ class AutoConfiguredOpenTelemetrySdkTest {
})
.addResourceCustomizer(
(resource, config) -> resource.merge(Resource.builder().put("cow", "moo").build()))
.addPropertiesSupplier(() -> Collections.singletonMap("otel.metrics.exporter", "none"))
.addPropertiesSupplier(() -> Collections.singletonMap("otel.traces.exporter", "none"))
.addPropertiesSupplier(() -> Collections.singletonMap("otel.logs.exporter", "none"))
.addPropertiesSupplier(() -> singletonMap("otel.metrics.exporter", "none"))
.addPropertiesSupplier(() -> singletonMap("otel.traces.exporter", "none"))
.addPropertiesSupplier(() -> singletonMap("otel.logs.exporter", "none"))
.setResultAsGlobal(false);
AutoConfiguredOpenTelemetrySdk autoConfigured = autoConfiguration.build();