From 3f9de0c8af37a6bf9a869af117f95b5ae206dd28 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 18 Jul 2023 17:23:12 +0300 Subject: [PATCH 1/3] Ensure that DataSource beans dependencies are initialized before the datasources --- .../quarkus/agroal/deployment/AgroalProcessor.java | 4 +++- .../io/quarkus/agroal/runtime/AgroalRecorder.java | 13 ++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java index 68b3407906052..3891e45c9ddc2 100644 --- a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java +++ b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java @@ -17,6 +17,7 @@ import jakarta.enterprise.inject.Default; import jakarta.inject.Singleton; +import org.jboss.jandex.ClassType; import org.jboss.jandex.DotName; import org.jboss.logging.Logger; @@ -278,9 +279,10 @@ void generateDataSourceBeans(AgroalRecorder recorder, .scope(Singleton.class) .setRuntimeInit() .unremovable() + .addInjectionPoint(ClassType.create(DotName.createSimple(DataSources.class))) // pass the runtime config into the recorder to ensure that the DataSource related beans // are created after runtime configuration has been set up - .supplier(recorder.agroalDataSourceSupplier(dataSourceName, dataSourcesRuntimeConfig)); + .createWith(recorder.agroalDataSourceSupplier(dataSourceName, dataSourcesRuntimeConfig)); if (entry.getValue().isDefault) { configurator.addQualifier(Default.class); diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalRecorder.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalRecorder.java index 3c52c35983506..a69ce8f788d32 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalRecorder.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalRecorder.java @@ -1,8 +1,10 @@ package io.quarkus.agroal.runtime; +import java.util.function.Function; import java.util.function.Supplier; import io.agroal.api.AgroalDataSource; +import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; import io.quarkus.runtime.annotations.Recorder; @@ -18,13 +20,14 @@ public DataSourceSupport get() { }; } - public Supplier agroalDataSourceSupplier(String dataSourceName, + public Function, AgroalDataSource> agroalDataSourceSupplier( + String dataSourceName, @SuppressWarnings("unused") DataSourcesRuntimeConfig dataSourcesRuntimeConfig) { - final AgroalDataSource agroalDataSource = DataSources.fromName(dataSourceName); - return new Supplier() { + return new Function<>() { @Override - public AgroalDataSource get() { - return agroalDataSource; + public AgroalDataSource apply(SyntheticCreationalContext context) { + DataSources dataSources = context.getInjectedReference(DataSources.class); + return dataSources.getDataSource(dataSourceName); } }; } From 690c46b7a2485d905666151b17593dd04c9b1852 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 18 Jul 2023 12:30:55 +0300 Subject: [PATCH 2/3] Properly construct instance of LateBoundBatchSpanProcessor This is now done entirely in a CDI producer method which is then fully initialized when OpenTelemetry autoconfigures itself Fixes: #29987 (which with newer Quarkus versions is even more problematic) --- .../deployment/OpenTelemetryProcessor.java | 18 +- .../exporter/otlp/OtlpExporterProcessor.java | 49 ++-- .../tracing/TracerIdGeneratorBuildItem.java | 19 -- .../deployment/tracing/TracerProcessor.java | 38 +-- .../tracing/TracerProviderBuildItem.java | 18 -- .../tracing/TracerResourceBuildItem.java | 17 -- .../tracing/TracerSpanExportersBuildItem.java | 19 -- .../TracerSpanProcessorsBuildItem.java | 19 -- .../otlp/OtlpExporterBadEndpointTest.java | 2 +- .../runtime/OpenTelemetryProducer.java | 10 + .../runtime/OpenTelemetryRecorder.java | 26 -- .../exporter/otlp/OtlpExporterProvider.java | 14 - .../runtime/exporter/otlp/OtlpRecorder.java | 263 +++++++++--------- .../runtime/tracing/TracerRecorder.java | 53 +--- .../InstrumentationRecorder.java | 25 +- ...est.java => OtlpExporterProviderTest.java} | 2 +- 16 files changed, 205 insertions(+), 387 deletions(-) delete mode 100644 extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerIdGeneratorBuildItem.java delete mode 100644 extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProviderBuildItem.java delete mode 100644 extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerResourceBuildItem.java delete mode 100644 extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanExportersBuildItem.java delete mode 100644 extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanProcessorsBuildItem.java delete mode 100644 extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProvider.java rename extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/{OtlpRecorderTest.java => OtlpExporterProviderTest.java} (99%) diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java index d7ff085e7d956..39d54355bcda5 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java @@ -16,7 +16,6 @@ import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.DotName; -import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.exporter.otlp.internal.OtlpSpanExporterProvider; import io.opentelemetry.instrumentation.annotations.SpanAttribute; @@ -30,6 +29,7 @@ import io.quarkus.agroal.spi.OpenTelemetryInitBuildItem; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem; +import io.quarkus.arc.deployment.BeanContainerBuildItem; import io.quarkus.arc.deployment.InterceptorBindingRegistrarBuildItem; import io.quarkus.arc.deployment.ValidationPhaseBuildItem.ValidationErrorBuildItem; import io.quarkus.arc.processor.AnnotationsTransformer; @@ -43,7 +43,6 @@ import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.RemovedResourceBuildItem; -import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; @@ -56,7 +55,6 @@ import io.quarkus.opentelemetry.runtime.tracing.cdi.WithSpanInterceptor; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.InstrumentationRecorder; import io.quarkus.runtime.LaunchMode; -import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.vertx.core.deployment.CoreVertxBuildItem; @@ -185,21 +183,23 @@ public void transform(TransformationContext context) { @Produce(OpenTelemetryInitBuildItem.class) void createOpenTelemetry( OpenTelemetryRecorder recorder, - InstrumentationRecorder instrumentationRecorder, CoreVertxBuildItem vertx, - LaunchModeBuildItem launchMode, - ShutdownContextBuildItem shutdownContextBuildItem) { + LaunchModeBuildItem launchMode) { if (launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT || launchMode.getLaunchMode() == LaunchMode.TEST) { recorder.resetGlobalOpenTelemetryForDevMode(); } - RuntimeValue openTelemetry = recorder.createOpenTelemetry(shutdownContextBuildItem); - recorder.eagerlyCreateContextStorage(); recorder.storeVertxOnContextStorage(vertx.getVertx()); + } + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void setupVertx(InstrumentationRecorder recorder, + BeanContainerBuildItem beanContainerBuildItem) { - instrumentationRecorder.setTracer(instrumentationRecorder.createTracers(openTelemetry)); + recorder.setupVertxTracer(beanContainerBuildItem.getValue()); } @BuildStep diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java index 92d2d12e9d604..6859fd1662aa4 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterProcessor.java @@ -4,20 +4,28 @@ import java.util.function.BooleanSupplier; -import io.quarkus.arc.deployment.AdditionalBeanBuildItem; -import io.quarkus.arc.deployment.BeanContainerBuildItem; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Singleton; + +import org.jboss.jandex.ClassType; +import org.jboss.jandex.DotName; +import org.jboss.jandex.ParameterizedType; +import org.jboss.jandex.Type; + +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.BuildSteps; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig; import io.quarkus.opentelemetry.runtime.config.build.exporter.OtlpExporterBuildConfig; import io.quarkus.opentelemetry.runtime.config.runtime.OTelRuntimeConfig; import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterRuntimeConfig; -import io.quarkus.opentelemetry.runtime.exporter.otlp.OtlpExporterProvider; +import io.quarkus.opentelemetry.runtime.exporter.otlp.LateBoundBatchSpanProcessor; import io.quarkus.opentelemetry.runtime.exporter.otlp.OtlpRecorder; -import io.quarkus.vertx.deployment.VertxBuildItem; +import io.quarkus.vertx.core.deployment.CoreVertxBuildItem; @BuildSteps(onlyIf = OtlpExporterProcessor.OtlpExporterEnabled.class) public class OtlpExporterProcessor { @@ -34,25 +42,24 @@ public boolean getAsBoolean() { } } - @BuildStep - AdditionalBeanBuildItem createBatchSpanProcessor() { - return AdditionalBeanBuildItem.builder() - .addBeanClass(OtlpExporterProvider.class) - .setUnremovable().build(); - } - + @SuppressWarnings("deprecation") @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - void installBatchSpanProcessorForOtlp( - OtlpRecorder recorder, - LaunchModeBuildItem launchModeBuildItem, + SyntheticBeanBuildItem createBatchSpanProcessor(OtlpRecorder recorder, OTelRuntimeConfig otelRuntimeConfig, OtlpExporterRuntimeConfig exporterRuntimeConfig, - VertxBuildItem vertxBuildItem, - BeanContainerBuildItem beanContainerBuildItem) { - recorder.installBatchSpanProcessorForOtlp(otelRuntimeConfig, - exporterRuntimeConfig, - vertxBuildItem.getVertx(), - launchModeBuildItem.getLaunchMode()); + CoreVertxBuildItem vertxBuildItem) { + return SyntheticBeanBuildItem + .configure(LateBoundBatchSpanProcessor.class) + .types(SpanProcessor.class) + .setRuntimeInit() + .scope(Singleton.class) + .unremovable() + .addInjectionPoint(ParameterizedType.create(DotName.createSimple(Instance.class), + new Type[] { ClassType.create(DotName.createSimple(SpanExporter.class.getName())) }, null)) + .createWith(recorder.batchSpanProcessorForOtlp(otelRuntimeConfig, exporterRuntimeConfig, + vertxBuildItem.getVertx())) + .done(); + } } diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerIdGeneratorBuildItem.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerIdGeneratorBuildItem.java deleted file mode 100644 index 7374cb8476280..0000000000000 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerIdGeneratorBuildItem.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.quarkus.opentelemetry.deployment.tracing; - -import java.util.Optional; - -import io.opentelemetry.sdk.trace.IdGenerator; -import io.quarkus.builder.item.SimpleBuildItem; -import io.quarkus.runtime.RuntimeValue; - -public final class TracerIdGeneratorBuildItem extends SimpleBuildItem { - private final RuntimeValue> idGenerator; - - public TracerIdGeneratorBuildItem(RuntimeValue> idGenerator) { - this.idGenerator = idGenerator; - } - - public RuntimeValue> getIdGenerator() { - return idGenerator; - } -} diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java index c958840b8e702..35641cf858a20 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProcessor.java @@ -143,42 +143,14 @@ void dropNames( @BuildStep @Record(ExecutionTime.STATIC_INIT) - TracerIdGeneratorBuildItem createIdGenerator(TracerRecorder recorder, - BeanContainerBuildItem beanContainerBuildItem) { - return new TracerIdGeneratorBuildItem(recorder.createIdGenerator()); - } - - @BuildStep - @Record(ExecutionTime.STATIC_INIT) - TracerResourceBuildItem createResource(TracerRecorder recorder, - ApplicationInfoBuildItem appInfo, - BeanContainerBuildItem beanContainerBuildItem) { - String serviceName = appInfo.getName(); - String serviceVersion = appInfo.getVersion(); - return new TracerResourceBuildItem(recorder.createResource(Version.getVersion(), serviceName, serviceVersion)); - } - - @BuildStep - @Record(ExecutionTime.STATIC_INIT) - TracerSpanExportersBuildItem createSpanExporters(TracerRecorder recorder, - BeanContainerBuildItem beanContainerBuildItem) { - return new TracerSpanExportersBuildItem(recorder.createSpanExporter()); - } - - @BuildStep - @Record(ExecutionTime.STATIC_INIT) - TracerSpanProcessorsBuildItem createSpanProcessors(TracerRecorder recorder, - BeanContainerBuildItem beanContainerBuildItem) { - return new TracerSpanProcessorsBuildItem(recorder.createSpanProcessors()); - } - - @BuildStep - @Record(ExecutionTime.STATIC_INIT) - void setupTracer( + void staticInitSetup( TracerRecorder recorder, + ApplicationInfoBuildItem appInfo, + BeanContainerBuildItem beanContainerBuildItem, DropNonApplicationUrisBuildItem dropNonApplicationUris, DropStaticResourcesBuildItem dropStaticResources) { - + recorder.setAttributes(beanContainerBuildItem.getValue(), Version.getVersion(), + appInfo.getName(), appInfo.getVersion()); recorder.setupSampler( dropNonApplicationUris.getDropNames(), dropStaticResources.getDropNames()); diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProviderBuildItem.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProviderBuildItem.java deleted file mode 100644 index a912f3b776e05..0000000000000 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerProviderBuildItem.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.quarkus.opentelemetry.deployment.tracing; - -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.quarkus.builder.item.SimpleBuildItem; -import io.quarkus.runtime.RuntimeValue; - -public final class TracerProviderBuildItem extends SimpleBuildItem { - - private final RuntimeValue tracerProvider; - - TracerProviderBuildItem(RuntimeValue tracerProvider) { - this.tracerProvider = tracerProvider; - } - - public RuntimeValue getTracerProvider() { - return tracerProvider; - } -} diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerResourceBuildItem.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerResourceBuildItem.java deleted file mode 100644 index 824bbff551e03..0000000000000 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerResourceBuildItem.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.quarkus.opentelemetry.deployment.tracing; - -import io.opentelemetry.sdk.resources.Resource; -import io.quarkus.builder.item.SimpleBuildItem; -import io.quarkus.runtime.RuntimeValue; - -public final class TracerResourceBuildItem extends SimpleBuildItem { - private final RuntimeValue resource; - - public TracerResourceBuildItem(RuntimeValue resource) { - this.resource = resource; - } - - public RuntimeValue getResource() { - return resource; - } -} diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanExportersBuildItem.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanExportersBuildItem.java deleted file mode 100644 index 629f911e17269..0000000000000 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanExportersBuildItem.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.quarkus.opentelemetry.deployment.tracing; - -import java.util.List; - -import io.opentelemetry.sdk.trace.export.SpanExporter; -import io.quarkus.builder.item.SimpleBuildItem; -import io.quarkus.runtime.RuntimeValue; - -public final class TracerSpanExportersBuildItem extends SimpleBuildItem { - private final RuntimeValue> spanExporters; - - public TracerSpanExportersBuildItem(RuntimeValue> spanExporters) { - this.spanExporters = spanExporters; - } - - public RuntimeValue> getSpanExporters() { - return spanExporters; - } -} diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanProcessorsBuildItem.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanProcessorsBuildItem.java deleted file mode 100644 index 0b0209f72fef0..0000000000000 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/TracerSpanProcessorsBuildItem.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.quarkus.opentelemetry.deployment.tracing; - -import java.util.List; - -import io.opentelemetry.sdk.trace.SpanProcessor; -import io.quarkus.builder.item.SimpleBuildItem; -import io.quarkus.runtime.RuntimeValue; - -public final class TracerSpanProcessorsBuildItem extends SimpleBuildItem { - private final RuntimeValue> spanProcessors; - - public TracerSpanProcessorsBuildItem(RuntimeValue> spanExporters) { - this.spanProcessors = spanExporters; - } - - public RuntimeValue> getSpanProcessors() { - return spanProcessors; - } -} diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterBadEndpointTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterBadEndpointTest.java index 0c9906fb63af8..5d9ab2e4ea83f 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterBadEndpointTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/exporter/otlp/OtlpExporterBadEndpointTest.java @@ -16,7 +16,7 @@ public class OtlpExporterBadEndpointTest { .withEmptyApplication() .overrideConfigKey("quarkus.otel.traces.exporter", "cdi") .overrideConfigKey("quarkus.opentelemetry.tracer.exporter.otlp.endpoint", "httz://nada:zero") - .setExpectedException(IllegalStateException.class); + .setExpectedException(IllegalArgumentException.class); @Inject OpenTelemetry openTelemetry; diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java index d1ad23b1dd432..f2087cdbb0b86 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java @@ -10,6 +10,7 @@ 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; @@ -18,6 +19,7 @@ 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; @@ -62,6 +64,14 @@ public class OpenTelemetryProducer { @Inject ApplicationConfig appConfig; + public void disposeOfOpenTelemetry(@Disposes OpenTelemetry openTelemetry) { + if (openTelemetry instanceof OpenTelemetrySdk) { + var openTelemetrySdk = ((OpenTelemetrySdk) openTelemetry); + openTelemetrySdk.getSdkTracerProvider().forceFlush(); + openTelemetrySdk.getSdkTracerProvider().shutdown(); + } + } + @Produces @Singleton @DefaultBean diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java index 4b8612c59ef02..47939edcbc01d 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryRecorder.java @@ -2,18 +2,10 @@ import java.util.function.Supplier; -import jakarta.enterprise.inject.Any; -import jakarta.enterprise.inject.spi.BeanManager; - import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.events.GlobalEventEmitterProvider; import io.opentelemetry.api.logs.GlobalLoggerProvider; import io.opentelemetry.context.ContextStorage; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.quarkus.arc.Arc; -import io.quarkus.runtime.RuntimeValue; -import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; import io.vertx.core.Vertx; @@ -29,24 +21,6 @@ public void resetGlobalOpenTelemetryForDevMode() { GlobalEventEmitterProvider.resetForTest(); } - /* RUNTIME INIT */ - public RuntimeValue createOpenTelemetry(ShutdownContext shutdownContext) { - - BeanManager beanManager = Arc.container().beanManager(); - - OpenTelemetry openTelemetry = beanManager.createInstance() - .select(OpenTelemetry.class, Any.Literal.INSTANCE).get(); - - // Because we are producing the ObfuscatedOpenTelemetry. These methods are not be available otherwise. - // Register shutdown tasks, because we are using CDI beans - shutdownContext.addShutdownTask(() -> { - ((OpenTelemetrySdk) openTelemetry).getSdkTracerProvider().forceFlush(); - ((OpenTelemetrySdk) openTelemetry).getSdkTracerProvider().shutdown(); - }); - - return new RuntimeValue<>(openTelemetry); - } - /* RUNTIME INIT */ public void eagerlyCreateContextStorage() { ContextStorage.get(); diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProvider.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProvider.java deleted file mode 100644 index 4d8b016d97b02..0000000000000 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProvider.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.quarkus.opentelemetry.runtime.exporter.otlp; - -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Singleton; - -@Deprecated -@Singleton -public class OtlpExporterProvider { - @Produces - @Singleton - public LateBoundBatchSpanProcessor batchSpanProcessorForOtlp() { - return new LateBoundBatchSpanProcessor(); - } -} diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java index 7704736dcc051..b03a806eaee35 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java @@ -8,9 +8,11 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; -import jakarta.enterprise.inject.Any; -import jakarta.enterprise.inject.spi.CDI; +import jakarta.enterprise.inject.Instance; +import jakarta.enterprise.util.TypeLiteral; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.exporter.internal.ExporterBuilderUtil; @@ -18,12 +20,11 @@ import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder; import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.opentelemetry.runtime.config.runtime.OTelRuntimeConfig; import io.quarkus.opentelemetry.runtime.config.runtime.exporter.CompressionType; import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterRuntimeConfig; import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterTracesConfig; -import io.quarkus.runtime.LaunchMode; -import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClientOptions; @@ -31,152 +32,162 @@ import io.vertx.core.net.PemKeyCertOptions; import io.vertx.core.net.PemTrustOptions; +@SuppressWarnings("deprecation") @Recorder public class OtlpRecorder { - static String resolveEndpoint(final OtlpExporterRuntimeConfig runtimeConfig) { - String endpoint = runtimeConfig.traces().legacyEndpoint() - .filter(OtlpRecorder::excludeDefaultEndpoint) - .orElse(runtimeConfig.traces().endpoint() - .filter(OtlpRecorder::excludeDefaultEndpoint) - .orElse(runtimeConfig.endpoint() - .filter(OtlpRecorder::excludeDefaultEndpoint) - .orElse(DEFAULT_GRPC_BASE_URI))); - return endpoint.trim(); - } - - private static boolean excludeDefaultEndpoint(String endpoint) { - return !DEFAULT_GRPC_BASE_URI.equals(endpoint); - } - - public void installBatchSpanProcessorForOtlp( + public Function, LateBoundBatchSpanProcessor> batchSpanProcessorForOtlp( OTelRuntimeConfig otelRuntimeConfig, OtlpExporterRuntimeConfig exporterRuntimeConfig, - RuntimeValue vertx, - LaunchMode launchMode) { - - if (otelRuntimeConfig.sdkDisabled()) { - return; - } - String grpcBaseUri = resolveEndpoint(exporterRuntimeConfig).trim(); - - // Only create the OtlpGrpcSpanExporter if an endpoint was set in runtime config - if (grpcBaseUri.length() > 0) { - try { - // Load span exporter if provided by user - SpanExporter spanExporter = CDI.current() - .select(SpanExporter.class, Any.Literal.INSTANCE).stream().findFirst().orElse(null); - // CDI exporter was already added to a processor by OTEL - if (spanExporter == null) { - spanExporter = createOtlpGrpcSpanExporter(exporterRuntimeConfig, grpcBaseUri, vertx.getValue()); - - // Create BatchSpanProcessor for OTLP and install into LateBoundBatchSpanProcessor - LateBoundBatchSpanProcessor delayedProcessor = CDI.current() - .select(LateBoundBatchSpanProcessor.class, Any.Literal.INSTANCE).get(); - - BatchSpanProcessorBuilder processorBuilder = BatchSpanProcessor.builder(spanExporter); - - processorBuilder.setScheduleDelay(otelRuntimeConfig.bsp().scheduleDelay()); - processorBuilder.setMaxQueueSize(otelRuntimeConfig.bsp().maxQueueSize()); - processorBuilder.setMaxExportBatchSize(otelRuntimeConfig.bsp().maxExportBatchSize()); - processorBuilder.setExporterTimeout(otelRuntimeConfig.bsp().exportTimeout()); - // processorBuilder.setMeterProvider() // TODO add meter provider to span processor. - - delayedProcessor.setBatchSpanProcessorDelegate(processorBuilder.build()); + Supplier vertx) { + var result = new LateBoundBatchSpanProcessor(); + URI grpcBaseUri = getGrpcBaseUri(exporterRuntimeConfig); // do the creation and validation here in order to preserve backward compatibility + return new Function<>() { + @Override + public LateBoundBatchSpanProcessor apply( + SyntheticCreationalContext context) { + if (otelRuntimeConfig.sdkDisabled()) { + return result; } - } catch (IllegalArgumentException iae) { - throw new IllegalStateException("Unable to install OTLP Exporter", iae); - } - } - } - private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig, String endpoint, - Vertx vertx) { + // Only create the OtlpGrpcSpanExporter if an endpoint was set in runtime config and was properly validated at startup + if (grpcBaseUri != null) { + try { + Instance spanExporters = context.getInjectedReference(new TypeLiteral<>() { + }); + if (spanExporters.isUnsatisfied()) { + var spanExporter = createOtlpGrpcSpanExporter(exporterRuntimeConfig, vertx.get(), grpcBaseUri); - OtlpExporterTracesConfig tracesConfig = exporterRuntimeConfig.traces(); - if (tracesConfig.protocol().isPresent()) { - if (!tracesConfig.protocol().get().equals(HTTP_PROTOBUF)) { - throw new IllegalStateException("Only the GRPC Exporter is currently supported. " + - "Please check `quarkus.otel.exporter.otlp.traces.protocol` property"); - } - } + BatchSpanProcessorBuilder processorBuilder = BatchSpanProcessor.builder(spanExporter); - boolean compressionEnabled = false; - if (tracesConfig.compression().isPresent()) { - compressionEnabled = (tracesConfig.compression().get() == CompressionType.GZIP); - } + processorBuilder.setScheduleDelay(otelRuntimeConfig.bsp().scheduleDelay()); + processorBuilder.setMaxQueueSize(otelRuntimeConfig.bsp().maxQueueSize()); + processorBuilder.setMaxExportBatchSize(otelRuntimeConfig.bsp().maxExportBatchSize()); + processorBuilder.setExporterTimeout(otelRuntimeConfig.bsp().exportTimeout()); + // processorBuilder.setMeterProvider() // TODO add meter provider to span processor. - Map headersMap = new HashMap<>(); - OtlpUserAgent.addUserAgentHeader(headersMap::put); - if (tracesConfig.headers().isPresent()) { - List headers = tracesConfig.headers().get(); - if (!headers.isEmpty()) { - for (String header : headers) { - if (header.isEmpty()) { - continue; + result.setBatchSpanProcessorDelegate(processorBuilder.build()); + } + } catch (IllegalArgumentException iae) { + throw new IllegalStateException("Unable to install OTLP Exporter", iae); } - String[] parts = header.split("=", 2); - String key = parts[0].trim(); - String value = parts[1].trim(); - headersMap.put(key, value); } + + return result; } - } - URI grpcBaseUri = ExporterBuilderUtil.validateEndpoint(endpoint); - return new VertxGrpcExporter( - "otlp", // use the same as OTel does - "span", // use the same as OTel does - MeterProvider::noop, - grpcBaseUri, - compressionEnabled, - tracesConfig.timeout(), - headersMap, - new Consumer<>() { - @Override - public void accept(HttpClientOptions options) { - configureTLS(options); + private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig, + Vertx vertx, final URI grpcBaseUri) { + + OtlpExporterTracesConfig tracesConfig = exporterRuntimeConfig.traces(); + if (tracesConfig.protocol().isPresent()) { + if (!tracesConfig.protocol().get().equals(HTTP_PROTOBUF)) { + throw new IllegalStateException("Only the GRPC Exporter is currently supported. " + + "Please check `quarkus.otel.exporter.otlp.traces.protocol` property"); } + } - private void configureTLS(HttpClientOptions options) { - // TODO: this can reuse existing stuff when https://github.com/quarkusio/quarkus/pull/33228 is in - options.setKeyCertOptions(toPemKeyCertOptions(tracesConfig)); - options.setPemTrustOptions(toPemTrustOptions(tracesConfig)); + boolean compressionEnabled = false; + if (tracesConfig.compression().isPresent()) { + compressionEnabled = (tracesConfig.compression().get() == CompressionType.GZIP); + } - if (VertxGrpcExporter.isHttps(grpcBaseUri)) { - options.setSsl(true); - options.setUseAlpn(true); + Map headersMap = new HashMap<>(); + OtlpUserAgent.addUserAgentHeader(headersMap::put); + if (tracesConfig.headers().isPresent()) { + List headers = tracesConfig.headers().get(); + if (!headers.isEmpty()) { + for (String header : headers) { + if (header.isEmpty()) { + continue; + } + String[] parts = header.split("=", 2); + String key = parts[0].trim(); + String value = parts[1].trim(); + headersMap.put(key, value); } } + } - private KeyCertOptions toPemKeyCertOptions(OtlpExporterTracesConfig configuration) { - PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions(); - OtlpExporterTracesConfig.KeyCert keyCert = configuration.keyCert(); - if (keyCert.certs().isPresent()) { - for (String cert : keyCert.certs().get()) { - pemKeyCertOptions.addCertPath(cert); + return new VertxGrpcExporter( + "otlp", // use the same as OTel does + "span", // use the same as OTel does + MeterProvider::noop, + grpcBaseUri, + compressionEnabled, + tracesConfig.timeout(), + headersMap, + new Consumer<>() { + @Override + public void accept(HttpClientOptions options) { + configureTLS(options); } - } - if (keyCert.keys().isPresent()) { - for (String cert : keyCert.keys().get()) { - pemKeyCertOptions.addKeyPath(cert); + + private void configureTLS(HttpClientOptions options) { + // TODO: this can reuse existing stuff when https://github.com/quarkusio/quarkus/pull/33228 is in + options.setKeyCertOptions(toPemKeyCertOptions(tracesConfig)); + options.setPemTrustOptions(toPemTrustOptions(tracesConfig)); + + if (VertxGrpcExporter.isHttps(grpcBaseUri)) { + options.setSsl(true); + options.setUseAlpn(true); + } } - } - return pemKeyCertOptions; - } - private PemTrustOptions toPemTrustOptions(OtlpExporterTracesConfig configuration) { - PemTrustOptions pemTrustOptions = new PemTrustOptions(); - OtlpExporterTracesConfig.TrustCert trustCert = configuration.trustCert(); - if (trustCert.certs().isPresent()) { - for (String cert : trustCert.certs().get()) { - pemTrustOptions.addCertPath(cert); + private KeyCertOptions toPemKeyCertOptions(OtlpExporterTracesConfig configuration) { + PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions(); + OtlpExporterTracesConfig.KeyCert keyCert = configuration.keyCert(); + if (keyCert.certs().isPresent()) { + for (String cert : keyCert.certs().get()) { + pemKeyCertOptions.addCertPath(cert); + } + } + if (keyCert.keys().isPresent()) { + for (String cert : keyCert.keys().get()) { + pemKeyCertOptions.addKeyPath(cert); + } + } + return pemKeyCertOptions; } - } - return pemTrustOptions; - } - }, - vertx); + private PemTrustOptions toPemTrustOptions(OtlpExporterTracesConfig configuration) { + PemTrustOptions pemTrustOptions = new PemTrustOptions(); + OtlpExporterTracesConfig.TrustCert trustCert = configuration.trustCert(); + if (trustCert.certs().isPresent()) { + for (String cert : trustCert.certs().get()) { + pemTrustOptions.addCertPath(cert); + } + } + return pemTrustOptions; + } + }, + vertx); + + } + }; + } + + private URI getGrpcBaseUri(OtlpExporterRuntimeConfig exporterRuntimeConfig) { + String endpoint = resolveEndpoint(exporterRuntimeConfig).trim(); + if (endpoint.isEmpty()) { + return null; + } + return ExporterBuilderUtil.validateEndpoint(endpoint); + } + + static String resolveEndpoint(final OtlpExporterRuntimeConfig runtimeConfig) { + String endpoint = runtimeConfig.traces().legacyEndpoint() + .filter(OtlpRecorder::excludeDefaultEndpoint) + .orElse(runtimeConfig.traces().endpoint() + .filter(OtlpRecorder::excludeDefaultEndpoint) + .orElse(runtimeConfig.endpoint() + .filter(OtlpRecorder::excludeDefaultEndpoint) + .orElse(DEFAULT_GRPC_BASE_URI))); + return endpoint.trim(); } + + private static boolean excludeDefaultEndpoint(String endpoint) { + return !DEFAULT_GRPC_BASE_URI.equals(endpoint); + } + } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java index 7075f8389532e..163ab17705b61 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/TracerRecorder.java @@ -2,22 +2,12 @@ import java.util.HashSet; import java.util.List; -import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; - -import jakarta.enterprise.inject.Any; -import jakarta.enterprise.inject.Instance; -import jakarta.enterprise.inject.spi.BeanManager; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.IdGenerator; -import io.opentelemetry.sdk.trace.SpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; -import io.quarkus.arc.Arc; -import io.quarkus.runtime.RuntimeValue; +import io.quarkus.arc.runtime.BeanContainer; import io.quarkus.runtime.annotations.Recorder; @Recorder @@ -27,24 +17,13 @@ public class TracerRecorder { public static final Set dropStaticResourceTargets = new HashSet<>(); /* STATIC INIT */ - public RuntimeValue> createIdGenerator() { - BeanManager beanManager = Arc.container().beanManager(); - - Instance idGenerator = beanManager.createInstance() - .select(IdGenerator.class, Any.Literal.INSTANCE); - - return new RuntimeValue<>(idGenerator.isResolvable() ? Optional.of(idGenerator.get()) : Optional.empty()); - } - - /* STATIC INIT */ - public RuntimeValue createResource( + public void setAttributes( + BeanContainer beanContainer, String quarkusVersion, String serviceName, String serviceVersion) { - BeanManager beanManager = Arc.container().beanManager(); - DelayedAttributes delayedAttributes = beanManager.createInstance() - .select(DelayedAttributes.class, Any.Literal.INSTANCE).get(); + DelayedAttributes delayedAttributes = beanContainer.beanInstance(DelayedAttributes.class); delayedAttributes.setAttributesDelegate(Resource.getDefault() .merge(Resource.create( @@ -54,30 +33,6 @@ public RuntimeValue createResource( ResourceAttributes.WEBENGINE_NAME, "Quarkus", ResourceAttributes.WEBENGINE_VERSION, quarkusVersion))) .getAttributes()); - - return new RuntimeValue<>(Resource.create(delayedAttributes)); - } - - /* STATIC INIT */ - public RuntimeValue> createSpanExporter() { - BeanManager beanManager = Arc.container().beanManager(); - // Find all SpanExporter instances - Instance allExporters = beanManager.createInstance() - .select(SpanExporter.class, Any.Literal.INSTANCE); - - return new RuntimeValue<>(allExporters.stream().collect(Collectors.toList())); - } - - /* STATIC INIT */ - public RuntimeValue> createSpanProcessors() { - BeanManager beanManager = Arc.container().beanManager(); - - // Find all SpanProcessor instances - Instance allProcessors = beanManager.createInstance() - .select(SpanProcessor.class, Any.Literal.INSTANCE); - - return new RuntimeValue<>(allProcessors.stream().collect(Collectors.toList())); - } /* STATIC INIT */ diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java index 85856e611726a..9613b7a13eebc 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java @@ -1,18 +1,16 @@ package io.quarkus.opentelemetry.runtime.tracing.intrumentation; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import io.opentelemetry.api.OpenTelemetry; +import io.quarkus.arc.runtime.BeanContainer; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.EventBusInstrumenterVertxTracer; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.HttpInstrumenterVertxTracer; -import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.InstrumenterVertxTracer; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxMetricsFactory; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracer; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracingFactory; import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.SqlClientInstrumenterVertxTracer; -import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; import io.vertx.core.VertxOptions; import io.vertx.core.metrics.MetricsOptions; @@ -23,16 +21,6 @@ public class InstrumentationRecorder { public static final OpenTelemetryVertxTracingFactory FACTORY = new OpenTelemetryVertxTracingFactory(); - /* RUNTIME INIT */ - public RuntimeValue createTracers(RuntimeValue openTelemetry) { - List> instrumenterVertxTracers = new ArrayList<>(); - instrumenterVertxTracers.add(new HttpInstrumenterVertxTracer(openTelemetry.getValue())); - instrumenterVertxTracers.add(new EventBusInstrumenterVertxTracer(openTelemetry.getValue())); - // TODO - Selectively register this in the recorder if the SQL Client is available. - instrumenterVertxTracers.add(new SqlClientInstrumenterVertxTracer(openTelemetry.getValue())); - return new RuntimeValue<>(new OpenTelemetryVertxTracer(instrumenterVertxTracers)); - } - /* RUNTIME INIT */ public Consumer getVertxTracingOptions() { TracingOptions tracingOptions = new TracingOptions() @@ -41,8 +29,14 @@ public Consumer getVertxTracingOptions() { } /* RUNTIME INIT */ - public void setTracer(RuntimeValue tracer) { - FACTORY.getVertxTracerDelegator().setDelegate(tracer.getValue()); + public void setupVertxTracer(BeanContainer beanContainer) { + OpenTelemetry openTelemetry = beanContainer.beanInstance(OpenTelemetry.class); + OpenTelemetryVertxTracer openTelemetryVertxTracer = new OpenTelemetryVertxTracer(List.of( + new HttpInstrumenterVertxTracer(openTelemetry), + new EventBusInstrumenterVertxTracer(openTelemetry), + // TODO - Selectively register this in the recorder if the SQL Client is available. + new SqlClientInstrumenterVertxTracer(openTelemetry))); + FACTORY.getVertxTracerDelegator().setDelegate(openTelemetryVertxTracer); } /* RUNTIME INIT */ @@ -52,4 +46,5 @@ public Consumer getVertxTracingMetricsOptions() { .setFactory(new OpenTelemetryVertxMetricsFactory()); return vertxOptions -> vertxOptions.setMetricsOptions(metricsOptions); } + } diff --git a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorderTest.java b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProviderTest.java similarity index 99% rename from extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorderTest.java rename to extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProviderTest.java index 643667e8a3a1b..50b17e200707e 100644 --- a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorderTest.java +++ b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpExporterProviderTest.java @@ -13,7 +13,7 @@ import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterRuntimeConfig; import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterTracesConfig; -class OtlpRecorderTest { +class OtlpExporterProviderTest { @Test public void resolveEndpoint_legacyWins() { From c50213f476141b59e1f96c1df092d7aa9a0f323f Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 18 Jul 2023 14:20:02 +0300 Subject: [PATCH 3/3] Further improve the construction of LateBoundBatchSpanProcessor --- .../runtime/OpenTelemetryProducer.java | 4 +- .../otlp/LateBoundBatchSpanProcessor.java | 8 +--- .../runtime/exporter/otlp/OtlpRecorder.java | 46 +++++++++---------- ...RemoveableLateBoundBatchSpanProcessor.java | 18 ++++++++ 4 files changed, 43 insertions(+), 33 deletions(-) create mode 100644 extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/RemoveableLateBoundBatchSpanProcessor.java diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java index f2087cdbb0b86..ba1ca3cd57436 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryProducer.java @@ -30,6 +30,7 @@ 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; @@ -154,7 +155,8 @@ public SdkTracerProviderBuilder apply(SdkTracerProviderBuilder builder, ConfigProperties configProperties) { if (oTelBuildConfig.traces().enabled().orElse(TRUE)) { idGenerator.stream().findFirst().ifPresent(builder::setIdGenerator); // from cdi - spanProcessors.stream().forEach(builder::addSpanProcessor); + spanProcessors.stream().filter(sp -> !(sp instanceof RemoveableLateBoundBatchSpanProcessor)) + .forEach(builder::addSpanProcessor); } return builder; } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/LateBoundBatchSpanProcessor.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/LateBoundBatchSpanProcessor.java index 06d7e07f38b3d..dde43e7c9dcc0 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/LateBoundBatchSpanProcessor.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/LateBoundBatchSpanProcessor.java @@ -14,19 +14,13 @@ * is started, enabling Quarkus to instantiate a {@link io.opentelemetry.api.trace.TracerProvider} * during static initialization and set a {@link BatchSpanProcessor} delegate during runtime initialization. */ -@Deprecated public class LateBoundBatchSpanProcessor implements SpanProcessor { private static final Logger log = Logger.getLogger(LateBoundBatchSpanProcessor.class); private boolean warningLogged = false; private BatchSpanProcessor delegate; - /** - * Set the actual {@link BatchSpanProcessor} to use as the delegate. - * - * @param delegate Properly constructed {@link BatchSpanProcessor} for processing spans. - */ - public void setBatchSpanProcessorDelegate(BatchSpanProcessor delegate) { + public LateBoundBatchSpanProcessor(BatchSpanProcessor delegate) { this.delegate = delegate; } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java index b03a806eaee35..02087407d5534 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/OtlpRecorder.java @@ -40,40 +40,36 @@ public Function, LateBou OTelRuntimeConfig otelRuntimeConfig, OtlpExporterRuntimeConfig exporterRuntimeConfig, Supplier vertx) { - var result = new LateBoundBatchSpanProcessor(); URI grpcBaseUri = getGrpcBaseUri(exporterRuntimeConfig); // do the creation and validation here in order to preserve backward compatibility return new Function<>() { @Override public LateBoundBatchSpanProcessor apply( SyntheticCreationalContext context) { - if (otelRuntimeConfig.sdkDisabled()) { - return result; + if (otelRuntimeConfig.sdkDisabled() || grpcBaseUri == null) { + return RemoveableLateBoundBatchSpanProcessor.INSTANCE; } - // Only create the OtlpGrpcSpanExporter if an endpoint was set in runtime config and was properly validated at startup - if (grpcBaseUri != null) { - try { - Instance spanExporters = context.getInjectedReference(new TypeLiteral<>() { - }); - if (spanExporters.isUnsatisfied()) { - var spanExporter = createOtlpGrpcSpanExporter(exporterRuntimeConfig, vertx.get(), grpcBaseUri); - - BatchSpanProcessorBuilder processorBuilder = BatchSpanProcessor.builder(spanExporter); - - processorBuilder.setScheduleDelay(otelRuntimeConfig.bsp().scheduleDelay()); - processorBuilder.setMaxQueueSize(otelRuntimeConfig.bsp().maxQueueSize()); - processorBuilder.setMaxExportBatchSize(otelRuntimeConfig.bsp().maxExportBatchSize()); - processorBuilder.setExporterTimeout(otelRuntimeConfig.bsp().exportTimeout()); - // processorBuilder.setMeterProvider() // TODO add meter provider to span processor. - - result.setBatchSpanProcessorDelegate(processorBuilder.build()); - } - } catch (IllegalArgumentException iae) { - throw new IllegalStateException("Unable to install OTLP Exporter", iae); - } + Instance spanExporters = context.getInjectedReference(new TypeLiteral<>() { + }); + if (!spanExporters.isUnsatisfied()) { + return RemoveableLateBoundBatchSpanProcessor.INSTANCE; } - return result; + try { + var spanExporter = createOtlpGrpcSpanExporter(exporterRuntimeConfig, vertx.get(), grpcBaseUri); + + BatchSpanProcessorBuilder processorBuilder = BatchSpanProcessor.builder(spanExporter); + + processorBuilder.setScheduleDelay(otelRuntimeConfig.bsp().scheduleDelay()); + processorBuilder.setMaxQueueSize(otelRuntimeConfig.bsp().maxQueueSize()); + processorBuilder.setMaxExportBatchSize(otelRuntimeConfig.bsp().maxExportBatchSize()); + processorBuilder.setExporterTimeout(otelRuntimeConfig.bsp().exportTimeout()); + // processorBuilder.setMeterProvider() // TODO add meter provider to span processor. + + return new LateBoundBatchSpanProcessor(processorBuilder.build()); + } catch (IllegalArgumentException iae) { + throw new IllegalStateException("Unable to install OTLP Exporter", iae); + } } private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig, diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/RemoveableLateBoundBatchSpanProcessor.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/RemoveableLateBoundBatchSpanProcessor.java new file mode 100644 index 0000000000000..66a3cbff07978 --- /dev/null +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/exporter/otlp/RemoveableLateBoundBatchSpanProcessor.java @@ -0,0 +1,18 @@ +package io.quarkus.opentelemetry.runtime.exporter.otlp; + +import io.quarkus.opentelemetry.runtime.OpenTelemetryProducer; + +/** + * The only point in having this class is to allow {@link OpenTelemetryProducer} + * to easily ignore the configured {@link LateBoundBatchSpanProcessor}. + *

+ * In the future when {@link OpenTelemetryProducer} is replaced by a synthetic bean, this class will no longer be necessary + */ +public final class RemoveableLateBoundBatchSpanProcessor extends LateBoundBatchSpanProcessor { + + public static final RemoveableLateBoundBatchSpanProcessor INSTANCE = new RemoveableLateBoundBatchSpanProcessor(); + + private RemoveableLateBoundBatchSpanProcessor() { + super(null); + } +}