Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add ComponentLoader to support more auto configuration scenarios, e.g…
…. spring boot
  • Loading branch information
zeitlinger committed Feb 28, 2024
commit 053186929e502f44ea74ebf9929ee3f033422718
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder setComponentLoader(io.opentelemetry.sdk.autoconfigure.ComponentLoader)
+++* NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.autoconfigure.ComponentLoader (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW SUPERCLASS: java.lang.Object
+++* NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.Iterable<T> load(java.lang.Class<T>)
GENERIC TEMPLATES: +++ T:java.lang.Object
+++* NEW METHOD: PUBLIC(+) java.util.Map<java.lang.String,T> loadConfigurableProviders(java.lang.Class<T>)
GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider
+++* NEW METHOD: PUBLIC(+) java.util.List<T> loadOrdered(java.lang.Class<T>)
GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.autoconfigure.spi.Ordered
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* #getPropagator(ConfigProperties)} will be enabled and available as part of {@link
* OpenTelemetry#getPropagators()}.
*/
public interface ConfigurablePropagatorProvider {
public interface ConfigurablePropagatorProvider extends ConfigurableProvider {
/**
* Returns a {@link TextMapPropagator} that can be registered to OpenTelemetry by providing the
* property value specified by {@link #getName()}.
Expand All @@ -27,5 +27,6 @@ public interface ConfigurablePropagatorProvider {
* property to enable it. If the name is the same as any other defined propagator name, it is
* undefined which will be used.
*/
@Override
String getName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.autoconfigure.spi;

/**
* A named configurable provider.
*
* <p>It can be used to generically determine if a provider should be replaced by another provider
* with the same name.
*/
public interface ConfigurableProvider {
/** Returns the name of this provider. */
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package io.opentelemetry.sdk.autoconfigure.spi.internal;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider;
import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
Expand All @@ -24,7 +25,7 @@
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public interface ConfigurableMetricReaderProvider {
public interface ConfigurableMetricReaderProvider extends ConfigurableProvider {

/**
* Returns a {@link MetricReader} that can be registered to OpenTelemetry by providing the
Expand All @@ -40,5 +41,6 @@ public interface ConfigurableMetricReaderProvider {
* name, the resulting behavior is undefined and it is explicitly unspecified which reader /
* exporter will actually be used.
*/
@Override
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package io.opentelemetry.sdk.autoconfigure.spi.logs;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;

/**
Expand All @@ -16,7 +17,7 @@
*
* @since 1.19.0
*/
public interface ConfigurableLogRecordExporterProvider {
public interface ConfigurableLogRecordExporterProvider extends ConfigurableProvider {

/**
* Returns a {@link LogRecordExporter} that can be registered to OpenTelemetry by providing the
Expand All @@ -30,5 +31,6 @@ public interface ConfigurableLogRecordExporterProvider {
* the name does conflict with another exporter name, the resulting behavior is undefined and it
* is explicitly unspecified which exporter will actually be used.
*/
@Override
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package io.opentelemetry.sdk.autoconfigure.spi.metrics;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ConfigurableMetricReaderProvider;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
Expand All @@ -22,7 +23,7 @@
*
* @since 1.15.0
*/
public interface ConfigurableMetricExporterProvider {
public interface ConfigurableMetricExporterProvider extends ConfigurableProvider {

/**
* Returns a {@link MetricExporter} that can be registered to OpenTelemetry by providing the
Expand All @@ -38,5 +39,6 @@ public interface ConfigurableMetricExporterProvider {
* name, the resulting behavior is undefined and it is explicitly unspecified which exporter /
* reader will actually be used.
*/
@Override
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package io.opentelemetry.sdk.autoconfigure.spi.traces;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider;
import io.opentelemetry.sdk.trace.samplers.Sampler;

/**
Expand All @@ -14,7 +15,7 @@
* returned by {@link #getName()}, the sampler returned by {@link #createSampler(ConfigProperties)}
* will be enabled and added to the SDK.
*/
public interface ConfigurableSamplerProvider {
public interface ConfigurableSamplerProvider extends ConfigurableProvider {

/**
* Returns a {@link Sampler} that can be registered to OpenTelemetry by providing the property
Expand All @@ -28,5 +29,6 @@ public interface ConfigurableSamplerProvider {
* the name does conflict with another exporter name, the resulting behavior is undefined and it
* is explicitly unspecified which exporter will actually be used.
*/
@Override
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package io.opentelemetry.sdk.autoconfigure.spi.traces;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider;
import io.opentelemetry.sdk.trace.export.SpanExporter;

/**
Expand All @@ -14,7 +15,7 @@
* is returned by {@link #getName()}, the exporter returned by {@link
* #createExporter(ConfigProperties)} will be enabled and added to the SDK.
*/
public interface ConfigurableSpanExporterProvider {
public interface ConfigurableSpanExporterProvider extends ConfigurableProvider {

/**
* Returns a {@link SpanExporter} that can be registered to OpenTelemetry by providing the
Expand All @@ -28,5 +29,6 @@ public interface ConfigurableSpanExporterProvider {
* the name does conflict with another exporter name, the resulting behavior is undefined and it
* is explicitly unspecified which exporter will actually be used.
*/
@Override
String getName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,12 @@ public AutoConfiguredOpenTelemetrySdkBuilder setServiceClassLoader(
return this;
}

public AutoConfiguredOpenTelemetrySdkBuilder setComponentLoader(ComponentLoader componentLoader) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this is problematic. Can't have a public API reference an internal class, since this would break when we move ComponentLoader to a public package. The way we've implemented this stuff in the past is:

  • ComponentLoader is in an internal package
  • AutoConfiguredOpenTelemetrySdkBuilder#setComponentLoader is package private
  • A public static method is added to a class in an internal package which reflectively calls AutoConfiguredOpenTelemetrySdkBuilder#setComponentLoader. The natural place for this is AutoConfigureUtil. If a user wants to use the experimental functionality, they can call the public static method on the internal AutoConfigureUtil until we promote the functionality to the public API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, that's why we have those reflective methods 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its strange but it works 😅

requireNonNull(componentLoader, "componentLoader");
this.spiHelper = SpiHelper.create(componentLoader);
return this;
}

/**
* Returns a new {@link AutoConfiguredOpenTelemetrySdk} holding components auto-configured using
* the settings of this {@link AutoConfiguredOpenTelemetrySdkBuilder}.
Expand Down Expand Up @@ -403,41 +409,53 @@ public AutoConfiguredOpenTelemetrySdk build() {
boolean sdkEnabled = !config.getBoolean("otel.sdk.disabled", false);

if (sdkEnabled) {
SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder();
meterProviderBuilder.setResource(resource);
MeterProviderConfiguration.configureMeterProvider(
meterProviderBuilder, config, spiHelper, metricExporterCustomizer, closeables);
meterProviderBuilder = meterProviderCustomizer.apply(meterProviderBuilder, config);
SdkMeterProvider meterProvider = meterProviderBuilder.build();
SdkMeterProvider meterProvider =
spiHelper.loadOptional(SdkMeterProvider.class).orElse(null);
if (meterProvider == null) {
SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder();
meterProviderBuilder.setResource(resource);
MeterProviderConfiguration.configureMeterProvider(
meterProviderBuilder, config, spiHelper, metricExporterCustomizer, closeables);
meterProviderBuilder = meterProviderCustomizer.apply(meterProviderBuilder, config);
meterProvider = meterProviderBuilder.build();
}
closeables.add(meterProvider);

SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder();
tracerProviderBuilder.setResource(resource);
TracerProviderConfiguration.configureTracerProvider(
tracerProviderBuilder,
config,
spiHelper,
meterProvider,
spanExporterCustomizer,
spanProcessorCustomizer,
samplerCustomizer,
closeables);
tracerProviderBuilder = tracerProviderCustomizer.apply(tracerProviderBuilder, config);
SdkTracerProvider tracerProvider = tracerProviderBuilder.build();
SdkTracerProvider tracerProvider =
spiHelper.loadOptional(SdkTracerProvider.class).orElse(null);
if (tracerProvider == null) {
SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder();
tracerProviderBuilder.setResource(resource);
TracerProviderConfiguration.configureTracerProvider(
tracerProviderBuilder,
config,
spiHelper,
meterProvider,
spanExporterCustomizer,
spanProcessorCustomizer,
samplerCustomizer,
closeables);
tracerProviderBuilder = tracerProviderCustomizer.apply(tracerProviderBuilder, config);
tracerProvider = tracerProviderBuilder.build();
}
closeables.add(tracerProvider);

SdkLoggerProviderBuilder loggerProviderBuilder = SdkLoggerProvider.builder();
loggerProviderBuilder.setResource(resource);
LoggerProviderConfiguration.configureLoggerProvider(
loggerProviderBuilder,
config,
spiHelper,
meterProvider,
logRecordExporterCustomizer,
logRecordProcessorCustomizer,
closeables);
loggerProviderBuilder = loggerProviderCustomizer.apply(loggerProviderBuilder, config);
SdkLoggerProvider loggerProvider = loggerProviderBuilder.build();
SdkLoggerProvider loggerProvider =
spiHelper.loadOptional(SdkLoggerProvider.class).orElse(null);
if (loggerProvider == null) {
SdkLoggerProviderBuilder loggerProviderBuilder = SdkLoggerProvider.builder();
loggerProviderBuilder.setResource(resource);
LoggerProviderConfiguration.configureLoggerProvider(
loggerProviderBuilder,
config,
spiHelper,
meterProvider,
logRecordExporterCustomizer,
logRecordProcessorCustomizer,
closeables);
loggerProviderBuilder = loggerProviderCustomizer.apply(loggerProviderBuilder, config);
loggerProvider = loggerProviderBuilder.build();
}
closeables.add(loggerProvider);

ContextPropagators propagators =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.autoconfigure;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigurableProvider;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/** A loader for components that are discovered via SPI. */
public interface ComponentLoader {
<T> Iterable<T> load(Class<T> spiClass);

default <T> Optional<T> loadOptional(Class<T> spiClass) {
Iterable<T> iterable = load(spiClass);
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
}

/**
* Load implementations of an ordered SPI (i.e. implements {@link Ordered}).
*
* @param spiClass the SPI class
* @param <T> the SPI type
* @return list of SPI implementations, in order
*/
default <T extends Ordered> List<T> loadOrdered(Class<T> spiClass) {
return StreamSupport.stream(load(spiClass).spliterator(), false)
.sorted(Comparator.comparing(Ordered::order))
.collect(Collectors.toList());
}

default <T extends ConfigurableProvider> Map<String, T> loadConfigurableProviders(
Class<T> spiClass) {
Map<String, T> components = new HashMap<>();
for (T component : load(spiClass)) {
components.put(component.getName(), component);
}
return components;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ static NamedSpiManager<LogRecordExporter> logRecordExporterSpiManager(
ConfigProperties config, SpiHelper spiHelper) {
return spiHelper.loadConfigurable(
ConfigurableLogRecordExporterProvider.class,
ConfigurableLogRecordExporterProvider::getName,
ConfigurableLogRecordExporterProvider::createExporter,
config);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
Expand All @@ -33,20 +34,25 @@ static void configureMeterProvider(
metricExporterCustomizer,
List<Closeable> closeables) {

// Configure default exemplar filters.
String exemplarFilter =
config.getString("otel.metrics.exemplar.filter", "trace_based").toLowerCase(Locale.ROOT);
switch (exemplarFilter) {
case "always_off":
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOff());
break;
case "always_on":
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOn());
break;
case "trace_based":
default:
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.traceBased());
break;
Optional<ExemplarFilter> spiExemplarFilter = spiHelper.loadOptional(ExemplarFilter.class);
if (spiExemplarFilter.isPresent()) {
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, spiExemplarFilter.get());
} else {
// Configure default exemplar filters.
String exemplarFilter =
config.getString("otel.metrics.exemplar.filter", "trace_based").toLowerCase(Locale.ROOT);
switch (exemplarFilter) {
case "always_off":
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOff());
break;
case "always_on":
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOn());
break;
case "trace_based":
default:
SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.traceBased());
break;
}
}

int cardinalityLimit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ static NamedSpiManager<MetricReader> metricReadersSpiManager(
ConfigProperties config, SpiHelper spiHelper) {
return spiHelper.loadConfigurable(
ConfigurableMetricReaderProvider.class,
ConfigurableMetricReaderProvider::getName,
ConfigurableMetricReaderProvider::createMetricReader,
config);
}
Expand All @@ -107,7 +106,6 @@ static NamedSpiManager<MetricExporter> metricExporterSpiManager(
ConfigProperties config, SpiHelper spiHelper) {
return spiHelper.loadConfigurable(
ConfigurableMetricExporterProvider.class,
ConfigurableMetricExporterProvider::getName,
ConfigurableMetricExporterProvider::createExporter,
config);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ static ContextPropagators configurePropagators(
NamedSpiManager<TextMapPropagator> spiPropagatorsManager =
spiHelper.loadConfigurable(
ConfigurablePropagatorProvider.class,
ConfigurablePropagatorProvider::getName,
ConfigurablePropagatorProvider::getPropagator,
config);

Expand Down
Loading