From 351c9ab92a005eae17e2b423c76b3b89918670cc Mon Sep 17 00:00:00 2001 From: Raul Valdoleiros Date: Fri, 16 Jul 2021 09:41:25 +0100 Subject: [PATCH] Opentracing - Add zipkin compatibility mode --- .github/native-tests.json | 2 +- bom/application/pom.xml | 15 ++ docs/src/main/asciidoc/opentracing.adoc | 21 +++ extensions/jaeger/deployment/pom.xml | 11 +- .../jaeger/deployment/JaegerProcessor.java | 14 +- .../jaeger/deployment/ZipkinProcessor.java | 33 +++++ .../jaeger/test/QuarkusJaegerTracerTest.java | 98 ++++++++++++ extensions/jaeger/runtime/pom.xml | 9 ++ .../runtime/JaegerDeploymentRecorder.java | 37 +++-- .../jaeger/runtime/QuarkusJaegerTracer.java | 39 +++++ .../jaeger/runtime/ReporterFactory.java | 9 ++ .../quarkus/jaeger/runtime/ZipkinConfig.java | 18 +++ .../runtime/ZipkinReporterFactoryImpl.java | 16 ++ .../runtime/ZipkinReporterProvider.java | 13 ++ integration-tests/pom.xml | 2 +- .../smallrye-opentracing/pom.xml | 139 ++++++++++++++++++ .../it/rest/client/server/EchoService.java | 16 ++ .../src/main/resources/application.properties | 5 + .../it/rest/client/WireMockZipkin.java | 39 +++++ .../it/rest/client/ZipkinIntegrationTest.java | 46 ++++++ .../rest/client/ZipkinIntegrationTestIT.java | 7 + 21 files changed, 570 insertions(+), 19 deletions(-) create mode 100644 extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/ZipkinProcessor.java create mode 100644 extensions/jaeger/deployment/src/test/java/io/quarkus/jaeger/test/QuarkusJaegerTracerTest.java create mode 100644 extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ReporterFactory.java create mode 100644 extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinConfig.java create mode 100644 extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterFactoryImpl.java create mode 100644 extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterProvider.java create mode 100644 integration-tests/smallrye-opentracing/pom.xml create mode 100644 integration-tests/smallrye-opentracing/src/main/java/io/quarkus/it/rest/client/server/EchoService.java create mode 100644 integration-tests/smallrye-opentracing/src/main/resources/application.properties create mode 100644 integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/WireMockZipkin.java create mode 100644 integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTest.java create mode 100644 integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTestIT.java diff --git a/.github/native-tests.json b/.github/native-tests.json index bb65386d34e64..385c17c24407b 100644 --- a/.github/native-tests.json +++ b/.github/native-tests.json @@ -111,7 +111,7 @@ { "category": "Misc3", "timeout": 65, - "test-modules": "kubernetes-client, openshift-client, smallrye-config, smallrye-graphql, smallrye-graphql-client, smallrye-metrics", + "test-modules": "kubernetes-client, openshift-client, smallrye-config, smallrye-graphql, smallrye-graphql-client, smallrye-metrics, smallrye-opentracing", "os-name": "ubuntu-latest" }, { diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 4141d71810dc3..647070f7435c9 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -2864,6 +2864,21 @@ jaeger-thrift ${jaeger.version} + + io.jaegertracing + jaeger-zipkin + ${jaeger.version} + + + commons-logging + commons-logging + + + javax.annotation + javax.annotation-api + + + com.h2database h2 diff --git a/docs/src/main/asciidoc/opentracing.adoc b/docs/src/main/asciidoc/opentracing.adoc index 080b90378e910..79e850829723d 100644 --- a/docs/src/main/asciidoc/opentracing.adoc +++ b/docs/src/main/asciidoc/opentracing.adoc @@ -282,6 +282,27 @@ Following the link:mongodb[MongoDB guide], the command listener will be register quarkus.mongodb.tracing.enabled=true ---- +=== Zipkin compatibility mode + +To enable it, add the following dependency to your pom.xml: + +[source, xml] +---- + + io.jaegertracing + jaeger-zipkin + +---- + +It contains the dependencies to convert the request to zipkin format. +The zipkin compatibility mode will be activated after defining the config property as follows: + +[source, properties] +---- +# Enable zipkin compatibility mode +quarkus.jaeger.zipkin.compatibility-mode=true +---- + [[configuration-reference]] == Jaeger Configuration Reference diff --git a/extensions/jaeger/deployment/pom.xml b/extensions/jaeger/deployment/pom.xml index d016032ea322d..4b901e141b351 100644 --- a/extensions/jaeger/deployment/pom.xml +++ b/extensions/jaeger/deployment/pom.xml @@ -34,13 +34,22 @@ io.quarkus quarkus-arc-deployment - test io.quarkus quarkus-smallrye-metrics-deployment test + + org.mockito + mockito-inline + test + + + io.jaegertracing + jaeger-zipkin + test + diff --git a/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/JaegerProcessor.java b/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/JaegerProcessor.java index 1d83c719d8971..2a473af8d648e 100644 --- a/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/JaegerProcessor.java +++ b/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/JaegerProcessor.java @@ -15,6 +15,7 @@ import io.quarkus.jaeger.runtime.JaegerBuildTimeConfig; import io.quarkus.jaeger.runtime.JaegerConfig; import io.quarkus.jaeger.runtime.JaegerDeploymentRecorder; +import io.quarkus.jaeger.runtime.ZipkinConfig; import io.quarkus.runtime.ApplicationConfig; import io.quarkus.runtime.metrics.MetricsFactory; @@ -29,18 +30,18 @@ void setVersion(JaegerDeploymentRecorder jdr) { @BuildStep @Record(ExecutionTime.RUNTIME_INIT) ExtensionSslNativeSupportBuildItem setupTracer(JaegerDeploymentRecorder jdr, JaegerBuildTimeConfig buildTimeConfig, - JaegerConfig jaeger, - ApplicationConfig appConfig, Optional metricsCapability) { + JaegerConfig jaeger, ApplicationConfig appConfig, Optional metricsCapability, + ZipkinConfig zipkinConfig) { if (buildTimeConfig.enabled) { if (buildTimeConfig.metricsEnabled && metricsCapability.isPresent()) { if (metricsCapability.get().metricsSupported(MetricsFactory.MICROMETER)) { - jdr.registerTracerWithMicrometerMetrics(jaeger, appConfig); + jdr.registerTracerWithMicrometerMetrics(jaeger, appConfig, zipkinConfig); } else { - jdr.registerTracerWithMpMetrics(jaeger, appConfig); + jdr.registerTracerWithMpMetrics(jaeger, appConfig, zipkinConfig); } } else { - jdr.registerTracerWithoutMetrics(jaeger, appConfig); + jdr.registerTracerWithoutMetrics(jaeger, appConfig, zipkinConfig); } } @@ -58,7 +59,6 @@ public ReflectiveClassBuildItem reflectiveClasses() { return ReflectiveClassBuildItem .builder("io.jaegertracing.internal.samplers.http.SamplingStrategyResponse", "io.jaegertracing.internal.samplers.http.ProbabilisticSamplingStrategy") - .finalFieldsWritable(true) - .build(); + .finalFieldsWritable(true).build(); } } diff --git a/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/ZipkinProcessor.java b/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/ZipkinProcessor.java new file mode 100644 index 0000000000000..aa506fa5bdf8b --- /dev/null +++ b/extensions/jaeger/deployment/src/main/java/io/quarkus/jaeger/deployment/ZipkinProcessor.java @@ -0,0 +1,33 @@ +package io.quarkus.jaeger.deployment; + +import java.util.function.BooleanSupplier; + +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.jaeger.runtime.JaegerDeploymentRecorder; +import io.quarkus.jaeger.runtime.ZipkinConfig; +import io.quarkus.jaeger.runtime.ZipkinReporterProvider; + +public class ZipkinProcessor { + + static final String REGISTRY_CLASS_NAME = "zipkin2.reporter.urlconnection.URLConnectionSender"; + static final Class REGISTRY_CLASS = JaegerDeploymentRecorder.getClassForName(REGISTRY_CLASS_NAME); + + public static class ZipkinEnabled implements BooleanSupplier { + ZipkinConfig config; + + public boolean getAsBoolean() { + return REGISTRY_CLASS != null && config.compatibilityMode; + } + } + + @BuildStep(onlyIf = ZipkinEnabled.class) + void addZipkinClasses(BuildProducer additionalBeans) { + + // Add Zipkin classes + additionalBeans.produce(AdditionalBeanBuildItem.builder().addBeanClass(ZipkinReporterProvider.class) + .setUnremovable().build()); + + } +} diff --git a/extensions/jaeger/deployment/src/test/java/io/quarkus/jaeger/test/QuarkusJaegerTracerTest.java b/extensions/jaeger/deployment/src/test/java/io/quarkus/jaeger/test/QuarkusJaegerTracerTest.java new file mode 100644 index 0000000000000..302e586faf822 --- /dev/null +++ b/extensions/jaeger/deployment/src/test/java/io/quarkus/jaeger/test/QuarkusJaegerTracerTest.java @@ -0,0 +1,98 @@ +package io.quarkus.jaeger.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import javax.enterprise.inject.Default; +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.spi.CDI; + +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import io.jaegertracing.Configuration; +import io.jaegertracing.internal.JaegerTracer; +import io.jaegertracing.internal.JaegerTracer.Builder; +import io.jaegertracing.spi.Reporter; +import io.jaegertracing.zipkin.ZipkinV2Reporter; +import io.opentracing.Tracer; +import io.quarkus.jaeger.runtime.QuarkusJaegerTracer; +import io.quarkus.jaeger.runtime.ReporterFactory; +import io.quarkus.jaeger.runtime.ZipkinReporterFactoryImpl; + +public class QuarkusJaegerTracerTest { + + @Test + @SuppressWarnings("unchecked") + public void withzipkinCompatibilityMode() { + + try (MockedStatic mockedStaticConfiguration = Mockito.mockStatic(Configuration.class); + MockedStatic mockedStaticCDI = Mockito.mockStatic(CDI.class)) { + + CDI mockedCDI = (CDI) Mockito.mock(CDI.class); + + mockedStaticCDI.when(() -> CDI.current()).thenReturn(mockedCDI); + + Instance instanceCDI = Mockito.mock(Instance.class); + Mockito.when(instanceCDI.isAmbiguous()).thenReturn(false); + Mockito.when(instanceCDI.isUnsatisfied()).thenReturn(false); + Mockito.when(instanceCDI.get()).thenReturn(new ZipkinReporterFactoryImpl()); + Mockito.when(mockedCDI.select(ReporterFactory.class, Default.Literal.INSTANCE)).thenReturn(instanceCDI); + + Configuration mockedInstanceConfiguration = Mockito.mock(Configuration.class); + Builder mockedBuilder = Mockito.mock(Builder.class); + Tracer mockedTracer = Mockito.mock(JaegerTracer.class); + + mockedStaticConfiguration.when(() -> Configuration.fromEnv()).thenReturn(mockedInstanceConfiguration); + mockedStaticConfiguration.when(() -> mockedInstanceConfiguration.withMetricsFactory(Mockito.any())) + .thenReturn(mockedInstanceConfiguration); + mockedStaticConfiguration.when(() -> mockedInstanceConfiguration.getTracerBuilder()) + .thenReturn(mockedBuilder); + mockedStaticConfiguration.when(() -> mockedBuilder.withScopeManager(Mockito.any())) + .thenReturn(mockedBuilder); + mockedStaticConfiguration.when(() -> mockedBuilder.withReporter(Mockito.any())).thenReturn(mockedBuilder); + mockedStaticConfiguration.when(() -> mockedBuilder.build()).thenReturn(mockedTracer); + + QuarkusJaegerTracer tracer = new QuarkusJaegerTracer(); + tracer.setZipkinCompatibilityMode(true); + tracer.setEndpoint("http://localhost"); + tracer.toString(); + tracer.close(); + + ArgumentCaptor argument = ArgumentCaptor.forClass(Reporter.class); + Mockito.verify(mockedBuilder).withReporter(argument.capture()); + assertEquals(ZipkinV2Reporter.class, argument.getValue().getClass()); + } + + } + + @Test + public void withoutZipkinCompatibilityMode() { + try (MockedStatic mockedStaticConfiguration = Mockito.mockStatic(Configuration.class)) { + Configuration mockedInstanceConfiguration = Mockito.mock(Configuration.class); + Builder mockedBuilder = Mockito.mock(Builder.class); + Tracer mockedTracer = Mockito.mock(JaegerTracer.class); + + mockedStaticConfiguration.when(() -> Configuration.fromEnv()).thenReturn(mockedInstanceConfiguration); + mockedStaticConfiguration.when(() -> mockedInstanceConfiguration.withMetricsFactory(Mockito.any())) + .thenReturn(mockedInstanceConfiguration); + mockedStaticConfiguration.when(() -> mockedInstanceConfiguration.getTracerBuilder()) + .thenReturn(mockedBuilder); + mockedStaticConfiguration.when(() -> mockedBuilder.withScopeManager(Mockito.any())) + .thenReturn(mockedBuilder); + mockedStaticConfiguration.when(() -> mockedBuilder.withReporter(Mockito.any())).thenReturn(mockedBuilder); + mockedStaticConfiguration.when(() -> mockedBuilder.build()).thenReturn(mockedTracer); + + QuarkusJaegerTracer tracer = new QuarkusJaegerTracer(); + tracer.toString(); + tracer.close(); + + ArgumentCaptor argument = ArgumentCaptor.forClass(Reporter.class); + Mockito.verify(mockedBuilder).withReporter(argument.capture()); + assertNull(argument.getValue()); + } + } + +} diff --git a/extensions/jaeger/runtime/pom.xml b/extensions/jaeger/runtime/pom.xml index f7a3c3b1a6375..4ebab85718a3f 100644 --- a/extensions/jaeger/runtime/pom.xml +++ b/extensions/jaeger/runtime/pom.xml @@ -32,6 +32,15 @@ + + io.quarkus + quarkus-arc + + + io.jaegertracing + jaeger-zipkin + true + jakarta.activation diff --git a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/JaegerDeploymentRecorder.java b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/JaegerDeploymentRecorder.java index 7140d386f2219..cb86e3fbc09d9 100644 --- a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/JaegerDeploymentRecorder.java +++ b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/JaegerDeploymentRecorder.java @@ -25,21 +25,25 @@ public void setJaegerVersion(String version) { } /* RUNTIME_INIT */ - public void registerTracerWithoutMetrics(JaegerConfig jaeger, ApplicationConfig appConfig) { - registerTracer(jaeger, appConfig, new NoopMetricsFactory()); + public void registerTracerWithoutMetrics(JaegerConfig jaeger, ApplicationConfig appConfig, + ZipkinConfig zipkinConfig) { + registerTracer(jaeger, appConfig, new NoopMetricsFactory(), zipkinConfig); } /* RUNTIME_INIT */ - public void registerTracerWithMpMetrics(JaegerConfig jaeger, ApplicationConfig appConfig) { - registerTracer(jaeger, appConfig, new QuarkusJaegerMpMetricsFactory()); + public void registerTracerWithMpMetrics(JaegerConfig jaeger, ApplicationConfig appConfig, + ZipkinConfig zipkinConfig) { + registerTracer(jaeger, appConfig, new QuarkusJaegerMpMetricsFactory(), zipkinConfig); } /* RUNTIME_INIT */ - public void registerTracerWithMicrometerMetrics(JaegerConfig jaeger, ApplicationConfig appConfig) { - registerTracer(jaeger, appConfig, new QuarkusJaegerMicrometerFactory()); + public void registerTracerWithMicrometerMetrics(JaegerConfig jaeger, ApplicationConfig appConfig, + ZipkinConfig zipkinConfig) { + registerTracer(jaeger, appConfig, new QuarkusJaegerMicrometerFactory(), zipkinConfig); } - private synchronized void registerTracer(JaegerConfig jaeger, ApplicationConfig appConfig, MetricsFactory metricsFactory) { + private synchronized void registerTracer(JaegerConfig jaeger, ApplicationConfig appConfig, + MetricsFactory metricsFactory, ZipkinConfig zipkinConfig) { if (!jaeger.serviceName.isPresent()) { if (appConfig.name.isPresent()) { jaeger.serviceName = appConfig.name; @@ -47,7 +51,7 @@ private synchronized void registerTracer(JaegerConfig jaeger, ApplicationConfig jaeger.serviceName = UNKNOWN_SERVICE_NAME; } } - initTracerConfig(jaeger); + initTracerConfig(jaeger, zipkinConfig); quarkusTracer.setMetricsFactory(metricsFactory); quarkusTracer.reset(); // register Quarkus tracer to GlobalTracer. @@ -60,8 +64,11 @@ private synchronized void registerTracer(JaegerConfig jaeger, ApplicationConfig } } - private void initTracerConfig(JaegerConfig jaeger) { + private void initTracerConfig(JaegerConfig jaeger, ZipkinConfig zipkinConfig) { initTracerProperty("JAEGER_ENDPOINT", jaeger.endpoint, uri -> uri.toString()); + if (jaeger.endpoint.isPresent()) { + quarkusTracer.setEndpoint(jaeger.endpoint.get().toString()); + } initTracerProperty("JAEGER_AUTH_TOKEN", jaeger.authToken, token -> token); initTracerProperty("JAEGER_USER", jaeger.user, user -> user); initTracerProperty("JAEGER_PASSWORD", jaeger.password, pw -> pw); @@ -79,6 +86,7 @@ private void initTracerConfig(JaegerConfig jaeger) { initTracerProperty("JAEGER_PROPAGATION", jaeger.propagation, format -> format.toString()); initTracerProperty("JAEGER_SENDER_FACTORY", jaeger.senderFactory, sender -> sender); quarkusTracer.setLogTraceContext(jaeger.logTraceContext); + quarkusTracer.setZipkinCompatibilityMode(zipkinConfig.compatibilityMode); } private void initTracerProperty(String property, Optional value, Function accessor) { @@ -92,4 +100,15 @@ private void initTracerProperty(String property, OptionalInt value, Function getClassForName(String className) { + Class clazz = null; + try { + clazz = Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException e) { + // Ignore exception + } + log.debugf("getClass: TCCL: %s ## %s : %s", Thread.currentThread().getContextClassLoader(), className, (clazz != null)); + return clazz; + } } diff --git a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/QuarkusJaegerTracer.java b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/QuarkusJaegerTracer.java index 49f64a7ee2b24..1e9ef522778e0 100644 --- a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/QuarkusJaegerTracer.java +++ b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/QuarkusJaegerTracer.java @@ -1,8 +1,15 @@ package io.quarkus.jaeger.runtime; +import javax.enterprise.inject.Default; +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.spi.CDI; + +import org.jboss.logging.Logger; + import io.jaegertracing.Configuration; import io.jaegertracing.internal.JaegerTracer; import io.jaegertracing.spi.MetricsFactory; +import io.jaegertracing.spi.Reporter; import io.opentracing.Scope; import io.opentracing.ScopeManager; import io.opentracing.Span; @@ -17,6 +24,10 @@ public class QuarkusJaegerTracer implements Tracer { private boolean logTraceContext; private MetricsFactory metricsFactory; + private boolean zipkinCompatibilityMode = false; + private String endpoint = null; + + private static final Logger log = Logger.getLogger(QuarkusJaegerTracer.class); private final ScopeManager scopeManager = new ScopeManager() { @@ -75,6 +86,7 @@ private Tracer tracer() { .withMetricsFactory(metricsFactory) .getTracerBuilder() .withScopeManager(scopeManager) + .withReporter(createReporter()) .build(); } } @@ -82,6 +94,25 @@ private Tracer tracer() { return tracer; } + private Reporter createReporter() { + Reporter reporter = null; + if (zipkinCompatibilityMode) { + Instance registries = CDI.current().select(ReporterFactory.class, + Default.Literal.INSTANCE); + ReporterFactory factory = null; + if (registries.isAmbiguous()) { + factory = registries.iterator().next(); + log.warnf("Multiple reporters present, using %s", factory.getClass().getName()); + } else if (!registries.isUnsatisfied()) { + factory = registries.get(); + } + if (factory != null) { + reporter = factory.createReporter(endpoint); + } + } + return reporter; + } + private ScopeManager getScopeManager() { ScopeManager scopeManager = new ThreadLocalScopeManager(); if (logTraceContext) { @@ -124,4 +155,12 @@ public Span activeSpan() { public Scope activateSpan(final Span span) { return tracer.activateSpan(span); } + + public void setZipkinCompatibilityMode(boolean zipkinCompatibilityMode) { + this.zipkinCompatibilityMode = zipkinCompatibilityMode; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } } diff --git a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ReporterFactory.java b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ReporterFactory.java new file mode 100644 index 0000000000000..d061a6f69b26a --- /dev/null +++ b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ReporterFactory.java @@ -0,0 +1,9 @@ +package io.quarkus.jaeger.runtime; + +import io.jaegertracing.spi.Reporter; + +public interface ReporterFactory { + + Reporter createReporter(String endpoint); + +} diff --git a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinConfig.java b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinConfig.java new file mode 100644 index 0000000000000..5a1f2039ecfc6 --- /dev/null +++ b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinConfig.java @@ -0,0 +1,18 @@ +package io.quarkus.jaeger.runtime; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +/** + * The Zipkin Jaeger configuration. + */ +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED, name = "jaeger.zipkin") +public class ZipkinConfig { + + /** + * Whether jaeger should run in zipkin compatibility mode + */ + @ConfigItem(defaultValue = "false") + public Boolean compatibilityMode; +} diff --git a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterFactoryImpl.java b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterFactoryImpl.java new file mode 100644 index 0000000000000..dbc5d3ba58151 --- /dev/null +++ b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterFactoryImpl.java @@ -0,0 +1,16 @@ +package io.quarkus.jaeger.runtime; + +import io.jaegertracing.spi.Reporter; +import io.jaegertracing.zipkin.ZipkinV2Reporter; +import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.urlconnection.URLConnectionSender; + +public class ZipkinReporterFactoryImpl implements ReporterFactory { + + public Reporter createReporter(String endpoint) { + + return new ZipkinV2Reporter(AsyncReporter.create(URLConnectionSender.create(endpoint))); + + } + +} diff --git a/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterProvider.java b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterProvider.java new file mode 100644 index 0000000000000..5f94d47fa4e33 --- /dev/null +++ b/extensions/jaeger/runtime/src/main/java/io/quarkus/jaeger/runtime/ZipkinReporterProvider.java @@ -0,0 +1,13 @@ +package io.quarkus.jaeger.runtime; + +import javax.enterprise.inject.Produces; +import javax.inject.Singleton; + +@Singleton +public class ZipkinReporterProvider { + @Produces + @Singleton + public ReporterFactory reporter() { + return new ZipkinReporterFactoryImpl(); + } +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 086e7db5e0aa6..e4d6324b4b29b 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -142,6 +142,7 @@ smallrye-metrics smallrye-graphql smallrye-graphql-client + smallrye-opentracing jpa-without-entity quartz redis-client @@ -328,4 +329,3 @@ - diff --git a/integration-tests/smallrye-opentracing/pom.xml b/integration-tests/smallrye-opentracing/pom.xml new file mode 100644 index 0000000000000..d7d6aec813b56 --- /dev/null +++ b/integration-tests/smallrye-opentracing/pom.xml @@ -0,0 +1,139 @@ + + + + quarkus-integration-tests-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + quarkus-integration-test-smallrye-opentracing + Quarkus - Integration Tests - Smallrye Opentracing + + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-smallrye-opentracing + + + + + io.quarkus + quarkus-rest-client + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + com.github.tomakehurst + wiremock-jre8 + test + + + + + io.quarkus + quarkus-rest-client-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-resteasy-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-smallrye-opentracing-deployment + ${project.version} + pom + test + + + * + * + + + + + io.jaegertracing + jaeger-zipkin + + + + + + + + src/main/resources + true + + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + + native-image + + + native + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + diff --git a/integration-tests/smallrye-opentracing/src/main/java/io/quarkus/it/rest/client/server/EchoService.java b/integration-tests/smallrye-opentracing/src/main/java/io/quarkus/it/rest/client/server/EchoService.java new file mode 100644 index 0000000000000..3818ccc09b75a --- /dev/null +++ b/integration-tests/smallrye-opentracing/src/main/java/io/quarkus/it/rest/client/server/EchoService.java @@ -0,0 +1,16 @@ +package io.quarkus.it.rest.client.server; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/echo") +public class EchoService { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String echo() { + return "result"; + } +} \ No newline at end of file diff --git a/integration-tests/smallrye-opentracing/src/main/resources/application.properties b/integration-tests/smallrye-opentracing/src/main/resources/application.properties new file mode 100644 index 0000000000000..cdb302678cee7 --- /dev/null +++ b/integration-tests/smallrye-opentracing/src/main/resources/application.properties @@ -0,0 +1,5 @@ +quarkus.jaeger.service-name=encryptions +quarkus.jaeger.sampler-type=const +quarkus.jaeger.sampler-param=1 +quarkus.jaeger.propagation=b3 +quarkus.jaeger.zipkin.compatibility-mode=true \ No newline at end of file diff --git a/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/WireMockZipkin.java b/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/WireMockZipkin.java new file mode 100644 index 0000000000000..02b977c380a21 --- /dev/null +++ b/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/WireMockZipkin.java @@ -0,0 +1,39 @@ +package io.quarkus.it.rest.client; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; + +import java.util.Collections; +import java.util.Map; + +import com.github.tomakehurst.wiremock.WireMockServer; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; + +public class WireMockZipkin implements QuarkusTestResourceLifecycleManager { + + private static WireMockServer wireMockServer; + + @Override + public Map start() { + wireMockServer = new WireMockServer(); + wireMockServer.start(); + + stubFor(post(anyUrl()).withRequestBody(equalToJson( + "[{\"name\": \"get:io.quarkus.it.rest.client.server.echoservice.echo\",\"tags\": {\"component\": \"jaxrs\",\"http.method\": \"GET\",\"http.status_code\": \"200\",\"sampler.param\": \"true\",\"sampler.type\": \"const\"}}]", + true, true)).willReturn(aResponse().withStatus(200))); + + return Collections.singletonMap("quarkus.jaeger.endpoint", wireMockServer.baseUrl() + "/zipkin"); + } + + @Override + public void stop() { + if (null != wireMockServer) { + wireMockServer.stop(); + } + } + + public static WireMockServer getWireMockServer() { + return wireMockServer; + } + +} diff --git a/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTest.java b/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTest.java new file mode 100644 index 0000000000000..5e9381baeeeb5 --- /dev/null +++ b/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTest.java @@ -0,0 +1,46 @@ +package io.quarkus.it.rest.client; + +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Date; + +import org.junit.jupiter.api.Test; + +import com.github.tomakehurst.wiremock.client.VerificationException; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +@QuarkusTestResource(WireMockZipkin.class) +public class ZipkinIntegrationTest { + + @Test + public void testZipkinIntegration() { + + given().when().get("/echo").then().statusCode(200).body(containsString("result")); + + boolean continues = true; + long current = new Date().getTime(); + while (continues) { + try { + verify(postRequestedFor(urlEqualTo("/zipkin"))); + continues = false; + } catch (VerificationException e) { + // Because the request to zipkin is asynchronous we should wait maximum 10 + // seconds. + if (new Date().getTime() - current > 10000) { + throw e; + } + } + } + + assertEquals(0, WireMockZipkin.getWireMockServer().findAllUnmatchedRequests().size()); + } + +} diff --git a/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTestIT.java b/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTestIT.java new file mode 100644 index 0000000000000..cd89e385e6350 --- /dev/null +++ b/integration-tests/smallrye-opentracing/src/test/java/io/quarkus/it/rest/client/ZipkinIntegrationTestIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.rest.client; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class ZipkinIntegrationTestIT extends ZipkinIntegrationTest { +}