Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up code of OpenTelemetryProducer #34946

Merged
merged 1 commit into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
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