Skip to content

Commit

Permalink
Add AutoConfigurationCustomizer#addPropertiesCustomizer() extension p… (
Browse files Browse the repository at this point in the history
open-telemetry#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 <[email protected]>

* since

Co-authored-by: jack-berg <[email protected]>
  • Loading branch information
Mateusz Rzeszutek and jack-berg authored Aug 7, 2022
1 parent 1d63b2a commit 91bd17e
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
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. */
Expand Down Expand Up @@ -72,6 +73,21 @@ AutoConfigurationCustomizer addSpanExporterCustomizer(
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
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;
Expand Down Expand Up @@ -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();

Expand All @@ -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");
Expand Down Expand Up @@ -191,6 +196,22 @@ public AutoConfiguredOpenTelemetrySdkBuilder addPropertiesSupplier(
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.
Expand Down Expand Up @@ -396,11 +417,20 @@ private void mergeSdkTracerProviderConfigurer() {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -59,6 +64,15 @@ private DefaultConfigProperties(
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -114,8 +115,7 @@ void builder_addPropagatorCustomizer() {

OpenTelemetrySdk sdk =
builder
.addPropertiesSupplier(
() -> Collections.singletonMap("otel.propagators", "tracecontext"))
.addPropertiesSupplier(() -> singletonMap("otel.propagators", "tracecontext"))
.addPropagatorCustomizer(
(previous, config) -> {
assertThat(previous).isSameAs(W3CTraceContextPropagator.getInstance());
Expand Down Expand Up @@ -205,12 +205,10 @@ void builder_addSpanExporterCustomizer() {
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))
Expand All @@ -219,6 +217,31 @@ void builder_addPropertiesSupplier() {
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());
Expand Down Expand Up @@ -324,8 +347,7 @@ public SdkLogEmitterProviderBuilder apply(

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)
Expand All @@ -352,9 +374,9 @@ void tracerProviderCustomizer() {
})
.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();
Expand Down

0 comments on commit 91bd17e

Please sign in to comment.