Skip to content

Commit

Permalink
Merge pull request #34946 from geoand/OpenTelemetryProducer-customizers
Browse files Browse the repository at this point in the history
Clean up code of OpenTelemetryProducer
  • Loading branch information
geoand authored Jul 24, 2023
2 parents 99fb6b6 + d1cff95 commit fa1dced
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.util.ServiceUtil;
import io.quarkus.maven.dependency.ArtifactKey;
import io.quarkus.opentelemetry.runtime.AutoConfiguredOpenTelemetrySdkBuilderCustomizer;
import io.quarkus.opentelemetry.runtime.OpenTelemetryProducer;
import io.quarkus.opentelemetry.runtime.OpenTelemetryRecorder;
import io.quarkus.opentelemetry.runtime.QuarkusContextStorage;
Expand All @@ -72,7 +73,10 @@ public class OpenTelemetryProcessor {
AdditionalBeanBuildItem ensureProducerIsRetained() {
return AdditionalBeanBuildItem.builder()
.setUnremovable()
.addBeanClass(OpenTelemetryProducer.class)
.addBeanClasses(OpenTelemetryProducer.class,
AutoConfiguredOpenTelemetrySdkBuilderCustomizer.ResourceCustomizer.class,
AutoConfiguredOpenTelemetrySdkBuilderCustomizer.SamplerCustomizer.class,
AutoConfiguredOpenTelemetrySdkBuilderCustomizer.TracerProviderCustomizer.class)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package io.quarkus.opentelemetry.runtime;

import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;

import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Singleton;

import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.IdGenerator;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.quarkus.arc.All;
import io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig;
import io.quarkus.opentelemetry.runtime.config.runtime.OTelRuntimeConfig;
import io.quarkus.opentelemetry.runtime.exporter.otlp.RemoveableLateBoundBatchSpanProcessor;
import io.quarkus.opentelemetry.runtime.tracing.DelayedAttributes;
import io.quarkus.opentelemetry.runtime.tracing.DropTargetsSampler;
import io.quarkus.opentelemetry.runtime.tracing.TracerRecorder;
import io.quarkus.opentelemetry.runtime.tracing.TracerUtil;
import io.quarkus.runtime.ApplicationConfig;

public interface AutoConfiguredOpenTelemetrySdkBuilderCustomizer {

void customize(AutoConfiguredOpenTelemetrySdkBuilder builder);

@Singleton
final class ResourceCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderCustomizer {

private final ApplicationConfig appConfig;
private final OTelBuildConfig oTelBuildConfig;
private final OTelRuntimeConfig oTelRuntimeConfig;
private final Instance<DelayedAttributes> delayedAttributes;
private final List<Resource> resources;

public ResourceCustomizer(ApplicationConfig appConfig,
OTelBuildConfig oTelBuildConfig,
OTelRuntimeConfig oTelRuntimeConfig,
@Any Instance<DelayedAttributes> delayedAttributes,
@All List<Resource> resources) {
this.appConfig = appConfig;
this.oTelBuildConfig = oTelBuildConfig;
this.oTelRuntimeConfig = oTelRuntimeConfig;
this.delayedAttributes = delayedAttributes;
this.resources = resources;
}

@Override
public void customize(AutoConfiguredOpenTelemetrySdkBuilder builder) {
builder.addResourceCustomizer(new BiFunction<>() {
@Override
public Resource apply(Resource existingResource, ConfigProperties configProperties) {
if (oTelBuildConfig.traces().enabled().orElse(TRUE)) {
Resource consolidatedResource = existingResource.merge(
Resource.create(delayedAttributes.get()));

// if user explicitly set 'otel.service.name', make sure we don't override it with defaults
// inside resource customizer
String serviceName = oTelRuntimeConfig
.serviceName()
.filter(sn -> !sn.equals(appConfig.name.orElse("unset")))
.orElse(null);

// Merge resource instances with env attributes
Resource resource = resources.stream()
.reduce(Resource.empty(), Resource::merge)
.merge(TracerUtil.mapResourceAttributes(
oTelRuntimeConfig.resourceAttributes().orElse(emptyList()),
serviceName)); // from properties
return consolidatedResource.merge(resource);
} else {
return Resource.builder().build();
}
}
});
}
}

@Singleton
final class SamplerCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderCustomizer {

private final OTelBuildConfig oTelBuildConfig;
private final OTelRuntimeConfig oTelRuntimeConfig;
private final List<Sampler> sampler;

public SamplerCustomizer(OTelBuildConfig oTelBuildConfig,
OTelRuntimeConfig oTelRuntimeConfig,
@All List<Sampler> sampler) {
this.oTelBuildConfig = oTelBuildConfig;
this.oTelRuntimeConfig = oTelRuntimeConfig;
this.sampler = sampler;
}

@Override
public void customize(AutoConfiguredOpenTelemetrySdkBuilder builder) {
builder.addSamplerCustomizer(new BiFunction<>() {
@Override
public Sampler apply(Sampler existingSampler, ConfigProperties configProperties) {
if (oTelBuildConfig.traces().enabled().orElse(TRUE)) {
final Sampler effectiveSampler = sampler.stream().findFirst()
.map(Sampler.class::cast)// use CDI if it exists
.orElse(existingSampler);

//collect default filtering targets (Needed for all samplers)
List<String> dropTargets = new ArrayList<>();
if (oTelRuntimeConfig.traces().suppressNonApplicationUris()) {//default is true
dropTargets.addAll(TracerRecorder.dropNonApplicationUriTargets);
}
if (!oTelRuntimeConfig.traces().includeStaticResources()) {// default is false
dropTargets.addAll(TracerRecorder.dropStaticResourceTargets);
}

// make sure dropped targets are not sampled
if (!dropTargets.isEmpty()) {
return new DropTargetsSampler(effectiveSampler, dropTargets);
} else {
return effectiveSampler;
}
} else {
return Sampler.alwaysOff();
}
}
});
}
}

@Singleton
final class TracerProviderCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderCustomizer {

private final OTelBuildConfig oTelBuildConfig;
private final List<IdGenerator> idGenerator;
private final List<SpanProcessor> spanProcessors;

public TracerProviderCustomizer(OTelBuildConfig oTelBuildConfig,
@All List<IdGenerator> idGenerator,
@All List<SpanProcessor> spanProcessors) {
this.oTelBuildConfig = oTelBuildConfig;
this.idGenerator = idGenerator;
this.spanProcessors = spanProcessors;
}

@Override
public void customize(AutoConfiguredOpenTelemetrySdkBuilder builder) {
builder.addTracerProviderCustomizer(
new BiFunction<>() {
@Override
public SdkTracerProviderBuilder apply(SdkTracerProviderBuilder builder,
ConfigProperties configProperties) {
if (oTelBuildConfig.traces().enabled().orElse(TRUE)) {
idGenerator.stream().findFirst().ifPresent(builder::setIdGenerator); // from cdi
spanProcessors.stream().filter(sp -> !(sp instanceof RemoveableLateBoundBatchSpanProcessor))
.forEach(builder::addSpanProcessor);
}
return builder;
}
});
}
}
}
Original file line number Diff line number Diff line change
@@ -1,70 +1,28 @@
package io.quarkus.opentelemetry.runtime;

import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.Disposes;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import org.eclipse.microprofile.config.ConfigProvider;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.IdGenerator;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.quarkus.arc.All;
import io.quarkus.arc.DefaultBean;
import io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig;
import io.quarkus.opentelemetry.runtime.config.runtime.OTelRuntimeConfig;
import io.quarkus.opentelemetry.runtime.exporter.otlp.RemoveableLateBoundBatchSpanProcessor;
import io.quarkus.opentelemetry.runtime.tracing.DelayedAttributes;
import io.quarkus.opentelemetry.runtime.tracing.DropTargetsSampler;
import io.quarkus.opentelemetry.runtime.tracing.TracerRecorder;
import io.quarkus.opentelemetry.runtime.tracing.TracerUtil;
import io.quarkus.runtime.ApplicationConfig;
import io.smallrye.config.ConfigValue;
import io.smallrye.config.NameIterator;
import io.smallrye.config.SmallRyeConfig;

@Singleton
public class OpenTelemetryProducer {

@Inject
Instance<IdGenerator> idGenerator;
@Inject
@Any
Instance<Resource> resources;
@Inject
@Any
Instance<DelayedAttributes> delayedAttributes;
@Inject
@Any
Instance<Sampler> sampler;
@Inject
@Any
Instance<SpanProcessor> spanProcessors;
@Inject
OTelBuildConfig oTelBuildConfig;
@Inject
OTelRuntimeConfig oTelRuntimeConfig;

@Inject
ApplicationConfig appConfig;

public void disposeOfOpenTelemetry(@Disposes OpenTelemetry openTelemetry) {
if (openTelemetry instanceof OpenTelemetrySdk) {
var openTelemetrySdk = ((OpenTelemetrySdk) openTelemetry);
Expand All @@ -76,7 +34,8 @@ public void disposeOfOpenTelemetry(@Disposes OpenTelemetry openTelemetry) {
@Produces
@Singleton
@DefaultBean
public OpenTelemetry getOpenTelemetry() {
public OpenTelemetry getOpenTelemetry(OTelRuntimeConfig oTelRuntimeConfig,
@All List<AutoConfiguredOpenTelemetrySdkBuilderCustomizer> builderCustomizers) {
final Map<String, String> oTelConfigs = getOtelConfigs();

if (oTelRuntimeConfig.sdkDisabled()) {
Expand All @@ -88,81 +47,16 @@ public OpenTelemetry getOpenTelemetry() {
.getOpenTelemetrySdk();
}

final AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk = AutoConfiguredOpenTelemetrySdk.builder()
var builder = AutoConfiguredOpenTelemetrySdk.builder()
.setResultAsGlobal(true)
.registerShutdownHook(false)
.addPropertiesSupplier(() -> oTelConfigs)
.setServiceClassLoader(Thread.currentThread().getContextClassLoader())
// no customization needed for spanExporter. Loads SPI from CDI
.addResourceCustomizer(new BiFunction<Resource, ConfigProperties, Resource>() {
@Override
public Resource apply(Resource existingResource, ConfigProperties configProperties) {
if (oTelBuildConfig.traces().enabled().orElse(TRUE)) {
Resource consolidatedResource = existingResource.merge(
Resource.create(delayedAttributes.get())); // from cdi

// if user explicitly set 'otel.service.name', make sure we don't override it with defaults
// inside resource customizer
String serviceName = oTelRuntimeConfig
.serviceName()
.filter(sn -> !sn.equals(appConfig.name.orElse("unset")))
.orElse(null);

// Merge resource instances with env attributes
Resource resource = resources.stream()
.reduce(Resource.empty(), Resource::merge)
.merge(TracerUtil.mapResourceAttributes(
oTelRuntimeConfig.resourceAttributes().orElse(emptyList()),
serviceName)); // from properties
return consolidatedResource.merge(resource);
} else {
return Resource.builder().build();
}
}
})
.addSamplerCustomizer(new BiFunction<Sampler, ConfigProperties, Sampler>() {
@Override
public Sampler apply(Sampler existingSampler, ConfigProperties configProperties) {
if (oTelBuildConfig.traces().enabled().orElse(TRUE)) {
final Sampler effectiveSampler = sampler.stream().findFirst()
.map(Sampler.class::cast)// use CDI if it exists
.orElse(existingSampler);

//collect default filtering targets (Needed for all samplers)
List<String> dropTargets = new ArrayList<>();
if (oTelRuntimeConfig.traces().suppressNonApplicationUris()) {//default is true
dropTargets.addAll(TracerRecorder.dropNonApplicationUriTargets);
}
if (!oTelRuntimeConfig.traces().includeStaticResources()) {// default is false
dropTargets.addAll(TracerRecorder.dropStaticResourceTargets);
}
.setServiceClassLoader(Thread.currentThread().getContextClassLoader());
for (var customizer : builderCustomizers) {
customizer.customize(builder);
}

// make sure dropped targets are not sampled
if (!dropTargets.isEmpty()) {
return new DropTargetsSampler(effectiveSampler, dropTargets);
} else {
return effectiveSampler;
}
} else {
return Sampler.alwaysOff();
}
}
})
.addTracerProviderCustomizer(
new BiFunction<SdkTracerProviderBuilder, ConfigProperties, SdkTracerProviderBuilder>() {
@Override
public SdkTracerProviderBuilder apply(SdkTracerProviderBuilder builder,
ConfigProperties configProperties) {
if (oTelBuildConfig.traces().enabled().orElse(TRUE)) {
idGenerator.stream().findFirst().ifPresent(builder::setIdGenerator); // from cdi
spanProcessors.stream().filter(sp -> !(sp instanceof RemoveableLateBoundBatchSpanProcessor))
.forEach(builder::addSpanProcessor);
}
return builder;
}
})
.build();
return autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk();
return builder.build().getOpenTelemetrySdk();
}

private Map<String, String> getOtelConfigs() {
Expand Down

0 comments on commit fa1dced

Please sign in to comment.