From 0c92e4907a70b9a77a2cb7d4955bd7b09262e67a Mon Sep 17 00:00:00 2001 From: brunobat Date: Mon, 16 Oct 2023 12:34:02 +0100 Subject: [PATCH 1/2] Fix instantiation of the exporters for Quarkus v3.2+, update parent and fix native mode --- .gitignore | 6 ++ .../ROOT/pages/includes/attributes.adoc | 2 +- pom.xml | 12 +-- .../runtime/LateBoundSpanProcessor.java | 7 +- .../RemovableLateBoundSpanProcessor.java | 14 +++ .../gcp/deployment/GcpExporterProcessor.java | 54 ++++++++++-- .../src/main/resources/application.properties | 2 - .../runtime/pom.xml | 21 ++--- .../gcp/runtime/GcpExporterProvider.java | 17 ---- .../exporter/gcp/runtime/GcpRecorder.java | 87 ++++++++++--------- .../gcp/runtime/graal/Substitutions.java | 61 +++++++++++++ .../deployment/JaegerExporterProcessor.java | 43 +++++++-- .../JaegerExporterBadEndpointTest.java | 2 +- .../jaeger/runtime/JaegerExporterConfig.java | 4 +- .../runtime/JaegerExporterProvider.java | 17 ---- .../jaeger/runtime/JaegerRecorder.java | 58 +++++++------ 16 files changed, 256 insertions(+), 151 deletions(-) create mode 100644 quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/RemovableLateBoundSpanProcessor.java delete mode 100644 quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpExporterProvider.java delete mode 100644 quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterProvider.java diff --git a/.gitignore b/.gitignore index a9264b5..64c07a9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,9 @@ buildNumber.properties /.idea/.gitignore /.idea/ /docs/modules/ROOT/pages/includes/ +/docs/quarkus-opentelemetry-exporter-docs.iml +/quarkus-opentelemetry-exporter-common/quarkus-opentelemetry-exporter-common.iml +/quarkus-opentelemetry-exporter-gcp/deployment/quarkus-opentelemetry-exporter-gcp-deployment.iml +/quarkus-opentelemetry-exporter-gcp/integration-tests/quarkus-opentelemetry-exporter-gcp-integration-tests.iml +/quarkus-opentelemetry-exporter-gcp/runtime/quarkus-opentelemetry-exporter-gcp.iml +/migrate.sh diff --git a/docs/modules/ROOT/pages/includes/attributes.adoc b/docs/modules/ROOT/pages/includes/attributes.adoc index 6fe5e53..afbc7c8 100644 --- a/docs/modules/ROOT/pages/includes/attributes.adoc +++ b/docs/modules/ROOT/pages/includes/attributes.adoc @@ -1,3 +1,3 @@ -:project-version: 1.1.1.Final +:project-version: 2.0.0.Final :examples-dir: ./../examples/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 56abf10..252c9f6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.quarkiverse quarkiverse-parent - 12 + 15 @@ -34,12 +34,12 @@ UTF-8 UTF-8 - 3.0.0.CR2 - 1.23.1 - 1.23.0-alpha + 3.5.0 + 1.31.0 + 1.31.0-alpha - 0.23.0 - 2.13.0 + 0.26.0 + 2.39.0 3.24.2 1.18.0 diff --git a/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/LateBoundSpanProcessor.java b/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/LateBoundSpanProcessor.java index c14330d..21e8f5a 100644 --- a/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/LateBoundSpanProcessor.java +++ b/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/LateBoundSpanProcessor.java @@ -17,12 +17,7 @@ public class LateBoundSpanProcessor implements SpanProcessor { private boolean warningLogged = false; private SpanProcessor delegate; - /** - * Set the actual {@link SpanProcessor} to use as the delegate. - * - * @param delegate Properly constructed {@link SpanProcessor} for processing spans. - */ - public void setSpanProcessorDelegate(SpanProcessor delegate) { + public LateBoundSpanProcessor(SpanProcessor delegate) { this.delegate = delegate; } diff --git a/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/RemovableLateBoundSpanProcessor.java b/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/RemovableLateBoundSpanProcessor.java new file mode 100644 index 0000000..525ffe8 --- /dev/null +++ b/quarkus-opentelemetry-exporter-common/src/main/java/io/quarkiverse/opentelemetry/exporter/common/runtime/RemovableLateBoundSpanProcessor.java @@ -0,0 +1,14 @@ +package io.quarkiverse.opentelemetry.exporter.common.runtime; + +/** + * The only point in having this class is to allow {@link TracerProviderCustomizer} + * to easily ignore the configured {@link LateBoundSpanProcessor}. + */ +public final class RemovableLateBoundSpanProcessor extends LateBoundSpanProcessor { + + public static final RemovableLateBoundSpanProcessor INSTANCE = new RemovableLateBoundSpanProcessor(); + + private RemovableLateBoundSpanProcessor() { + super(null); + } +} diff --git a/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java b/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java index 14c0e55..0b5053e 100644 --- a/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java +++ b/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java @@ -4,14 +4,28 @@ import java.util.function.BooleanSupplier; +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.quarkiverse.opentelemetry.exporter.common.runtime.LateBoundSpanProcessor; import io.quarkiverse.opentelemetry.exporter.gcp.runtime.GcpExporterConfig; -import io.quarkiverse.opentelemetry.exporter.gcp.runtime.GcpExporterProvider; import io.quarkiverse.opentelemetry.exporter.gcp.runtime.GcpRecorder; -import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.BuildSteps; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import io.quarkus.opentelemetry.deployment.exporter.otlp.ExternalOtelExporterBuildItem; @BuildSteps(onlyIf = GcpExporterProcessor.GcpExporterEnabled.class) public class GcpExporterProcessor { @@ -25,17 +39,41 @@ public boolean getAsBoolean() { } @BuildStep - AdditionalBeanBuildItem createBatchSpanProcessor() { - return AdditionalBeanBuildItem.builder() - .addBeanClass(GcpExporterProvider.class) - .setUnremovable().build(); + void registerExternalExporter(BuildProducer buildProducer) { + buildProducer.produce(new ExternalOtelExporterBuildItem("gcp")); + } + + @BuildStep + NativeImageConfigBuildItem nativeImageConfiguration() { + NativeImageConfigBuildItem.Builder builder = NativeImageConfigBuildItem.builder() + .addRuntimeReinitializedClass("com.google.protobuf.UnsafeUtil") + .addRuntimeInitializedClass("io.grpc.netty.shaded.io.grpc.netty.UdsNameResolverProvider"); + // .addRuntimeReinitializedClass("io.grpc.netty.shaded.io.grpc.netty.UdsNameResolverProvider"); + return builder.build(); + } + + @BuildStep + public void configureNativeExecutable(BuildProducer reflectiveClass) { + reflectiveClass.produce( + ReflectiveClassBuildItem.builder("io.grpc.netty.shaded.io.netty.channel.ProtocolNegotiators") + .methods() + .build()); } @BuildStep @Record(RUNTIME_INIT) - void installBatchSpanProcessorForGcp(GcpRecorder recorder, + SyntheticBeanBuildItem installBatchSpanProcessorForGcp(GcpRecorder recorder, LaunchModeBuildItem launchModeBuildItem, GcpExporterConfig.GcpExporterRuntimeConfig runtimeConfig) { - recorder.installSpanProcessorForGcp(runtimeConfig, launchModeBuildItem.getLaunchMode()); + + return SyntheticBeanBuildItem.configure(LateBoundSpanProcessor.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.installSpanProcessorForGcp(runtimeConfig, launchModeBuildItem.getLaunchMode())) + .done(); } } diff --git a/quarkus-opentelemetry-exporter-gcp/integration-tests/src/main/resources/application.properties b/quarkus-opentelemetry-exporter-gcp/integration-tests/src/main/resources/application.properties index 14ef0b9..84ce6d9 100644 --- a/quarkus-opentelemetry-exporter-gcp/integration-tests/src/main/resources/application.properties +++ b/quarkus-opentelemetry-exporter-gcp/integration-tests/src/main/resources/application.properties @@ -2,8 +2,6 @@ quarkus.application.name=opentelemetry-exporter-gcp-integration-test quarkus.application.version=999-SNAPSHOT -quarkus.opentelemetry.tracer.exporter.otlp.enabled=false - simple/mp-rest/url=${test.url} quarkus.generate-code.grpc.scan-for-imports=all \ No newline at end of file diff --git a/quarkus-opentelemetry-exporter-gcp/runtime/pom.xml b/quarkus-opentelemetry-exporter-gcp/runtime/pom.xml index 9bb8eb5..7438e0d 100644 --- a/quarkus-opentelemetry-exporter-gcp/runtime/pom.xml +++ b/quarkus-opentelemetry-exporter-gcp/runtime/pom.xml @@ -33,21 +33,6 @@ io.quarkus quarkus-grpc-common - - com.google.cloud.opentelemetry - exporter-trace - ${gcp-opentelemetry.version} - - - com.google.api - gax-grpc - - - com.google.api - gax - - - com.google.api gax-grpc @@ -58,6 +43,12 @@ gax ${gax-grpc.version} + + com.google.cloud.opentelemetry + exporter-trace + ${gcp-opentelemetry.version} + compile + io.opentelemetry opentelemetry-exporter-otlp-common diff --git a/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpExporterProvider.java b/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpExporterProvider.java deleted file mode 100644 index 1956667..0000000 --- a/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpExporterProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.quarkiverse.opentelemetry.exporter.gcp.runtime; - -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Singleton; - -import io.quarkiverse.opentelemetry.exporter.common.runtime.LateBoundSpanProcessor; -import io.quarkus.arc.DefaultBean; - -@Singleton -public class GcpExporterProvider { - @Produces - @Singleton - @DefaultBean - public LateBoundSpanProcessor spanProcessorForGCP() { - return new LateBoundSpanProcessor(); - } -} diff --git a/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpRecorder.java b/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpRecorder.java index dc6a707..1d5b378 100644 --- a/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpRecorder.java +++ b/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/GcpRecorder.java @@ -1,9 +1,7 @@ package io.quarkiverse.opentelemetry.exporter.gcp.runtime; import java.io.IOException; - -import jakarta.enterprise.inject.Any; -import jakarta.enterprise.inject.spi.CDI; +import java.util.function.Function; import com.google.cloud.opentelemetry.trace.TestTraceConfigurationBuilder; import com.google.cloud.opentelemetry.trace.TraceConfiguration; @@ -13,40 +11,51 @@ import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.quarkiverse.opentelemetry.exporter.common.runtime.LateBoundSpanProcessor; +import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.annotations.Recorder; @Recorder public class GcpRecorder { - public void installSpanProcessorForGcp(GcpExporterConfig.GcpExporterRuntimeConfig runtimeConfig, LaunchMode launchMode) { - if (launchMode != LaunchMode.TEST && runtimeConfig.endpoint.isEmpty()) { - try { - configureTraceExporter(runtimeConfig); - } catch (IOException e) { - throw new RuntimeException("Unable to initialize GCP TraceExporter.", e); - } - } else { - TraceConfiguration.Builder builder = TestTraceConfigurationBuilder.buildTestTraceConfiguration(); - if (runtimeConfig.endpoint.isPresent() && runtimeConfig.endpoint.get().trim().length() > 0) { - builder.setTraceServiceEndpoint(runtimeConfig.endpoint.get()); - } - - TraceConfiguration config = builder.build(); - try { - if (runtimeConfig.cloudrun) { - configureSimpleSpanExporter(config); + public Function, LateBoundSpanProcessor> installSpanProcessorForGcp( + GcpExporterConfig.GcpExporterRuntimeConfig runtimeConfig, + LaunchMode launchMode) { + return new Function<>() { + @Override + public LateBoundSpanProcessor apply( + SyntheticCreationalContext lateBoundSpanProcessorSyntheticCreationalContext) { + + if (launchMode != LaunchMode.TEST && runtimeConfig.endpoint.isEmpty()) { + try { + return configureTraceExporter(runtimeConfig); + } catch (IOException e) { + throw new RuntimeException("Unable to initialize GCP TraceExporter.", e); + } } else { - configureBatchSpanExporter(config); + TraceConfiguration.Builder builder = TestTraceConfigurationBuilder.buildTestTraceConfiguration(); + + if (runtimeConfig.endpoint.isPresent() && runtimeConfig.endpoint.get().trim().length() > 0) { + builder.setTraceServiceEndpoint(runtimeConfig.endpoint.get()); + } + + TraceConfiguration config = builder.build(); + try { + if (runtimeConfig.cloudrun) { + return configureSimpleSpanExporter(config); + } else { + return configureBatchSpanExporter(config); + } + } catch (IOException e) { + throw new RuntimeException("Unable to initialize GCP TraceExporter.", e); + } } - } catch (IOException e) { - throw new RuntimeException("Unable to initialize GCP TraceExporter.", e); } - } - + }; } - private void configureTraceExporter(GcpExporterConfig.GcpExporterRuntimeConfig runtimeConfig) throws IOException { + private LateBoundSpanProcessor configureTraceExporter(GcpExporterConfig.GcpExporterRuntimeConfig runtimeConfig) + throws IOException { TraceConfiguration.Builder builder = TraceConfiguration.builder(); if (runtimeConfig.projectid.isPresent() && runtimeConfig.projectid.get().trim().length() > 0) { @@ -56,29 +65,21 @@ private void configureTraceExporter(GcpExporterConfig.GcpExporterRuntimeConfig r TraceConfiguration traceConfig = builder.build(); // Initialize GCP TraceExporter default configuration if (runtimeConfig.cloudrun) { - configureSimpleSpanExporter(traceConfig); + return configureSimpleSpanExporter(traceConfig); } else { - configureBatchSpanExporter(traceConfig); + return configureBatchSpanExporter(traceConfig); } } - private void configureBatchSpanExporter(TraceConfiguration config) throws IOException { - BatchSpanProcessor batchSpanProcessor = BatchSpanProcessor.builder(TraceExporter.createWithConfiguration(config)) + private LateBoundSpanProcessor configureBatchSpanExporter(TraceConfiguration config) throws IOException { + BatchSpanProcessor batchSpanProcessor = BatchSpanProcessor + .builder(TraceExporter.createWithConfiguration(config)) .build(); - - LateBoundSpanProcessor delayedProcessor = CDI.current() - .select(LateBoundSpanProcessor.class, Any.Literal.INSTANCE).get(); - - delayedProcessor.setSpanProcessorDelegate(batchSpanProcessor); + return new LateBoundSpanProcessor(batchSpanProcessor); } - private void configureSimpleSpanExporter(TraceConfiguration config) throws IOException { - TraceExporter traceExporter = TraceExporter.createWithConfiguration(config); - SpanProcessor spanProcessor = SimpleSpanProcessor.create(traceExporter); - - LateBoundSpanProcessor delayedProcessor = CDI.current() - .select(LateBoundSpanProcessor.class, Any.Literal.INSTANCE).get(); - - delayedProcessor.setSpanProcessorDelegate(spanProcessor); + private LateBoundSpanProcessor configureSimpleSpanExporter(TraceConfiguration config) throws IOException { + SpanProcessor spanProcessor = SimpleSpanProcessor.create(TraceExporter.createWithConfiguration(config)); + return new LateBoundSpanProcessor(spanProcessor); } } diff --git a/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/graal/Substitutions.java b/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/graal/Substitutions.java index 8fba930..892e2f3 100644 --- a/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/graal/Substitutions.java +++ b/quarkus-opentelemetry-exporter-gcp/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/runtime/graal/Substitutions.java @@ -1,9 +1,12 @@ package io.quarkiverse.opentelemetry.exporter.gcp.runtime.graal; import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URI; import java.security.GeneralSecurityException; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; import org.threeten.bp.Duration; @@ -26,8 +29,11 @@ import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.MethodDescriptor; +import io.grpc.NameResolver; import io.grpc.netty.shaded.io.netty.util.internal.logging.InternalLogLevel; import io.grpc.netty.shaded.io.netty.util.internal.logging.InternalLogger; +import io.grpc.netty.shaded.io.netty.util.internal.logging.InternalLoggerFactory; +import sun.misc.Unsafe; /** * Cut out unsupported and optional features that are only present in grpc-alts. @@ -154,9 +160,64 @@ public ClientCall interceptCall(MethodDescriptor clazz) { return new InternalLogger() { diff --git a/quarkus-opentelemetry-exporter-jaeger/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterProcessor.java b/quarkus-opentelemetry-exporter-jaeger/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterProcessor.java index 7ad285c..3aadbf1 100644 --- a/quarkus-opentelemetry-exporter-jaeger/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterProcessor.java +++ b/quarkus-opentelemetry-exporter-jaeger/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterProcessor.java @@ -2,15 +2,29 @@ import java.util.function.BooleanSupplier; +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.exporter.internal.grpc.GrpcSenderProvider; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.quarkiverse.opentelemetry.exporter.common.runtime.LateBoundSpanProcessor; import io.quarkiverse.opentelemetry.exporter.jaeger.runtime.JaegerExporterConfig; -import io.quarkiverse.opentelemetry.exporter.jaeger.runtime.JaegerExporterProvider; import io.quarkiverse.opentelemetry.exporter.jaeger.runtime.JaegerRecorder; -import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; 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.deployment.builditem.nativeimage.ServiceProviderBuildItem; +import io.quarkus.opentelemetry.deployment.exporter.otlp.ExternalOtelExporterBuildItem; @BuildSteps(onlyIf = JaegerExporterProcessor.JaegerExporterEnabled.class) public class JaegerExporterProcessor { @@ -24,17 +38,30 @@ public boolean getAsBoolean() { } @BuildStep - AdditionalBeanBuildItem createBatchSpanProcessor() { - return AdditionalBeanBuildItem.builder() - .addBeanClass(JaegerExporterProvider.class) - .setUnremovable().build(); + void retainBeans(BuildProducer services) { + + services.produce(new ServiceProviderBuildItem(GrpcSenderProvider.class.getName(), + "io.opentelemetry.exporter.sender.okhttp.internal.OkHttpGrpcSenderProvider")); + } + + @BuildStep + void registerExternalExporter(BuildProducer buildProducer) { + buildProducer.produce(new ExternalOtelExporterBuildItem("jaeger")); } @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - void installBatchSpanProcessorForJaeger(JaegerRecorder recorder, + SyntheticBeanBuildItem installBatchSpanProcessorForJaeger(JaegerRecorder recorder, LaunchModeBuildItem launchModeBuildItem, JaegerExporterConfig.JaegerExporterRuntimeConfig runtimeConfig) { - recorder.installBatchSpanProcessorForJaeger(runtimeConfig, launchModeBuildItem.getLaunchMode()); + return SyntheticBeanBuildItem.configure(LateBoundSpanProcessor.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.createBatchSpanProcessorForJaeger(runtimeConfig)) + .done(); } } diff --git a/quarkus-opentelemetry-exporter-jaeger/deployment/src/test/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterBadEndpointTest.java b/quarkus-opentelemetry-exporter-jaeger/deployment/src/test/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterBadEndpointTest.java index 56b1b56..adf496e 100644 --- a/quarkus-opentelemetry-exporter-jaeger/deployment/src/test/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterBadEndpointTest.java +++ b/quarkus-opentelemetry-exporter-jaeger/deployment/src/test/java/io/quarkiverse/opentelemetry/exporter/jaeger/deployment/JaegerExporterBadEndpointTest.java @@ -15,7 +15,7 @@ public class JaegerExporterBadEndpointTest { static final QuarkusUnitTest config = new QuarkusUnitTest() .withEmptyApplication() .overrideConfigKey("quarkus.opentelemetry.tracer.exporter.jaeger.endpoint", "httz://nada:zero") - .setExpectedException(IllegalStateException.class); + .setExpectedException(IllegalArgumentException.class); @Inject OpenTelemetry openTelemetry; diff --git a/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterConfig.java b/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterConfig.java index b78c1cc..4ddacbd 100644 --- a/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterConfig.java +++ b/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterConfig.java @@ -10,6 +10,8 @@ import io.quarkus.runtime.configuration.TrimmedStringConverter; public class JaegerExporterConfig { + static final String DEFAULT_JAEGER_BASE_URI = "http://localhost:14250"; + @ConfigRoot(name = "opentelemetry.tracer.exporter.jaeger", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) public static class JaegerExporterBuildConfig { /** @@ -26,7 +28,7 @@ public static class JaegerExporterRuntimeConfig { /** * The Jaeger endpoint to connect to. The endpoint must start with either http:// or https://. */ - @ConfigItem + @ConfigItem(defaultValue = DEFAULT_JAEGER_BASE_URI) @ConvertWith(TrimmedStringConverter.class) public Optional endpoint; diff --git a/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterProvider.java b/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterProvider.java deleted file mode 100644 index eb1eb8d..0000000 --- a/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerExporterProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.quarkiverse.opentelemetry.exporter.jaeger.runtime; - -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Singleton; - -import io.quarkiverse.opentelemetry.exporter.common.runtime.LateBoundSpanProcessor; -import io.quarkus.arc.DefaultBean; - -@Singleton -public class JaegerExporterProvider { - @Produces - @Singleton - @DefaultBean - public LateBoundSpanProcessor batchSpanProcessorForJaeger() { - return new LateBoundSpanProcessor(); - } -} diff --git a/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerRecorder.java b/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerRecorder.java index 437548c..cee75fd 100644 --- a/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerRecorder.java +++ b/quarkus-opentelemetry-exporter-jaeger/runtime/src/main/java/io/quarkiverse/opentelemetry/exporter/jaeger/runtime/JaegerRecorder.java @@ -1,41 +1,47 @@ package io.quarkiverse.opentelemetry.exporter.jaeger.runtime; -import java.util.Optional; - -import jakarta.enterprise.inject.Any; -import jakarta.enterprise.inject.spi.CDI; +import java.net.URI; +import java.util.function.Function; +import io.opentelemetry.exporter.internal.ExporterBuilderUtil; import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.quarkiverse.opentelemetry.exporter.common.runtime.LateBoundSpanProcessor; -import io.quarkus.runtime.LaunchMode; +import io.quarkiverse.opentelemetry.exporter.common.runtime.RemovableLateBoundSpanProcessor; +import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.runtime.annotations.Recorder; @Recorder public class JaegerRecorder { - public void installBatchSpanProcessorForJaeger(JaegerExporterConfig.JaegerExporterRuntimeConfig runtimeConfig, - LaunchMode launchMode) { - - if (launchMode == LaunchMode.DEVELOPMENT && !runtimeConfig.endpoint.isPresent()) { - // Default the endpoint for development only - runtimeConfig.endpoint = Optional.of("http://localhost:14250"); - } - // Only create the JaegerGrpcSpanExporter if an endpoint was set in runtime config - if (runtimeConfig.endpoint.isPresent() && runtimeConfig.endpoint.get().trim().length() > 0) { - try { - JaegerGrpcSpanExporter jaegerSpanExporter = JaegerGrpcSpanExporter.builder() - .setEndpoint(runtimeConfig.endpoint.get()) - .setTimeout(runtimeConfig.exportTimeout) - .build(); - - // Create BatchSpanProcessor for Jaeger and install into LateBoundSpanProcessor - LateBoundSpanProcessor delayedProcessor = CDI.current() - .select(LateBoundSpanProcessor.class, Any.Literal.INSTANCE).get(); - delayedProcessor.setSpanProcessorDelegate(BatchSpanProcessor.builder(jaegerSpanExporter).build()); - } catch (IllegalArgumentException iae) { - throw new IllegalStateException("Unable to install Jaeger Exporter", iae); + public Function, LateBoundSpanProcessor> createBatchSpanProcessorForJaeger( + JaegerExporterConfig.JaegerExporterRuntimeConfig runtimeConfig) { + URI baseUri = getBaseUri(runtimeConfig); + return new Function<>() { + @Override + public LateBoundSpanProcessor apply(SyntheticCreationalContext context) { + //Will embrace the default, if no endpoint is set + if (baseUri == null) { + return RemovableLateBoundSpanProcessor.INSTANCE; + } + try { + JaegerGrpcSpanExporter jaegerSpanExporter = JaegerGrpcSpanExporter.builder() + .setEndpoint(baseUri.toString()) + .setTimeout(runtimeConfig.exportTimeout) + .build(); + return new LateBoundSpanProcessor(BatchSpanProcessor.builder(jaegerSpanExporter).build()); + } catch (IllegalArgumentException iae) { + throw new IllegalStateException("Unable to install OTel Jaeger Exporter", iae); + } } + }; + } + + private URI getBaseUri(JaegerExporterConfig.JaegerExporterRuntimeConfig runtimeConfig) { + String endpoint = runtimeConfig.endpoint.orElse("").trim(); + if (endpoint.isEmpty()) { + return null; } + return ExporterBuilderUtil.validateEndpoint(endpoint); } } From 3154e234091a02ae45ebe93df77996f0785a08b6 Mon Sep 17 00:00:00 2001 From: brunobat Date: Thu, 15 Feb 2024 16:46:33 +0000 Subject: [PATCH 2/2] explain why native mode not working on GCP --- README.md | 2 +- .../quarkus-opentelemetry-exporter-gcp.adoc | 9 +++ .../gcp/deployment/GcpExporterProcessor.java | 4 +- .../integration-tests/pom.xml | 56 ++++++++++--------- .../exporter/it/GcpExporterIT.java | 4 ++ 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 1ed825b..d5dd183 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Exporters are OpenTelemetry SDK Plugins which implement the Exporter interface, and emit telemetry to consumers, usually observability vendors. Currently, we support this implementation: * Jaeger -* Google Cloud Platform +* Google Cloud Platform (Not available in native mode) ## Documentation diff --git a/docs/modules/ROOT/pages/quarkus-opentelemetry-exporter-gcp.adoc b/docs/modules/ROOT/pages/quarkus-opentelemetry-exporter-gcp.adoc index d588e8e..cf6b335 100644 --- a/docs/modules/ROOT/pages/quarkus-opentelemetry-exporter-gcp.adoc +++ b/docs/modules/ROOT/pages/quarkus-opentelemetry-exporter-gcp.adoc @@ -6,6 +6,15 @@ Exporters are OpenTelemetry SDK Plugins which implement the Exporter interface, This exporter sends data to Google Cloud Platform using https://github.com/GoogleCloudPlatform/opentelemetry-operations-java[opentelemetry-operations-java library]. +[WARNING] +==== +This extension doesn't work on native mode. + +The `UdsNameResolverProvider` is forced to be initialized at run time with no good reason. +This can be related to https://github.com/oracle/graal/pull/8230. +==== + + == Installation === Add exporter dependency diff --git a/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java b/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java index 0b5053e..2eaa106 100644 --- a/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java +++ b/quarkus-opentelemetry-exporter-gcp/deployment/src/main/java/io/quarkiverse/opentelemetry/exporter/gcp/deployment/GcpExporterProcessor.java @@ -46,9 +46,7 @@ void registerExternalExporter(BuildProducer build @BuildStep NativeImageConfigBuildItem nativeImageConfiguration() { NativeImageConfigBuildItem.Builder builder = NativeImageConfigBuildItem.builder() - .addRuntimeReinitializedClass("com.google.protobuf.UnsafeUtil") - .addRuntimeInitializedClass("io.grpc.netty.shaded.io.grpc.netty.UdsNameResolverProvider"); - // .addRuntimeReinitializedClass("io.grpc.netty.shaded.io.grpc.netty.UdsNameResolverProvider"); + .addRuntimeReinitializedClass("com.google.protobuf.UnsafeUtil"); return builder.build(); } diff --git a/quarkus-opentelemetry-exporter-gcp/integration-tests/pom.xml b/quarkus-opentelemetry-exporter-gcp/integration-tests/pom.xml index dcf71bb..4beac6d 100644 --- a/quarkus-opentelemetry-exporter-gcp/integration-tests/pom.xml +++ b/quarkus-opentelemetry-exporter-gcp/integration-tests/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 io.quarkiverse.opentelemetry.exporter @@ -98,29 +99,32 @@ - - - native-image - - - native - - - - - - maven-surefire-plugin - - ${native.surefire.skip} - - - - - - false - native - -H:ReflectionConfigurationFiles=reflection-config.json - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/quarkus-opentelemetry-exporter-gcp/integration-tests/src/test/java/io/quarkiverse/opentelemetry/exporter/it/GcpExporterIT.java b/quarkus-opentelemetry-exporter-gcp/integration-tests/src/test/java/io/quarkiverse/opentelemetry/exporter/it/GcpExporterIT.java index 568c4c4..c82bfb0 100644 --- a/quarkus-opentelemetry-exporter-gcp/integration-tests/src/test/java/io/quarkiverse/opentelemetry/exporter/it/GcpExporterIT.java +++ b/quarkus-opentelemetry-exporter-gcp/integration-tests/src/test/java/io/quarkiverse/opentelemetry/exporter/it/GcpExporterIT.java @@ -1,7 +1,11 @@ package io.quarkiverse.opentelemetry.exporter.it; +import org.junit.jupiter.api.Disabled; + import io.quarkus.test.junit.QuarkusIntegrationTest; @QuarkusIntegrationTest +@Disabled("The UdsNameResolverProvider is forced to be initialized at run time with no good reason. " + + "This can be related to https://github.com/oracle/graal/pull/8230.") public class GcpExporterIT extends GcpTraceBatchExporterTest { }