From 8da799067b58173bbfbb423ff6fcd23952f50370 Mon Sep 17 00:00:00 2001 From: Guillaume Lamirand Date: Fri, 11 Oct 2024 17:27:01 +0200 Subject: [PATCH] feat: add OpenTelemetry feature into Gravitee Node BREAKING CHANGE: Tracing plugin has been removed and is now embedded inside node framework --- gravitee-node-api/pom.xml | 19 +- .../api/opentelemetry/InstrumenterTracer.java | 32 ++ .../InstrumenterTracerFactory.java} | 17 +- .../gravitee/node/api/opentelemetry/Span.java | 18 +- .../node/api/opentelemetry/Tracer.java | 43 ++ .../node/api/opentelemetry/TracerFactory.java | 32 ++ .../http/ObservableHttpClientRequest.java | 106 ++++ .../http/ObservableHttpClientResponse.java | 36 ++ .../http/ObservableHttpRequest.java | 14 +- .../http/ObservableHttpResponse.java | 25 + .../http/ObservableHttpServerRequest.java | 61 +++ .../http/ObservableHttpServerResponse.java | 26 + .../internal/InternalRequest.java | 15 + .../gravitee-node-cache-common/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../gravitee-node-cache-plugin-redis/pom.xml | 2 +- .../pom.xml | 2 +- gravitee-node-cache/pom.xml | 2 +- gravitee-node-certificates/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- gravitee-node-cluster/pom.xml | 2 +- gravitee-node-container/pom.xml | 7 +- .../spring/SpringBasedContainer.java | 2 + gravitee-node-jetty/pom.xml | 2 +- gravitee-node-kubernetes/pom.xml | 2 +- gravitee-node-license/pom.xml | 6 +- gravitee-node-management/pom.xml | 2 +- gravitee-node-monitoring/pom.xml | 2 +- gravitee-node-notifier/pom.xml | 2 +- gravitee-node-opentelemetry/pom.xml | 129 +++++ .../opentelemetry/OpenTelemetryFactory.java | 121 +++++ .../configuration/CompressionType.java | 44 ++ .../OpenTelemetryConfiguration.java | 225 ++++++++ .../opentelemetry/configuration/Protocol.java | 51 ++ .../exporter/ExporterFactory.java | 242 +++++++++ .../exporter/OTelExporterUtil.java | 29 + .../exporter/sender/BufferOutputStream.java | 27 + .../exporter/sender/VertxGrpcSender.java | 505 ++++++++++++++++++ .../exporter/sender/VertxHttpSender.java | 360 +++++++++++++ .../tracing/VertxGrpcSpanExporter.java | 36 ++ .../tracing/VertxHttpSpanExporter.java | 36 ++ .../OpenTelemetrySpringConfiguration.java | 65 +++ .../tracer/OpenTelemetryTracer.java | 164 ++++++ .../AbstractInstrumenterTracer.java | 89 +++ .../internal/InternalInstrumenterTracer.java | 58 ++ .../InternalInstrumenterTracerFactory.java | 24 + .../InternalAttributesExtractor.java | 36 ++ .../extractor/InternalSpanNameExtractor.java | 16 + .../vertx/VertxHttpInstrumenterTracer.java | 148 +++++ .../VertxHttpInstrumenterTracerFactory.java | 23 + .../instrumentation/vertx/VertxUtil.java | 93 ++++ .../AdditionalServerAttributesExtractor.java | 61 +++ .../extractor/ClientSpanNameExtractor.java | 30 ++ .../HttpClientAttributesExtractor.java | 80 +++ .../extractor/HttpRequestTextMapGetter.java | 33 ++ .../extractor/HttpRequestTextMapSetter.java | 17 + .../vertx/extractor/RouteGetter.java | 40 ++ .../extractor/ServerAttributesExtractor.java | 101 ++++ .../opentelemetry/tracer/noop}/NoOpSpan.java | 37 +- .../opentelemetry/tracer/noop/NoOpTracer.java | 61 +++ .../tracer/span/OpenTelemetrySpan.java | 84 +++ .../tracer/vertx/VertxContextStorage.java | 110 ++++ ...entelemetry.context.ContextStorageProvider | 1 + .../OpenTelemetryTracerIntegrationTest.java | 426 +++++++++++++++ .../testcontainers/JaegerAllInOne.java | 57 ++ .../src/test/resources/logback-test.xml | 14 + .../src/test/resources/ssl/ca.key | 54 ++ .../src/test/resources/ssl/ca.pem | 35 ++ .../test/resources/ssl/client-keystore.jks | Bin 0 -> 3907 bytes .../test/resources/ssl/client-keystore.p12 | Bin 0 -> 4398 bytes .../test/resources/ssl/client-truststore.jks | Bin 0 -> 3102 bytes .../test/resources/ssl/client-truststore.p12 | Bin 0 -> 3494 bytes .../test/resources/ssl/client-truststore.pem | 78 +++ .../src/test/resources/ssl/client.cer | 31 ++ .../src/test/resources/ssl/client.csr | 26 + .../src/test/resources/ssl/client.key | 52 ++ .../resources/ssl/generate-certificates.sh | 83 +++ .../src/test/resources/ssl/server.jaeger.crt | 33 ++ .../src/test/resources/ssl/server.jaeger.csr | 26 + .../src/test/resources/ssl/server.jaeger.key | 52 ++ .../gravitee-node-plugins-service/pom.xml | 2 +- gravitee-node-plugins/pom.xml | 2 +- gravitee-node-reporter/pom.xml | 2 +- .../pom.xml | 2 +- .../gravitee-node-secrets-service/pom.xml | 2 +- gravitee-node-secrets/pom.xml | 2 +- .../pom.xml | 2 +- .../gravitee-node-services-upgrader/pom.xml | 2 +- gravitee-node-services/pom.xml | 2 +- gravitee-node-tracing/pom.xml | 74 --- .../io/gravitee/node/tracing/LazyTracer.java | 42 -- .../gravitee/node/tracing/TracingService.java | 88 --- .../tracing/plugin/TracingPluginHandler.java | 62 --- .../tracing/spring/TracingConfiguration.java | 47 -- .../node/tracing/vertx/LazyVertxTracer.java | 97 ---- .../tracing/vertx/LazyVertxTracerFactory.java | 58 -- .../main/resources/META-INF/spring.factories | 2 - gravitee-node-vertx/pom.xml | 6 +- .../io/gravitee/node/vertx/VertxFactory.java | 34 +- .../node/vertx/spring/VertxConfiguration.java | 3 - .../gravitee/node/vertx/VertxFactoryTest.java | 2 - pom.xml | 85 ++- 105 files changed, 4653 insertions(+), 599 deletions(-) create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracer.java rename gravitee-node-api/src/main/java/io/gravitee/node/api/{tracing/Tracer.java => opentelemetry/InstrumenterTracerFactory.java} (57%) rename gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracerPlugin.java => gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Span.java (61%) create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Tracer.java create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/TracerFactory.java create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientRequest.java create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientResponse.java rename gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/VertxTracer.java => gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpRequest.java (60%) create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpResponse.java create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerRequest.java create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerResponse.java create mode 100644 gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/internal/InternalRequest.java create mode 100644 gravitee-node-opentelemetry/pom.xml create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/OpenTelemetryFactory.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/CompressionType.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/OpenTelemetryConfiguration.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/Protocol.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/ExporterFactory.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/OTelExporterUtil.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/BufferOutputStream.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxGrpcSender.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxHttpSender.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxGrpcSpanExporter.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxHttpSpanExporter.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/spring/OpenTelemetrySpringConfiguration.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/OpenTelemetryTracer.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/AbstractInstrumenterTracer.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracer.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracerFactory.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalAttributesExtractor.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalSpanNameExtractor.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracer.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracerFactory.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxUtil.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/AdditionalServerAttributesExtractor.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ClientSpanNameExtractor.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpClientAttributesExtractor.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapGetter.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapSetter.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/RouteGetter.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ServerAttributesExtractor.java rename {gravitee-node-tracing/src/main/java/io/gravitee/node/tracing => gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop}/NoOpSpan.java (53%) create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpTracer.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/span/OpenTelemetrySpan.java create mode 100644 gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/vertx/VertxContextStorage.java create mode 100644 gravitee-node-opentelemetry/src/main/resources/META-INF/io.opentelemetry.context.ContextStorageProvider create mode 100644 gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/OpenTelemetryTracerIntegrationTest.java create mode 100644 gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/testcontainers/JaegerAllInOne.java create mode 100644 gravitee-node-opentelemetry/src/test/resources/logback-test.xml create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/ca.key create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/ca.pem create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client-keystore.jks create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client-keystore.p12 create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.jks create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.p12 create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.pem create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client.cer create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client.csr create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/client.key create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/generate-certificates.sh create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.crt create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.csr create mode 100755 gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.key delete mode 100644 gravitee-node-tracing/pom.xml delete mode 100644 gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/LazyTracer.java delete mode 100644 gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/TracingService.java delete mode 100644 gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracingPluginHandler.java delete mode 100644 gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/spring/TracingConfiguration.java delete mode 100644 gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracer.java delete mode 100644 gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracerFactory.java delete mode 100644 gravitee-node-tracing/src/main/resources/META-INF/spring.factories diff --git a/gravitee-node-api/pom.xml b/gravitee-node-api/pom.xml index 0a6e2299d..e941b4f87 100644 --- a/gravitee-node-api/pom.xml +++ b/gravitee-node-api/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-api @@ -48,11 +48,6 @@ gravitee-reporter-api - - io.gravitee.tracing - gravitee-tracing-api - - io.reactivex.rxjava3 @@ -63,5 +58,17 @@ com.google.guava guava + + + + io.vertx + vertx-core + + + + + io.opentelemetry + opentelemetry-api + diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracer.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracer.java new file mode 100644 index 000000000..6c1a840dd --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracer.java @@ -0,0 +1,32 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry; + +import io.vertx.core.Context; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public interface InstrumenterTracer { + String instrumentationName(); + + boolean canHandle(final R request); + + Span startSpan(final Context vertxContext, final R request, final boolean root, final Span parentSpan); + + void endSpan(final Context vertxContext, final Span span, final R response, final Throwable throwable); +} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/tracing/Tracer.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracerFactory.java similarity index 57% rename from gravitee-node-api/src/main/java/io/gravitee/node/api/tracing/Tracer.java rename to gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracerFactory.java index eb2526c0e..81f2a9891 100644 --- a/gravitee-node-api/src/main/java/io/gravitee/node/api/tracing/Tracer.java +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/InstrumenterTracerFactory.java @@ -1,11 +1,11 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.gravitee.node.api.tracing; +package io.gravitee.node.api.opentelemetry; -import io.gravitee.common.component.LifecycleComponent; -import io.gravitee.tracing.api.Span; +import io.opentelemetry.api.OpenTelemetry; /** - * @author David BRASSELY (david.brassely at graviteesource.com) + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) * @author GraviteeSource Team */ -public interface Tracer extends LifecycleComponent { - Span trace(String spanName); +public interface InstrumenterTracerFactory { + InstrumenterTracer createInstrumenterTracer(final OpenTelemetry openTelemetry); } diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracerPlugin.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Span.java similarity index 61% rename from gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracerPlugin.java rename to gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Span.java index 351663692..254dcf437 100644 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracerPlugin.java +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Span.java @@ -1,11 +1,11 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.gravitee.node.tracing.plugin; - -import io.gravitee.plugin.core.api.Plugin; +package io.gravitee.node.api.opentelemetry; /** - * @author David BRASSELY (david.brassely at graviteesource.com) + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) * @author GraviteeSource Team */ -public interface TracerPlugin extends Plugin { - String PLUGIN_TYPE = "tracer"; +public interface Span { + boolean isRoot(); + + Span withAttribute(final String name, final T value); } diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Tracer.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Tracer.java new file mode 100644 index 000000000..92ce47063 --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/Tracer.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry; + +import io.gravitee.common.service.Service; +import io.vertx.core.Context; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public interface Tracer extends Service { + Span startRootSpanFrom(final Context vertxContext, final R request); + + Span startSpanFrom(final Context vertxContext, final R request); + + Span startSpanWithParentFrom(Context vertxContext, Span parentSpan, R request); + + void end(final Context vertxContext, final Span span); + + void endOnError(final Context vertxContext, final Span span, final Throwable throwable); + + void endOnError(final Context vertxContext, final Span span, final String message); + + void endWithResponse(final Context vertxContext, final Span span, final R response); + + void endWithResponseAndError(final Context vertxContext, final Span span, final R response, final Throwable throwable); + + void endWithResponseAndError(final Context vertxContext, final Span span, final R response, final String message); +} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/TracerFactory.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/TracerFactory.java new file mode 100644 index 000000000..4e2989757 --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/TracerFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry; + +import java.util.List; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public interface TracerFactory { + Tracer createTracer( + final String id, + final String serviceName, + final String serviceNamespace, + final String version, + final List instrumenterTracerFactories + ); +} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientRequest.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientRequest.java new file mode 100644 index 000000000..d5d3358fe --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientRequest.java @@ -0,0 +1,106 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry.http; + +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.RequestOptions; +import io.vertx.core.http.impl.HttpRequestHead; +import io.vertx.core.http.impl.headers.HeadersMultiMap; +import io.vertx.core.net.SocketAddress; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@RequiredArgsConstructor +@Getter +@Setter +@Accessors(fluent = true) +public class ObservableHttpClientRequest implements ObservableHttpRequest { + + @NonNull + private final RequestOptions requestOptions; + + private HttpClientRequest httpClientRequest; + + /** + * Only used for internal Vertx testing; see {@link HttpRequestHead#id() } + */ + @Override + public int id() { + return 0; + } + + @Override + public String uri() { + return requestOptions.getURI(); + } + + @Override + public String absoluteURI() { + return ( + (Boolean.TRUE.equals(requestOptions.isSsl()) ? "https://" : "http://") + + requestOptions.getHost() + + ':' + + requestOptions.getPort() + + requestOptions.getURI() + ); + } + + @Override + public HttpMethod method() { + return requestOptions.getMethod(); + } + + @Override + public MultiMap headers() { + MultiMap headers = null; + if (httpClientRequest != null) { + headers = httpClientRequest.headers(); + } + if (headers == null) { + headers = requestOptions.getHeaders(); + } + if (headers == null) { + return HeadersMultiMap.headers(); + } + return headers; + } + + @Override + public SocketAddress remoteAddress() { + return requestOptions.getServer(); + } + + public String traceOperation() { + String traceOperation = null; + if (httpClientRequest != null) { + traceOperation = httpClientRequest.traceOperation(); + } + if (traceOperation == null) { + traceOperation = requestOptions.getTraceOperation(); + } + return traceOperation; + } +} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientResponse.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientResponse.java new file mode 100644 index 000000000..78b8c5742 --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpClientResponse.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry.http; + +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpClientResponse; +import io.vertx.core.spi.observability.HttpResponse; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public record ObservableHttpClientResponse(HttpClientResponse httpClientResponse) implements ObservableHttpResponse { + @Override + public int statusCode() { + return httpClientResponse.statusCode(); + } + + @Override + public MultiMap headers() { + return httpClientResponse.headers(); + } +} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/VertxTracer.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpRequest.java similarity index 60% rename from gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/VertxTracer.java rename to gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpRequest.java index 79090f9d6..b7075d99f 100644 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/VertxTracer.java +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpRequest.java @@ -1,11 +1,11 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.gravitee.node.tracing.vertx; +package io.gravitee.node.api.opentelemetry.http; -import io.gravitee.node.api.tracing.Tracer; +import io.vertx.core.spi.observability.HttpRequest; /** - * @author David BRASSELY (david.brassely at graviteesource.com) + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) * @author GraviteeSource Team */ -public interface VertxTracer extends Tracer, io.vertx.core.spi.tracing.VertxTracer {} +public interface ObservableHttpRequest extends HttpRequest {} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpResponse.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpResponse.java new file mode 100644 index 000000000..6d7892114 --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpResponse.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry.http; + +import io.vertx.core.spi.observability.HttpRequest; +import io.vertx.core.spi.observability.HttpResponse; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public interface ObservableHttpResponse extends HttpResponse {} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerRequest.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerRequest.java new file mode 100644 index 000000000..ae18abb9a --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.api.opentelemetry.http; + +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.impl.HttpRequestHead; +import io.vertx.core.net.SocketAddress; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public record ObservableHttpServerRequest(HttpServerRequest httpServerRequest) implements ObservableHttpRequest { + /** + * Only used for internal Vertx testing; see {@link HttpRequestHead#id() } + */ + @Override + public int id() { + return 0; + } + + @Override + public String uri() { + return httpServerRequest.uri(); + } + + @Override + public String absoluteURI() { + return httpServerRequest.absoluteURI(); + } + + @Override + public HttpMethod method() { + return httpServerRequest.method(); + } + + @Override + public MultiMap headers() { + return httpServerRequest.headers(); + } + + @Override + public SocketAddress remoteAddress() { + return httpServerRequest.remoteAddress(); + } +} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerResponse.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerResponse.java new file mode 100644 index 000000000..07b62a607 --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/http/ObservableHttpServerResponse.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.api.opentelemetry.http; + +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.spi.observability.HttpResponse; +import lombok.RequiredArgsConstructor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public record ObservableHttpServerResponse(HttpServerResponse httpServerResponse) implements ObservableHttpResponse { + @Override + public int statusCode() { + return httpServerResponse.getStatusCode(); + } + + @Override + public MultiMap headers() { + return httpServerResponse.headers(); + } +} diff --git a/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/internal/InternalRequest.java b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/internal/InternalRequest.java new file mode 100644 index 000000000..6c0bec3e7 --- /dev/null +++ b/gravitee-node-api/src/main/java/io/gravitee/node/api/opentelemetry/internal/InternalRequest.java @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.api.opentelemetry.internal; + +import java.util.Map; +import lombok.Builder; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@Builder +public record InternalRequest(String name, Map attributes) {} diff --git a/gravitee-node-cache/gravitee-node-cache-common/pom.xml b/gravitee-node-cache/gravitee-node-cache-common/pom.xml index 260dbeca7..61516bdfc 100644 --- a/gravitee-node-cache/gravitee-node-cache-common/pom.xml +++ b/gravitee-node-cache/gravitee-node-cache-common/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cache - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cache-common diff --git a/gravitee-node-cache/gravitee-node-cache-plugin-handler/pom.xml b/gravitee-node-cache/gravitee-node-cache-plugin-handler/pom.xml index af91aa2bf..290683524 100644 --- a/gravitee-node-cache/gravitee-node-cache-plugin-handler/pom.xml +++ b/gravitee-node-cache/gravitee-node-cache-plugin-handler/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cache - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cache-plugin-handler diff --git a/gravitee-node-cache/gravitee-node-cache-plugin-hazelcast/pom.xml b/gravitee-node-cache/gravitee-node-cache-plugin-hazelcast/pom.xml index 9fd5873df..ceb7e96cd 100644 --- a/gravitee-node-cache/gravitee-node-cache-plugin-hazelcast/pom.xml +++ b/gravitee-node-cache/gravitee-node-cache-plugin-hazelcast/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cache - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cache-plugin-hazelcast diff --git a/gravitee-node-cache/gravitee-node-cache-plugin-redis/pom.xml b/gravitee-node-cache/gravitee-node-cache-plugin-redis/pom.xml index e701f7108..4027ec0fb 100644 --- a/gravitee-node-cache/gravitee-node-cache-plugin-redis/pom.xml +++ b/gravitee-node-cache/gravitee-node-cache-plugin-redis/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cache - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cache-plugin-redis diff --git a/gravitee-node-cache/gravitee-node-cache-plugin-standalone/pom.xml b/gravitee-node-cache/gravitee-node-cache-plugin-standalone/pom.xml index 6ebb8bc33..c8c80b201 100644 --- a/gravitee-node-cache/gravitee-node-cache-plugin-standalone/pom.xml +++ b/gravitee-node-cache/gravitee-node-cache-plugin-standalone/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cache - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cache-plugin-standalone diff --git a/gravitee-node-cache/pom.xml b/gravitee-node-cache/pom.xml index 9b5e5cdb4..f1287070a 100644 --- a/gravitee-node-cache/pom.xml +++ b/gravitee-node-cache/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cache diff --git a/gravitee-node-certificates/pom.xml b/gravitee-node-certificates/pom.xml index c760a47be..27670ae05 100644 --- a/gravitee-node-certificates/pom.xml +++ b/gravitee-node-certificates/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-certificates diff --git a/gravitee-node-cluster/gravitee-node-cluster-plugin-handler/pom.xml b/gravitee-node-cluster/gravitee-node-cluster-plugin-handler/pom.xml index 59d86edc1..0b65443e9 100644 --- a/gravitee-node-cluster/gravitee-node-cluster-plugin-handler/pom.xml +++ b/gravitee-node-cluster/gravitee-node-cluster-plugin-handler/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cluster - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cluster-plugin-handler diff --git a/gravitee-node-cluster/gravitee-node-cluster-plugin-hazelcast/pom.xml b/gravitee-node-cluster/gravitee-node-cluster-plugin-hazelcast/pom.xml index 1ba32c453..7b5dde4da 100644 --- a/gravitee-node-cluster/gravitee-node-cluster-plugin-hazelcast/pom.xml +++ b/gravitee-node-cluster/gravitee-node-cluster-plugin-hazelcast/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cluster - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cluster-plugin-hazelcast diff --git a/gravitee-node-cluster/gravitee-node-cluster-plugin-standalone/pom.xml b/gravitee-node-cluster/gravitee-node-cluster-plugin-standalone/pom.xml index 302b7ca01..cdc38898a 100644 --- a/gravitee-node-cluster/gravitee-node-cluster-plugin-standalone/pom.xml +++ b/gravitee-node-cluster/gravitee-node-cluster-plugin-standalone/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-cluster - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cluster-plugin-standalone diff --git a/gravitee-node-cluster/pom.xml b/gravitee-node-cluster/pom.xml index 6ef96b8de..3eee3b4c1 100644 --- a/gravitee-node-cluster/pom.xml +++ b/gravitee-node-cluster/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-cluster diff --git a/gravitee-node-container/pom.xml b/gravitee-node-container/pom.xml index 0cd192098..a8972c2c4 100644 --- a/gravitee-node-container/pom.xml +++ b/gravitee-node-container/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-container @@ -81,6 +81,11 @@ gravitee-node-license + + io.gravitee.node + gravitee-node-opentelemetry + + io.gravitee.common gravitee-common diff --git a/gravitee-node-container/src/main/java/io/gravitee/node/container/spring/SpringBasedContainer.java b/gravitee-node-container/src/main/java/io/gravitee/node/container/spring/SpringBasedContainer.java index 46eba8507..7e5633fbb 100644 --- a/gravitee-node-container/src/main/java/io/gravitee/node/container/spring/SpringBasedContainer.java +++ b/gravitee-node-container/src/main/java/io/gravitee/node/container/spring/SpringBasedContainer.java @@ -26,6 +26,7 @@ import io.gravitee.node.license.LicenseLoaderService; import io.gravitee.node.management.http.spring.ManagementConfiguration; import io.gravitee.node.monitoring.spring.NodeMonitoringConfiguration; +import io.gravitee.node.opentelemetry.spring.OpenTelemetrySpringConfiguration; import io.gravitee.node.secrets.service.spring.SecretServiceConfiguration; import io.gravitee.node.vertx.spring.VertxConfiguration; import io.gravitee.plugin.core.internal.BootPluginEventListener; @@ -157,6 +158,7 @@ protected List>> bootstrapComponents() { protected List> annotatedClasses() { List> classes = new ArrayList<>(); classes.add(VertxConfiguration.class); + classes.add(OpenTelemetrySpringConfiguration.class); classes.add(PluginConfiguration.class); classes.add(ManagementConfiguration.class); classes.add(NodeMonitoringConfiguration.class); diff --git a/gravitee-node-jetty/pom.xml b/gravitee-node-jetty/pom.xml index 2727e6856..6f838daf2 100644 --- a/gravitee-node-jetty/pom.xml +++ b/gravitee-node-jetty/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-jetty diff --git a/gravitee-node-kubernetes/pom.xml b/gravitee-node-kubernetes/pom.xml index c82d665a5..4dfc1802b 100644 --- a/gravitee-node-kubernetes/pom.xml +++ b/gravitee-node-kubernetes/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-kubernetes diff --git a/gravitee-node-license/pom.xml b/gravitee-node-license/pom.xml index c97f4760e..013412400 100644 --- a/gravitee-node-license/pom.xml +++ b/gravitee-node-license/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-license @@ -44,6 +44,10 @@ io.gravitee.node gravitee-node-management + + io.gravitee.plugin + gravitee-plugin-core + diff --git a/gravitee-node-management/pom.xml b/gravitee-node-management/pom.xml index 0ce2d4425..a5d5f6bb9 100644 --- a/gravitee-node-management/pom.xml +++ b/gravitee-node-management/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-management diff --git a/gravitee-node-monitoring/pom.xml b/gravitee-node-monitoring/pom.xml index c0f0b1b51..fc055b3b7 100644 --- a/gravitee-node-monitoring/pom.xml +++ b/gravitee-node-monitoring/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-monitoring diff --git a/gravitee-node-notifier/pom.xml b/gravitee-node-notifier/pom.xml index 9c0f12755..e535fbb70 100644 --- a/gravitee-node-notifier/pom.xml +++ b/gravitee-node-notifier/pom.xml @@ -22,7 +22,7 @@ gravitee-node io.gravitee.node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT 4.0.0 diff --git a/gravitee-node-opentelemetry/pom.xml b/gravitee-node-opentelemetry/pom.xml new file mode 100644 index 000000000..61c748f31 --- /dev/null +++ b/gravitee-node-opentelemetry/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + + io.gravitee.node + gravitee-node + 7.0.0-archi-401-opentelemetry-SNAPSHOT + + + gravitee-node-opentelemetry + Gravitee.io - Node - OpenTelemetry + + + + + io.gravitee.node + gravitee-node-api + ${project.version} + + + + io.vertx + vertx-core + + + io.vertx + vertx-grpc-client + + + io.smallrye.reactive + mutiny + + + io.smallrye.common + smallrye-common-vertx-context + + + + + org.springframework + spring-core + provided + + + org.springframework + spring-context + provided + + + + + io.opentelemetry + opentelemetry-sdk + + + io.opentelemetry.semconv + opentelemetry-semconv + + + io.opentelemetry + opentelemetry-exporter-otlp-common + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-api + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-api-semconv + + + + + ch.qos.logback + logback-classic + test + + + org.awaitility + awaitility + test + + + org.testcontainers + testcontainers + test + + + org.testcontainers + junit-jupiter + test + + + io.vertx + vertx-web-client + test + + + io.vertx + vertx-junit5 + test + + + org.springframework + spring-test + test + + + diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/OpenTelemetryFactory.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/OpenTelemetryFactory.java new file mode 100644 index 000000000..b575e634d --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/OpenTelemetryFactory.java @@ -0,0 +1,121 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry; + +import io.gravitee.node.api.opentelemetry.InstrumenterTracerFactory; +import io.gravitee.node.api.opentelemetry.Tracer; +import io.gravitee.node.api.opentelemetry.TracerFactory; +import io.gravitee.node.opentelemetry.configuration.OpenTelemetryConfiguration; +import io.gravitee.node.opentelemetry.exporter.ExporterFactory; +import io.gravitee.node.opentelemetry.tracer.OpenTelemetryTracer; +import io.gravitee.node.opentelemetry.tracer.noop.NoOpTracer; +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.OpenTelemetrySdkBuilder; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.semconv.ResourceAttributes; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@Slf4j +@RequiredArgsConstructor +public class OpenTelemetryFactory implements TracerFactory { + + private static final String DEFAULT_HOST_NAME = "unknown"; + private static final String DEFAULT_IP = "0.0.0.0"; + private static final AttributeKey ATTRIBUTE_KEY_HOSTNAME = AttributeKey.stringKey("hostname"); + private static final AttributeKey ATTRIBUTE_KEY_IP = AttributeKey.stringKey("ip"); + private static final AttributeKey ATTRIBUTE_KEY_SERVICE_NAMESPACE = AttributeKey.stringKey("service.namespace"); + + private final OpenTelemetryConfiguration configuration; + private final ExporterFactory exporterFactory; + + @Override + public Tracer createTracer( + final String serviceInstanceId, + final String serviceName, + final String serviceNamespace, + final String serviceVersion, + final List instrumenterTracerFactories + ) { + if (configuration.isTracesEnabled()) { + final Resource resource = createResource(serviceInstanceId, serviceName, serviceNamespace, serviceVersion); + + final OpenTelemetrySdkBuilder builder = OpenTelemetrySdk + .builder() + .setPropagators( + ContextPropagators.create( + TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()) + ) + ); + + SdkTracerProvider tracerProvider = SdkTracerProvider + .builder() + .addSpanProcessor(BatchSpanProcessor.builder(exporterFactory.createSpanExporter()).build()) + .setResource(resource) + .build(); + + builder.setTracerProvider(tracerProvider); + OpenTelemetrySdk openTelemetrySdk = builder.build(); + return new OpenTelemetryTracer(openTelemetrySdk, instrumenterTracerFactories); + } else { + return new NoOpTracer(); + } + } + + private Resource createResource( + final String serviceInstanceId, + final String serviceName, + final String serviceNameSpace, + final String serviceVersion + ) { + String hostname; + String ipv4; + + try { + hostname = InetAddress.getLocalHost().getHostName(); + ipv4 = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.warn("Unable to retrieve current host and ip for OpenTelemetry Tracer, fallback to default value"); + hostname = DEFAULT_HOST_NAME; + ipv4 = DEFAULT_IP; + } + + return Resource + .getDefault() + .toBuilder() + .put(ResourceAttributes.SERVICE_INSTANCE_ID, serviceInstanceId) + .put(ResourceAttributes.SERVICE_NAME, serviceName) + .put(ATTRIBUTE_KEY_SERVICE_NAMESPACE, serviceNameSpace) + .put(ResourceAttributes.SERVICE_VERSION, serviceVersion) + .put(ATTRIBUTE_KEY_IP, ipv4) + .put(ATTRIBUTE_KEY_HOSTNAME, hostname) + .build(); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/CompressionType.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/CompressionType.java new file mode 100644 index 000000000..2dba0944d --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/CompressionType.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.configuration; + +import java.util.Map; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@RequiredArgsConstructor +@Getter +@Accessors(fluent = true) +public enum CompressionType { + GZIP("gzip"), + NONE("none"); + + private final String value; + + private static final Map MAP = Map.of(NONE.value, NONE, GZIP.value, GZIP); + + public static CompressionType fromValue(final String value) { + if (value != null && MAP.containsKey(value)) { + return MAP.get(value); + } + return NONE; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/OpenTelemetryConfiguration.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/OpenTelemetryConfiguration.java new file mode 100644 index 000000000..4090c47df --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/OpenTelemetryConfiguration.java @@ -0,0 +1,225 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.configuration; + +import io.gravitee.common.util.EnvironmentUtils; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@Builder +@AllArgsConstructor +@Getter +@Setter +public class OpenTelemetryConfiguration { + + private final ConfigurableEnvironment environment; + + @Autowired + public OpenTelemetryConfiguration(ConfigurableEnvironment environment) { + this.environment = environment; + } + + @Value("${services.opentelemetry.enabled:${services.tracing.otel.traces.enabled:true}}") + private boolean tracesEnabled = true; + + @Value("${services.opentelemetry.verbose:false}") + private boolean verboseEnabled = false; + + /** + * Sets the OTLP endpoint to send telemetry data. If unset, defaults to http://localhost:4317. + *

+ * If protocol is `http/protobuf` the version and signal will be appended to the path (e.g. v1/traces or v1/metrics) + * and the default port will be http://localhost:4318. + */ + @Value("${services.opentelemetry.exporter.endpoint:${services.tracing.otel.url:http://localhost:4317}}") + private String endpoint; + + /** + * Key-value pairs to be used as headers associated with exporter requests. + */ + @Getter(AccessLevel.NONE) + private Map customHeaders; + + public Map getCustomHeaders() { + if (customHeaders == null) { + customHeaders = getPropertyMap("services.opentelemetry.exporter.headers"); + + if (customHeaders.isEmpty()) { + customHeaders = getPropertyMap("services.tracing.otel.headers"); + } + } + return customHeaders; + } + + /** + * Sets the method used to compress payloads. If unset, compression is disabled. Currently + * supported compression methods include `gzip` and `none`. + */ + @Value("${services.opentelemetry.exporter.compression:${services.tracing.otel.compression:none}}") + @Getter(AccessLevel.NONE) + private String compression; + + public CompressionType getCompressionType() { + return CompressionType.fromValue(compression); + } + + /** + * Sets the maximum time to wait for the collector to process an exported batch of telemetry data. If + * unset, defaults to 10s. + */ + @Value("${services.opentelemetry.exporter.timeout:${services.tracing.otel.timeout:10000}}") + @Getter(AccessLevel.NONE) + private int timeout; + + public Duration getTimeout() { + return Duration.ofMillis(timeout); + } + + /** + * OTLP defines the encoding of telemetry data and the protocol used to exchange data between the client and the + * server. Depending on the exporter, the available protocols will be different. + *

+ * Currently, only {@code grpc} and {@code http/protobuf} are allowed. + *

+ * Please mind that changing the protocol requires changing the port in the endpoint as well. + */ + @Value("${services.opentelemetry.exporter.protocol:${services.tracing.otel.type:grpc}}") + private String protocol; + + public Protocol getProtocol() { + return Protocol.fromValue(protocol); + } + + @Value("${services.opentelemetry.exporter.ssl.keystore.type:${services.tracing.otel.ssl.keystore.type:#{null}}}") + private String keystoreType; + + @Value("${services.opentelemetry.exporter.ssl.keystore.path:${services.tracing.otel.ssl.keystore.path:#{null}}}") + private String keystorePath; + + @Value("${services.opentelemetry.exporter.ssl.keystore.password:${services.tracing.otel.ssl.keystore.password:#{null}}}") + private String keystorePassword; + + private List keystorePemCerts; + + public List getKeystorePemCerts() { + if (keystorePemCerts == null) { + keystorePemCerts = + getPropertyList("services.opentelemetry.exporter.keystore.certs", "services.tracing.otel.ssl.keystore.certs"); + } + + return keystorePemCerts; + } + + private List keystorePemKeys; + + public List getKeystorePemKeys() { + if (keystorePemKeys == null) { + keystorePemKeys = getPropertyList("services.opentelemetry.exporter.keystore.keys", "services.tracing.otel.ssl.keystore.keys"); + } + + return keystorePemKeys; + } + + @Value("${services.opentelemetry.exporter.ssl.trustall:${services.tracing.otel.ssl.trustall:false}}") + private boolean trustAll = false; + + @Value("${services.opentelemetry.exporter.ssl.verifyHost:${services.tracing.otel.ssl.verifyHostname:true}}") + private boolean verifyHost = true; + + @Value("${services.opentelemetry.exporter.ssl.truststore.type:${services.tracing.otel.ssl.truststore.type:#{null}}}") + private String truststoreType; + + @Value("${services.opentelemetry.exporter.ssl.truststore.path:${services.tracing.otel.ssl.truststore.path:#{null}}}") + private String truststorePath; + + @Value("${services.opentelemetry.exporter.ssl.truststore.password:${services.tracing.otel.ssl.truststore.password:#{null}}}") + private String truststorePassword; + + /** + * If proxy connection must be used. + */ + @Value("${services.opentelemetry.exporter.proxy.enabled:false}") + boolean proxyEnabled; + + @Value("${services.opentelemetry.exporter.proxy.useSystemProxy:true}") + boolean proxyUseSystemProxy; + + @Value("${services.opentelemetry.exporter.proxy.host:#{null}}") + String proxyHost; + + @Value("${services.opentelemetry.exporter.proxy.port:#{null}}") + Integer proxyPort; + + @Value("${services.opentelemetry.exporter.proxy.username:#{null}}") + String proxyUsername; + + @Value("${services.opentelemetry.exporter.proxy.password:#{null}}") + String proxyPassword; + + private Map getPropertyMap(final String key) { + return EnvironmentUtils + .getPropertiesStartingWith(environment, key) + .entrySet() + .stream() + .filter(entry -> Objects.nonNull(entry.getValue())) + .collect(Collectors.toMap(entry -> entry.getKey().substring(key.length() + 1), entry -> String.valueOf(entry.getValue()))); + } + + private List getPropertyList(final String key, final String fallbackKey) { + List values = new ArrayList<>(); + String indexKey = ("%s[%s]").formatted(key, 0); + String indexFallBackKey = ("%s[%s]").formatted(fallbackKey, 0); + while (containsProperty(indexKey, indexFallBackKey)) { + String value = getProperty(indexKey, indexFallBackKey); + if (value != null && !value.isBlank()) { + values.add(value); + } + indexKey = ("%s[%s]").formatted(key, values.size()); + indexFallBackKey = ("%s[%s]").formatted(fallbackKey, values.size()); + } + + return values; + } + + private boolean containsProperty(final String key, final String fallbackKey) { + return environment.containsProperty(key) || environment.containsProperty(fallbackKey); + } + + private String getProperty(final String key, final String fallbackKey) { + String value = environment.getProperty(key); + if (value == null && environment.containsProperty(fallbackKey)) { + value = environment.getProperty(fallbackKey); + } + return value; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/Protocol.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/Protocol.java new file mode 100644 index 000000000..177528c69 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/configuration/Protocol.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.configuration; + +import java.util.Map; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; + +@RequiredArgsConstructor +@Getter +@Accessors(fluent = true) +public enum Protocol { + UNKNOWN("unknown"), + GRPC("grpc"), + HTTP_PROTOBUF("http/protobuf"), + HTTP("http"); + + private final String value; + + private static final Map MAP = Map.of( + UNKNOWN.value, + UNKNOWN, + GRPC.value, + GRPC, + HTTP_PROTOBUF.value, + HTTP_PROTOBUF, + HTTP.value, + HTTP + ); + + public static Protocol fromValue(final String value) { + if (value != null && MAP.containsKey(value)) { + return MAP.get(value); + } + return UNKNOWN; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/ExporterFactory.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/ExporterFactory.java new file mode 100644 index 000000000..c83f2a801 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/ExporterFactory.java @@ -0,0 +1,242 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.exporter; + +import com.google.common.base.Strings; +import io.gravitee.node.opentelemetry.configuration.CompressionType; +import io.gravitee.node.opentelemetry.configuration.OpenTelemetryConfiguration; +import io.gravitee.node.opentelemetry.configuration.Protocol; +import io.gravitee.node.opentelemetry.exporter.sender.VertxGrpcSender; +import io.gravitee.node.opentelemetry.exporter.sender.VertxHttpSender; +import io.gravitee.node.opentelemetry.exporter.tracing.VertxGrpcSpanExporter; +import io.gravitee.node.opentelemetry.exporter.tracing.VertxHttpSpanExporter; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.exporter.internal.ExporterBuilderUtil; +import io.opentelemetry.exporter.internal.grpc.GrpcExporter; +import io.opentelemetry.exporter.internal.http.HttpExporter; +import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.net.JksOptions; +import io.vertx.core.net.PemKeyCertOptions; +import io.vertx.core.net.PemTrustOptions; +import io.vertx.core.net.PfxOptions; +import io.vertx.core.net.ProxyOptions; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + * @see OTelExporterRecorder.java + */ +@RequiredArgsConstructor +@Slf4j +public class ExporterFactory { + + private static final String OTLP_VALUE = "otlp"; + private final OpenTelemetryConfiguration openTelemetryConfiguration; + private final Vertx vertx; + + public SpanExporter createSpanExporter() { + URI tracesUri = getTracesUri(); + Protocol protocol = getProtocol(); + if (protocol == Protocol.HTTP_PROTOBUF || protocol == Protocol.HTTP) { + return createHttpSpanExporter(tracesUri, protocol); + } else { + return createGrpcSpanExporter(tracesUri); + } + } + + private SpanExporter createGrpcSpanExporter(final URI tracesUri) { + return new VertxGrpcSpanExporter( + new GrpcExporter( + OTLP_VALUE, // use the same as OTel does + "span", // use the same as OTel does + new VertxGrpcSender( + tracesUri, + VertxGrpcSender.GRPC_TRACE_SERVICE_NAME, + determineCompression(), + openTelemetryConfiguration.getTimeout(), + populateTracingExportHttpHeaders(), + new HttpClientOptionsConsumer(openTelemetryConfiguration, tracesUri), + vertx + ), + MeterProvider::noop + ) + ); + } + + private SpanExporter createHttpSpanExporter(URI baseUri, final Protocol protocol) { + boolean exportAsJson = protocol == Protocol.HTTP; + + return new VertxHttpSpanExporter( + new HttpExporter<>( + OTLP_VALUE, // use the same as OTel does + "span", // use the same as OTel does + new VertxHttpSender( + baseUri, + VertxHttpSender.TRACES_PATH, + determineCompression(), + openTelemetryConfiguration.getTimeout(), + populateTracingExportHttpHeaders(), + exportAsJson ? "application/json" : "application/x-protobuf", + new HttpClientOptionsConsumer(openTelemetryConfiguration, baseUri), + vertx + ), + MeterProvider::noop, + exportAsJson + ) + ); + } + + private Protocol getProtocol() { + Protocol protocol = openTelemetryConfiguration.getProtocol(); + if (Protocol.UNKNOWN == protocol) { + log.warn("OpenTelemetry protocol unsupported, fallback to GRPC."); + protocol = Protocol.GRPC; + } + return protocol; + } + + private URI getTracesUri() { + String endpoint = openTelemetryConfiguration.getEndpoint(); + // Replace grpc to http to handle backward compatibilty + if (endpoint.startsWith("grpc://")) { + endpoint = endpoint.replace("grpc://", "http://"); + } else if (endpoint.startsWith("grpcs://")) { + endpoint = endpoint.replace("grpcs://", "https://"); + } + return ExporterBuilderUtil.validateEndpoint(endpoint); + } + + private boolean determineCompression() { + return openTelemetryConfiguration.getCompressionType() == CompressionType.GZIP; + } + + private Map populateTracingExportHttpHeaders() { + Map headersMap = new HashMap<>(); + + if (openTelemetryConfiguration.getCustomHeaders() != null) { + headersMap.putAll(openTelemetryConfiguration.getCustomHeaders()); + } + + return headersMap; + } + + private record HttpClientOptionsConsumer(OpenTelemetryConfiguration configuration, URI baseUri) implements Consumer { + private static final String KEYSTORE_FORMAT_JKS = "JKS"; + private static final String KEYSTORE_FORMAT_PEM = "PEM"; + private static final String KEYSTORE_FORMAT_PKCS12 = "PKCS12"; + + @Override + public void accept(HttpClientOptions options) { + if (OTelExporterUtil.isHttps(baseUri)) { + configureSsl(options); + } + if (configuration.isProxyEnabled()) { + configureProxyOptions(options); + } + } + + private void configureSsl(HttpClientOptions options) { + options.setSsl(true).setUseAlpn(true); + + if (configuration.isTrustAll()) { + options.setTrustAll(true).setVerifyHost(false); + } else { + options.setTrustAll(false).setVerifyHost(configuration.isVerifyHost()); + } + + if (KEYSTORE_FORMAT_JKS.equalsIgnoreCase(configuration.getKeystoreType())) { + options.setKeyCertOptions( + new JksOptions().setPath(configuration.getKeystorePath()).setPassword(configuration.getKeystorePassword()) + ); + } else if (KEYSTORE_FORMAT_PKCS12.equalsIgnoreCase(configuration.getKeystoreType())) { + options.setKeyCertOptions( + new PfxOptions().setPath(configuration.getKeystorePath()).setPassword(configuration.getKeystorePassword()) + ); + } else if (KEYSTORE_FORMAT_PEM.equalsIgnoreCase(configuration.getKeystoreType())) { + options.setKeyCertOptions( + new PemKeyCertOptions() + .setCertPaths(configuration.getKeystorePemCerts()) + .setKeyPaths(configuration.getKeystorePemKeys()) + ); + } + + if (KEYSTORE_FORMAT_JKS.equalsIgnoreCase(configuration.getTruststoreType())) { + options.setTrustOptions( + new JksOptions().setPath(configuration.getTruststorePath()).setPassword(configuration.getTruststorePassword()) + ); + } else if (KEYSTORE_FORMAT_PKCS12.equalsIgnoreCase(configuration.getTruststoreType())) { + options.setTrustOptions( + new PfxOptions().setPath(configuration.getTruststorePath()).setPassword(configuration.getTruststorePassword()) + ); + } else if (KEYSTORE_FORMAT_PEM.equalsIgnoreCase(configuration.getTruststoreType())) { + options.setTrustOptions(new PemTrustOptions().addCertPath(configuration.getTruststorePath())); + } + } + + private void configureProxyOptions(HttpClientOptions options) { + String proxyHost = configuration.getProxyHost(); + if (!Strings.isNullOrEmpty(proxyHost)) { + ProxyOptions proxyOptions = new ProxyOptions().setHost(proxyHost); + if (configuration.getProxyPort() != null) { + proxyOptions.setPort(configuration.getProxyPort()); + } + if (!Strings.isNullOrEmpty(configuration.getProxyUsername())) { + proxyOptions.setUsername(configuration.getProxyUsername()); + } + if (!Strings.isNullOrEmpty(configuration.getProxyPassword())) { + proxyOptions.setPassword(configuration.getProxyPassword()); + } + options.setProxyOptions(proxyOptions); + } else if (configuration.isProxyUseSystemProxy()) { + configureProxyOptionsFromJDKSysProps(options); + } + } + + private void configureProxyOptionsFromJDKSysProps(HttpClientOptions options) { + String proxyHost = options.isSsl() + ? System.getProperty("https.proxyHost", "none") + : System.getProperty("http.proxyHost", "none"); + String proxyPortAsString = options.isSsl() + ? System.getProperty("https.proxyPort", "443") + : System.getProperty("http.proxyPort", "80"); + int proxyPort = Integer.parseInt(proxyPortAsString); + + if (!"none".equals(proxyHost)) { + ProxyOptions proxyOptions = new ProxyOptions().setHost(proxyHost).setPort(proxyPort); + String proxyUser = options.isSsl() ? System.getProperty("https.proxyUser") : System.getProperty("http.proxyUser"); + if (proxyUser != null && !proxyUser.isBlank()) { + proxyOptions.setUsername(proxyUser); + } + String proxyPassword = options.isSsl() + ? System.getProperty("https.proxyPassword") + : System.getProperty("http.proxyPassword"); + if (proxyPassword != null && !proxyPassword.isBlank()) { + proxyOptions.setPassword(proxyPassword); + } + options.setProxyOptions(proxyOptions); + } + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/OTelExporterUtil.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/OTelExporterUtil.java new file mode 100644 index 000000000..9279b8a60 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/OTelExporterUtil.java @@ -0,0 +1,29 @@ +package io.gravitee.node.opentelemetry.exporter; + +import java.net.URI; +import java.util.Locale; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * See OTelExporterUtil.java + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class OTelExporterUtil { + + public static int getPort(URI uri) { + int originalPort = uri.getPort(); + if (originalPort > -1) { + return originalPort; + } + + if (isHttps(uri)) { + return 443; + } + return 80; + } + + public static boolean isHttps(URI uri) { + return "https".equals(uri.getScheme().toLowerCase(Locale.ROOT)) || "grpcs".equals(uri.getScheme().toLowerCase(Locale.ROOT)); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/BufferOutputStream.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/BufferOutputStream.java new file mode 100644 index 000000000..92b1340bf --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/BufferOutputStream.java @@ -0,0 +1,27 @@ +package io.gravitee.node.opentelemetry.exporter.sender; + +import io.vertx.core.buffer.Buffer; +import java.io.IOException; +import java.io.OutputStream; + +/** + * See BufferOutputStream.java + */ +public class BufferOutputStream extends OutputStream { + + private final Buffer buffer; + + public BufferOutputStream(Buffer buffer) { + this.buffer = buffer; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + buffer.appendBytes(b, off, len); + } + + @Override + public void write(int b) throws IOException { + buffer.appendInt(b); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxGrpcSender.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxGrpcSender.java new file mode 100644 index 000000000..7a5e04014 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxGrpcSender.java @@ -0,0 +1,505 @@ +package io.gravitee.node.opentelemetry.exporter.sender; + +import io.gravitee.node.opentelemetry.exporter.OTelExporterUtil; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.opentelemetry.exporter.internal.grpc.GrpcResponse; +import io.opentelemetry.exporter.internal.grpc.GrpcSender; +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.internal.ThrottlingLogger; +import io.smallrye.mutiny.Uni; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.net.SocketAddress; +import io.vertx.core.tracing.TracingPolicy; +import io.vertx.grpc.client.GrpcClient; +import io.vertx.grpc.client.GrpcClientRequest; +import io.vertx.grpc.client.GrpcClientResponse; +import io.vertx.grpc.common.GrpcError; +import io.vertx.grpc.common.GrpcStatus; +import io.vertx.grpc.common.ServiceName; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; +import lombok.extern.slf4j.Slf4j; + +/** + * See VertxGrpcSender.java + */ +@Slf4j +public final class VertxGrpcSender implements GrpcSender { + + public static final String GRPC_TRACE_SERVICE_NAME = "opentelemetry.proto.collector.trace.v1.TraceService"; + public static final String GRPC_METRIC_SERVICE_NAME = "opentelemetry.proto.collector.metrics.v1.MetricsService"; + public static final String GRPC_LOG_SERVICE_NAME = "opentelemetry.proto.collector.logs.v1.LogsService"; + private static final String GRPC_METHOD_NAME = "Export"; + + private static final String GRPC_STATUS = "grpc-status"; + private static final String GRPC_MESSAGE = "grpc-message"; + + private static final Logger internalLogger = Logger.getLogger(VertxGrpcSender.class.getName()); + private static final int MAX_ATTEMPTS = 3; + + private final ThrottlingLogger logger = new ThrottlingLogger(internalLogger); // TODO: is there something in JBoss Logging we can use? + + // We only log unimplemented once since it's a configuration issue that won't be recovered. + private final AtomicBoolean loggedUnimplemented = new AtomicBoolean(); + private final AtomicBoolean isShutdown = new AtomicBoolean(); + private final CompletableResultCode shutdownResult = new CompletableResultCode(); + private final SocketAddress server; + private final boolean compressionEnabled; + private final Map headers; + private final String grpcEndpointPath; + + private final GrpcClient client; + + public VertxGrpcSender( + URI grpcBaseUri, + String grpcEndpointPath, + boolean compressionEnabled, + Duration timeout, + Map headersMap, + Consumer clientOptionsCustomizer, + Vertx vertx + ) { + this.grpcEndpointPath = grpcEndpointPath; + this.server = SocketAddress.inetSocketAddress(OTelExporterUtil.getPort(grpcBaseUri), grpcBaseUri.getHost()); + this.compressionEnabled = compressionEnabled; + this.headers = headersMap; + var httpClientOptions = new HttpClientOptions() + .setHttp2ClearTextUpgrade(false) // needed otherwise connections get closed immediately + .setReadIdleTimeout((int) timeout.getSeconds()) + .setTracingPolicy(TracingPolicy.IGNORE); // needed to avoid tracing the calls from this gRPC client + clientOptionsCustomizer.accept(httpClientOptions); + this.client = GrpcClient.client(vertx, httpClientOptions); + } + + @Override + public void send(Marshaler request, Runnable onSuccess, BiConsumer onError) { + if (isShutdown.get()) { + return; + } + + final String marshalerType = request.getClass().getSimpleName(); + var onSuccessHandler = new ClientRequestOnSuccessHandler( + client, + server, + headers, + compressionEnabled, + request, + loggedUnimplemented, + logger, + marshalerType, + onSuccess, + onError, + 1, + grpcEndpointPath, + isShutdown::get + ); + + initiateSend(client, server, MAX_ATTEMPTS, onSuccessHandler, throwable -> failOnClientRequest(marshalerType, throwable, onError)); + } + + @Override + public CompletableResultCode shutdown() { + if (!isShutdown.compareAndSet(false, true)) { + logger.log(Level.FINE, "Calling shutdown() multiple times."); + return shutdownResult; + } + + client + .close() + .onSuccess( + new Handler<>() { + @Override + public void handle(Void event) { + shutdownResult.succeed(); + } + } + ) + .onFailure( + new Handler<>() { + @Override + public void handle(Throwable event) { + shutdownResult.fail(); + } + } + ); + return shutdownResult; + } + + private static void initiateSend( + GrpcClient client, + SocketAddress server, + int numberOfAttempts, + Handler> onSuccessHandler, + Consumer onFailureCallback + ) { + Uni + .createFrom() + .completionStage( + new Supplier>>() { + @Override + public CompletionStage> get() { + return client.request(server).toCompletionStage(); + } + } + ) + .onFailure( + new Predicate() { + @Override + public boolean test(Throwable t) { + // Will not retry on shutdown + return t instanceof IllegalStateException || t instanceof RejectedExecutionException; + } + } + ) + .recoverWithUni( + new Supplier>>() { + @Override + public Uni> get() { + return Uni.createFrom().nothing(); + } + } + ) + .onFailure() + .retry() + .withBackOff(Duration.ofMillis(100)) + .atMost(numberOfAttempts) + .subscribe() + .with( + new Consumer<>() { + @Override + public void accept(GrpcClientRequest request) { + onSuccessHandler.handle(request); + } + }, + onFailureCallback + ); + } + + private void failOnClientRequest(String type, Throwable t, BiConsumer onError) { + String message = + "Failed to export " + + type + + "s. The request could not be executed. Full error message: " + + (t.getMessage() == null ? t.getClass().getName() : t.getMessage()); + logger.log(Level.WARNING, message); + onError.accept(GrpcResponse.create(2/* UNKNOWN */, message), t); + } + + private static final class ClientRequestOnSuccessHandler implements Handler> { + + private final GrpcClient client; + private final SocketAddress server; + private final Map headers; + private final boolean compressionEnabled; + + private final Marshaler marshaler; + private final AtomicBoolean loggedUnimplemented; + private final ThrottlingLogger logger; + private final String type; + private final Runnable onSuccess; + private final BiConsumer onError; + private final String grpcEndpointPath; + + private final int attemptNumber; + private final Supplier isShutdown; + + public ClientRequestOnSuccessHandler( + GrpcClient client, + SocketAddress server, + Map headers, + boolean compressionEnabled, + Marshaler marshaler, + AtomicBoolean loggedUnimplemented, + ThrottlingLogger logger, + String type, + Runnable onSuccess, + BiConsumer onError, + int attemptNumber, + String grpcEndpointPath, + Supplier isShutdown + ) { + this.client = client; + this.server = server; + this.grpcEndpointPath = grpcEndpointPath; + this.headers = headers; + this.compressionEnabled = compressionEnabled; + this.marshaler = marshaler; + this.loggedUnimplemented = loggedUnimplemented; + this.logger = logger; + this.type = type; + this.onSuccess = onSuccess; + this.onError = onError; + this.attemptNumber = attemptNumber; + this.isShutdown = isShutdown; + } + + @Override + public void handle(GrpcClientRequest request) { + if (compressionEnabled) { + request.encoding("gzip"); + } + + // Set the service name and the method to call + request.serviceName(ServiceName.create(grpcEndpointPath)); + request.methodName(GRPC_METHOD_NAME); + + if (!headers.isEmpty()) { + var vertxHeaders = request.headers(); + for (var entry : headers.entrySet()) { + vertxHeaders.set(entry.getKey(), entry.getValue()); + } + } + + try { + int messageSize = marshaler.getBinarySerializedSize(); + Buffer buffer = Buffer.buffer(messageSize); + var os = new BufferOutputStream(buffer); + marshaler.writeBinaryTo(os); + request + .send(buffer) + .onSuccess( + new Handler<>() { + @Override + public void handle(GrpcClientResponse response) { + response + .exceptionHandler( + new Handler<>() { + @Override + public void handle(Throwable t) { + if (attemptNumber <= MAX_ATTEMPTS && !isShutdown.get()) { + // retry + initiateSend( + client, + server, + MAX_ATTEMPTS - attemptNumber, + newAttempt(), + new Consumer<>() { + @Override + public void accept(Throwable throwable) { + failOnClientRequest(throwable, onError, attemptNumber); + } + } + ); + } else { + failOnClientRequest(t, onError, attemptNumber); + } + } + } + ) + .errorHandler( + new Handler<>() { + @Override + public void handle(GrpcError error) { + handleError(error.status, response); + } + } + ) + .endHandler( + new Handler<>() { + @Override + public void handle(Void ignored) { + GrpcStatus status = getStatus(response); + if (status == GrpcStatus.OK) { + onSuccess.run(); + } else { + handleError(status, response); + } + } + } + ); + } + + private void handleError(GrpcStatus status, GrpcClientResponse response) { + String statusMessage = getStatusMessage(response); + logAppropriateWarning(status, statusMessage); + onError.accept( + GrpcResponse.create(2/* UNKNOWN */, statusMessage), + new IllegalStateException(statusMessage) + ); + } + + private void logAppropriateWarning(GrpcStatus status, String statusMessage) { + if (status == GrpcStatus.UNIMPLEMENTED) { + if (loggedUnimplemented.compareAndSet(false, true)) { + logUnimplemented(internalLogger, type, statusMessage); + } + } else if (status == GrpcStatus.UNAVAILABLE) { + logger.log( + Level.WARNING, + "Failed to export " + + type + + "s. Server is UNAVAILABLE. " + + "Make sure your collector is running and reachable from this network. " + + "Full error message:" + + statusMessage + ); + } else { + if (status == null) { + if (statusMessage == null) { + logger.log( + Level.WARNING, + "Failed to export " + + type + + "s. Perhaps the collector does not support collecting traces using grpc? Try configuring 'quarkus.otel.exporter.otlp.traces.protocol=http/protobuf'" + ); + } else { + logger.log( + Level.WARNING, + "Failed to export " + type + "s. Server responded with error message: " + statusMessage + ); + } + } else { + logger.log( + Level.WARNING, + "Failed to export " + + type + + "s. Server responded with " + + status.code + + ". Error message: " + + statusMessage + ); + } + } + } + + private void logUnimplemented(Logger logger, String type, String fullErrorMessage) { + String envVar; + switch (type) { + case "span": + envVar = "OTEL_TRACES_EXPORTER"; + break; + case "metric": + envVar = "OTEL_METRICS_EXPORTER"; + break; + case "log": + envVar = "OTEL_LOGS_EXPORTER"; + break; + default: + throw new IllegalStateException( + "Unrecognized type, this is a programming bug in the OpenTelemetry SDK" + ); + } + + logger.log( + Level.WARNING, + "Failed to export " + + type + + "s. Server responded with UNIMPLEMENTED. " + + "This usually means that your collector is not configured with an otlp " + + "receiver in the \"pipelines\" section of the configuration. " + + "If export is not desired and you are using OpenTelemetry autoconfiguration or the javaagent, " + + "disable export by setting " + + envVar + + "=none. " + + "Full error message: " + + fullErrorMessage + ); + } + + private GrpcStatus getStatus(GrpcClientResponse response) { + // Status can either be in the headers or trailers depending on error + GrpcStatus result = response.status(); + if (result == null) { + String statusFromTrailer = response.trailers().get(GRPC_STATUS); + if (statusFromTrailer != null) { + result = GrpcStatus.valueOf(Integer.parseInt(statusFromTrailer)); + } + } + return result; + } + + private String getStatusMessage(GrpcClientResponse response) { + // Status message can either be in the headers or trailers depending on error + String result = response.statusMessage(); + if (result == null) { + result = response.trailers().get(GRPC_MESSAGE); + if (result != null) { + result = QueryStringDecoder.decodeComponent(result, StandardCharsets.UTF_8); + } + } + return result; + } + } + ) + .onFailure( + new Handler<>() { + @Override + public void handle(Throwable t) { + if (attemptNumber <= MAX_ATTEMPTS && !isShutdown.get()) { + // retry + initiateSend( + client, + server, + MAX_ATTEMPTS - attemptNumber, + newAttempt(), + new Consumer<>() { + @Override + public void accept(Throwable throwable) { + failOnClientRequest(throwable, onError, attemptNumber); + } + } + ); + } else { + failOnClientRequest(t, onError, attemptNumber); + } + } + } + ); + } catch (IOException e) { + final String message = + "Failed to export " + + type + + "s. Unable to serialize payload. Full error message: " + + (e.getMessage() == null ? e.getClass().getName() : e.getMessage()); + logger.log(Level.WARNING, message); + onError.accept(GrpcResponse.create(2/* UNKNOWN */, message), e); + } + } + + private void failOnClientRequest(Throwable t, BiConsumer onError, int attemptNumber) { + final String message = + "Failed to export " + + type + + "s. The request could not be executed after " + + attemptNumber + + " attempts. Full error message: " + + (t != null ? t.getMessage() : ""); + logger.log(Level.WARNING, message); + onError.accept(GrpcResponse.create(2/* UNKNOWN */, message), t); + } + + public ClientRequestOnSuccessHandler newAttempt() { + return new ClientRequestOnSuccessHandler( + client, + server, + headers, + compressionEnabled, + marshaler, + loggedUnimplemented, + logger, + type, + onSuccess, + onError, + attemptNumber + 1, + grpcEndpointPath, + isShutdown + ); + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxHttpSender.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxHttpSender.java new file mode 100644 index 000000000..c6af256f4 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/sender/VertxHttpSender.java @@ -0,0 +1,360 @@ +package io.gravitee.node.opentelemetry.exporter.sender; + +import static io.gravitee.node.opentelemetry.exporter.OTelExporterUtil.getPort; + +import io.opentelemetry.exporter.internal.http.HttpSender; +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.internal.ThrottlingLogger; +import io.smallrye.mutiny.Uni; +import io.vertx.core.AsyncResult; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpClientResponse; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.tracing.TracingPolicy; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.GZIPOutputStream; + +/** + * See VertxHttpSender.java + */ +public final class VertxHttpSender implements HttpSender { + + public static final String TRACES_PATH = "/v1/traces"; + public static final String METRICS_PATH = "/v1/metrics"; + public static final String LOGS_PATH = "/v1/logs"; + + private static final Logger internalLogger = Logger.getLogger(VertxHttpSender.class.getName()); + private static final ThrottlingLogger logger = new ThrottlingLogger(internalLogger); + + private static final int MAX_ATTEMPTS = 3; + + private final String basePath; + private final boolean compressionEnabled; + private final Map headers; + private final String contentType; + private final HttpClient client; + private final String signalPath; + + public VertxHttpSender( + URI baseUri, + String signalPath, + boolean compressionEnabled, + Duration timeout, + Map headersMap, + String contentType, + Consumer clientOptionsCustomizer, + Vertx vertx + ) { + this.basePath = determineBasePath(baseUri); + this.signalPath = signalPath; + this.compressionEnabled = compressionEnabled; + this.headers = headersMap; + this.contentType = contentType; + var httpClientOptions = new HttpClientOptions() + .setReadIdleTimeout((int) timeout.getSeconds()) + .setDefaultHost(baseUri.getHost()) + .setDefaultPort(getPort(baseUri)) + .setTracingPolicy(TracingPolicy.IGNORE); // needed to avoid tracing the calls from this http client + clientOptionsCustomizer.accept(httpClientOptions); + this.client = vertx.createHttpClient(httpClientOptions); + } + + private final AtomicBoolean isShutdown = new AtomicBoolean(); + private final CompletableResultCode shutdownResult = new CompletableResultCode(); + + private static String determineBasePath(URI baseUri) { + String path = baseUri.getPath(); + if (path.isEmpty() || path.equals("/")) { + return ""; + } + if (path.endsWith("/")) { // strip ending slash + path = path.substring(0, path.length() - 1); + } + if (!path.startsWith("/")) { // prepend leading slash + path = "/" + path; + } + return path; + } + + @Override + public void send(Marshaler marshaler, int contentLength, Consumer onHttpResponseRead, Consumer onError) { + if (isShutdown.get()) { + return; + } + + String requestURI = basePath + signalPath; + var clientRequestSuccessHandler = new ClientRequestSuccessHandler( + client, + requestURI, + headers, + compressionEnabled, + contentType, + contentLength, + onHttpResponseRead, + onError, + marshaler, + 1, + isShutdown::get + ); + initiateSend(client, requestURI, MAX_ATTEMPTS, clientRequestSuccessHandler, onError, isShutdown::get); + } + + private static void initiateSend( + HttpClient client, + String requestURI, + int numberOfAttempts, + Handler clientRequestSuccessHandler, + Consumer onError, + Supplier isShutdown + ) { + Uni + .createFrom() + .completionStage( + new Supplier>() { + @Override + public CompletionStage get() { + return client.request(HttpMethod.POST, requestURI).toCompletionStage(); + } + } + ) + .onFailure( + new Predicate() { + @Override + public boolean test(Throwable t) { + // Will not retry on shutdown + return t instanceof IllegalStateException || t instanceof RejectedExecutionException || isShutdown.get(); + } + } + ) + .recoverWithUni( + new Supplier>() { + @Override + public Uni get() { + return Uni.createFrom().nothing(); + } + } + ) + .onFailure() + .retry() + .withBackOff(Duration.ofMillis(100)) + .atMost(numberOfAttempts) + .subscribe() + .with( + new Consumer<>() { + @Override + public void accept(HttpClientRequest request) { + clientRequestSuccessHandler.handle(request); + } + }, + onError + ); + } + + @Override + public CompletableResultCode shutdown() { + if (!isShutdown.compareAndSet(false, true)) { + logger.log(Level.FINE, "Calling shutdown() multiple times."); + return shutdownResult; + } + + client + .close() + .onSuccess( + new Handler<>() { + @Override + public void handle(Void event) { + shutdownResult.succeed(); + } + } + ) + .onFailure( + new Handler<>() { + @Override + public void handle(Throwable event) { + shutdownResult.fail(); + } + } + ); + return shutdownResult; + } + + private static class ClientRequestSuccessHandler implements Handler { + + private final HttpClient client; + private final String requestURI; + private final Map headers; + private final boolean compressionEnabled; + private final String contentType; + private final int contentLength; + private final Consumer onHttpResponseRead; + private final Consumer onError; + private final Marshaler marshaler; + + private final int attemptNumber; + private final Supplier isShutdown; + + public ClientRequestSuccessHandler( + HttpClient client, + String requestURI, + Map headers, + boolean compressionEnabled, + String contentType, + int contentLength, + Consumer onHttpResponseRead, + Consumer onError, + Marshaler marshaler, + int attemptNumber, + Supplier isShutdown + ) { + this.client = client; + this.requestURI = requestURI; + this.headers = headers; + this.compressionEnabled = compressionEnabled; + this.contentType = contentType; + this.contentLength = contentLength; + this.onHttpResponseRead = onHttpResponseRead; + this.onError = onError; + this.marshaler = marshaler; + this.attemptNumber = attemptNumber; + this.isShutdown = isShutdown; + } + + @Override + public void handle(HttpClientRequest request) { + HttpClientRequest clientRequest = request + .response( + new Handler<>() { + @Override + public void handle(AsyncResult callResult) { + if (callResult.succeeded()) { + HttpClientResponse clientResponse = callResult.result(); + Throwable cause = callResult.cause(); + clientResponse.body( + new Handler<>() { + @Override + public void handle(AsyncResult bodyResult) { + if (bodyResult.succeeded()) { + if (clientResponse.statusCode() >= 500) { + if (attemptNumber <= MAX_ATTEMPTS && !isShutdown.get()) { + // we should retry for 5xx error as they might be recoverable + initiateSend( + client, + requestURI, + MAX_ATTEMPTS - attemptNumber, + newAttempt(), + onError, + isShutdown + ); + return; + } + } + onHttpResponseRead.accept( + new Response() { + @Override + public int statusCode() { + return clientResponse.statusCode(); + } + + @Override + public String statusMessage() { + return clientResponse.statusMessage(); + } + + @Override + public byte[] responseBody() { + return bodyResult.result().getBytes(); + } + } + ); + } else { + if (attemptNumber <= MAX_ATTEMPTS && !isShutdown.get()) { + // retry + initiateSend( + client, + requestURI, + MAX_ATTEMPTS - attemptNumber, + newAttempt(), + onError, + isShutdown + ); + } else { + onError.accept(bodyResult.cause()); + } + } + } + } + ); + } else { + if (attemptNumber <= MAX_ATTEMPTS && !isShutdown.get()) { + // retry + initiateSend(client, requestURI, MAX_ATTEMPTS - attemptNumber, newAttempt(), onError, isShutdown); + } else { + onError.accept(callResult.cause()); + } + } + } + } + ) + .putHeader("Content-Type", contentType); + + Buffer buffer = Buffer.buffer(contentLength); + OutputStream os = new BufferOutputStream(buffer); + if (compressionEnabled) { + clientRequest.putHeader("Content-Encoding", "gzip"); + try (var gzos = new GZIPOutputStream(os)) { + marshaler.writeBinaryTo(gzos); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } else { + try { + marshaler.writeBinaryTo(os); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + if (!headers.isEmpty()) { + for (var entry : headers.entrySet()) { + clientRequest.putHeader(entry.getKey(), entry.getValue()); + } + } + + clientRequest.send(buffer); + } + + public ClientRequestSuccessHandler newAttempt() { + return new ClientRequestSuccessHandler( + client, + requestURI, + headers, + compressionEnabled, + contentType, + contentLength, + onHttpResponseRead, + onError, + marshaler, + attemptNumber + 1, + isShutdown + ); + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxGrpcSpanExporter.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxGrpcSpanExporter.java new file mode 100644 index 000000000..427b57424 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxGrpcSpanExporter.java @@ -0,0 +1,36 @@ +package io.gravitee.node.opentelemetry.exporter.tracing; + +import io.opentelemetry.exporter.internal.grpc.GrpcExporter; +import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Collection; + +/** + * See VertxGrpcSpanExporter.java + */ +public final class VertxGrpcSpanExporter implements SpanExporter { + + private final GrpcExporter delegate; + + public VertxGrpcSpanExporter(GrpcExporter delegate) { + this.delegate = delegate; + } + + @Override + public CompletableResultCode export(Collection spans) { + TraceRequestMarshaler exportRequest = TraceRequestMarshaler.create(spans); + return delegate.export(exportRequest, spans.size()); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return delegate.shutdown(); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxHttpSpanExporter.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxHttpSpanExporter.java new file mode 100644 index 000000000..da564656b --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/tracing/VertxHttpSpanExporter.java @@ -0,0 +1,36 @@ +package io.gravitee.node.opentelemetry.exporter.tracing; + +import io.opentelemetry.exporter.internal.http.HttpExporter; +import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Collection; + +/** + * See VertxHttpSpanExporter.java + */ +public final class VertxHttpSpanExporter implements SpanExporter { + + private final HttpExporter delegate; + + public VertxHttpSpanExporter(HttpExporter delegate) { + this.delegate = delegate; + } + + @Override + public CompletableResultCode export(Collection spans) { + TraceRequestMarshaler exportRequest = TraceRequestMarshaler.create(spans); + return delegate.export(exportRequest, spans.size()); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return delegate.shutdown(); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/spring/OpenTelemetrySpringConfiguration.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/spring/OpenTelemetrySpringConfiguration.java new file mode 100644 index 000000000..78a9e2c6d --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/spring/OpenTelemetrySpringConfiguration.java @@ -0,0 +1,65 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.spring; + +import io.gravitee.node.api.opentelemetry.InstrumenterTracerFactory; +import io.gravitee.node.opentelemetry.OpenTelemetryFactory; +import io.gravitee.node.opentelemetry.configuration.OpenTelemetryConfiguration; +import io.gravitee.node.opentelemetry.exporter.ExporterFactory; +import io.gravitee.node.opentelemetry.tracer.instrumentation.internal.InternalInstrumenterTracerFactory; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.VertxHttpInstrumenterTracerFactory; +import io.vertx.core.Vertx; +import java.util.List; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@Configuration +public class OpenTelemetrySpringConfiguration { + + @Bean + public OpenTelemetryConfiguration openTelemetryConfiguration(final ConfigurableEnvironment environment) { + return new OpenTelemetryConfiguration(environment); + } + + @Bean + public ExporterFactory exporterFactory(final OpenTelemetryConfiguration openTelemetryConfiguration, final Vertx vertx) { + return new ExporterFactory(openTelemetryConfiguration, vertx); + } + + @Bean + public OpenTelemetryFactory openTelemetryFactory( + final OpenTelemetryConfiguration openTelemetryConfiguration, + final ExporterFactory exporterFactory + ) { + return new OpenTelemetryFactory(openTelemetryConfiguration, exporterFactory); + } + + @Bean + public VertxHttpInstrumenterTracerFactory vertxHttpInstrumenterTracerFactory() { + return new VertxHttpInstrumenterTracerFactory(); + } + + @Bean + public InternalInstrumenterTracerFactory internalInstrumenterTracerFactory() { + return new InternalInstrumenterTracerFactory(); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/OpenTelemetryTracer.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/OpenTelemetryTracer.java new file mode 100644 index 000000000..713d7efae --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/OpenTelemetryTracer.java @@ -0,0 +1,164 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.tracer; + +import io.gravitee.common.service.AbstractService; +import io.gravitee.node.api.opentelemetry.InstrumenterTracer; +import io.gravitee.node.api.opentelemetry.InstrumenterTracerFactory; +import io.gravitee.node.api.opentelemetry.Span; +import io.gravitee.node.api.opentelemetry.Tracer; +import io.gravitee.node.opentelemetry.tracer.noop.NoOpSpan; +import io.gravitee.node.opentelemetry.tracer.span.OpenTelemetrySpan; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.vertx.core.Context; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@RequiredArgsConstructor +@Slf4j +public class OpenTelemetryTracer extends AbstractService implements Tracer { + + private final OpenTelemetrySdk openTelemetrySdk; + private final List instrumenterTracerFactories; + private List instrumenterTracers; + + @Override + protected void doStart() throws Exception { + super.doStart(); + if (instrumenterTracerFactories != null) { + instrumenterTracers = + instrumenterTracerFactories + .stream() + .map(instrumenterTracerFactory -> { + try { + return instrumenterTracerFactory.createInstrumenterTracer(openTelemetrySdk); + } catch (Exception e) { + log.warn( + "Unable to register extra instrumenter factory [{}]", + instrumenterTracerFactory.getClass().getName(), + e + ); + } + return null; + }) + .filter(Objects::nonNull) + .toList(); + } + } + + @Override + protected void doStop() throws Exception { + super.doStop(); + openTelemetrySdk.close(); + } + + @Override + public Span startRootSpanFrom(final Context vertxContext, final R request) { + if (instrumenterTracers != null) { + Optional first = instrumenterTracers + .stream() + .filter(instrumenterTracer -> instrumenterTracer.canHandle(request)) + .findFirst(); + if (first.isPresent()) { + InstrumenterTracer instrumenterTracer = first.get(); + return instrumenterTracer.startSpan(vertxContext, request, true, null); + } + } + return NoOpSpan.asRoot(); + } + + @Override + public Span startSpanFrom(final Context vertxContext, final R request) { + if (instrumenterTracers != null) { + Optional first = instrumenterTracers + .stream() + .filter(instrumenterTracer -> instrumenterTracer.canHandle(request)) + .findFirst(); + if (first.isPresent()) { + InstrumenterTracer instrumenterTracer = first.get(); + return instrumenterTracer.startSpan(vertxContext, request, false, null); + } + } + return NoOpSpan.asDefault(); + } + + @Override + public Span startSpanWithParentFrom(final Context vertxContext, final Span parentSpan, final R request) { + if (instrumenterTracers != null) { + Optional first = instrumenterTracers + .stream() + .filter(instrumenterTracer -> instrumenterTracer.canHandle(request)) + .findFirst(); + if (first.isPresent()) { + InstrumenterTracer instrumenterTracer = first.get(); + return instrumenterTracer.startSpan(vertxContext, request, false, parentSpan); + } + } + return NoOpSpan.asDefault(); + } + + @Override + public void end(final Context vertxContext, final Span span) { + endWithResponse(vertxContext, span, null); + } + + @Override + public void endOnError(final Context vertxContext, final Span span, final Throwable throwable) { + endWithResponseAndError(vertxContext, span, null, throwable); + } + + @Override + public void endOnError(final Context vertxContext, final Span span, final String message) { + endWithResponseAndError(vertxContext, span, null, message); + } + + @Override + public void endWithResponse(final Context vertxContext, final Span span, final R response) { + endWithResponseAndError(vertxContext, span, response, (Throwable) null); + } + + @Override + public void endWithResponseAndError(final Context vertxContext, final Span span, final R response, final String message) { + if (span instanceof OpenTelemetrySpan openTelemetrySpan) { + openTelemetrySpan.span().setStatus(StatusCode.ERROR, message); + endWithResponse(vertxContext, span, response); + } + } + + @Override + public void endWithResponseAndError(final Context vertxContext, final Span span, final R response, final Throwable throwable) { + if (instrumenterTracers != null) { + if (span instanceof OpenTelemetrySpan openTelemetrySpan) { + Optional first = instrumenterTracers + .stream() + .filter(instrumenterTracer -> instrumenterTracer.canHandle(openTelemetrySpan.request())) + .findFirst(); + if (first.isPresent()) { + InstrumenterTracer instrumenterTracer = first.get(); + instrumenterTracer.endSpan(vertxContext, openTelemetrySpan, response, throwable); + } + } + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/AbstractInstrumenterTracer.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/AbstractInstrumenterTracer.java new file mode 100644 index 000000000..7db5da680 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/AbstractInstrumenterTracer.java @@ -0,0 +1,89 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.tracer.instrumentation; + +import io.gravitee.common.service.AbstractService; +import io.gravitee.node.api.opentelemetry.InstrumenterTracer; +import io.gravitee.node.api.opentelemetry.Span; +import io.gravitee.node.api.opentelemetry.Tracer; +import io.gravitee.node.opentelemetry.tracer.noop.NoOpSpan; +import io.gravitee.node.opentelemetry.tracer.span.OpenTelemetrySpan; +import io.gravitee.node.opentelemetry.tracer.vertx.VertxContextStorage; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.vertx.core.Context; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public abstract class AbstractInstrumenterTracer extends AbstractService implements InstrumenterTracer { + + protected abstract Instrumenter getRootInstrumenter(); + + protected abstract Instrumenter getDefaultInstrumenter(); + + @Override + public Span startSpan(final Context vertxContext, final R request, final boolean root, final Span parentSpan) { + io.opentelemetry.context.Context parentContext; + if (parentSpan instanceof OpenTelemetrySpan openTelemetryParentSpan) { + parentContext = openTelemetryParentSpan.otelContext(); + } else { + parentContext = VertxContextStorage.getContext(vertxContext); + if (parentContext == null) { + parentContext = io.opentelemetry.context.Context.current(); + } + } + Instrumenter instrumenter; + if (parentContext.equals(io.opentelemetry.context.Context.root())) { + instrumenter = getRootInstrumenter(); + } else { + instrumenter = getDefaultInstrumenter(); + } + + if (instrumenter.shouldStart(parentContext, (REQ) request)) { + io.opentelemetry.context.Context otelContext = instrumenter.start(parentContext, (REQ) request); + Scope scope = VertxContextStorage.INSTANCE.attach(vertxContext, otelContext); + return new OpenTelemetrySpan<>(vertxContext, otelContext, scope, root, request); + } + if (root) { + return NoOpSpan.asRoot(); + } else { + return NoOpSpan.asDefault(); + } + } + + @Override + public void endSpan(final Context vertxContext, final Span span, final R response, final Throwable throwable) { + if (span instanceof OpenTelemetrySpan openTelemetrySpan) { + Scope scope = openTelemetrySpan.scope(); + if (scope == null) { + return; + } + + Object request = openTelemetrySpan.request(); + Instrumenter instrumenter; + if (openTelemetrySpan.isRoot()) { + instrumenter = getRootInstrumenter(); + } else { + instrumenter = getDefaultInstrumenter(); + } + try (scope) { + instrumenter.end(openTelemetrySpan.otelContext(), (REQ) request, (RESP) response, throwable); + } + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracer.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracer.java new file mode 100644 index 000000000..3415f2f8f --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracer.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.opentelemetry.tracer.instrumentation.internal; + +import io.gravitee.node.api.opentelemetry.internal.InternalRequest; +import io.gravitee.node.opentelemetry.tracer.instrumentation.AbstractInstrumenterTracer; +import io.gravitee.node.opentelemetry.tracer.instrumentation.internal.extractor.InternalAttributesExtractor; +import io.gravitee.node.opentelemetry.tracer.instrumentation.internal.extractor.InternalSpanNameExtractor; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; +import lombok.RequiredArgsConstructor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@RequiredArgsConstructor +public class InternalInstrumenterTracer extends AbstractInstrumenterTracer { + + private final OpenTelemetry openTelemetry; + private Instrumenter instrumenter; + + @Override + public String instrumentationName() { + return "io.gravitee.opentelemetry.internal"; + } + + @Override + public boolean canHandle(final R request) { + return request instanceof InternalRequest; + } + + @Override + protected Instrumenter getRootInstrumenter() { + return getDefaultInstrumenter(); + } + + @Override + protected Instrumenter getDefaultInstrumenter() { + if (instrumenter == null) { + instrumenter = createInstrumenter(openTelemetry); + } + return instrumenter; + } + + private Instrumenter createInstrumenter(final OpenTelemetry openTelemetry) { + InstrumenterBuilder serverBuilder = Instrumenter.builder( + openTelemetry, + instrumentationName(), + new InternalSpanNameExtractor() + ); + + return serverBuilder.addAttributesExtractor(new InternalAttributesExtractor()).buildInstrumenter(); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracerFactory.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracerFactory.java new file mode 100644 index 000000000..84db1b417 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/InternalInstrumenterTracerFactory.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.opentelemetry.tracer.instrumentation.internal; + +import io.gravitee.node.api.opentelemetry.InstrumenterTracer; +import io.gravitee.node.api.opentelemetry.InstrumenterTracerFactory; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.VertxHttpInstrumenterTracer; +import io.opentelemetry.api.OpenTelemetry; +import lombok.NoArgsConstructor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@NoArgsConstructor +public class InternalInstrumenterTracerFactory implements InstrumenterTracerFactory { + + @Override + public InstrumenterTracer createInstrumenterTracer(final OpenTelemetry openTelemetry) { + return new InternalInstrumenterTracer(openTelemetry); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalAttributesExtractor.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalAttributesExtractor.java new file mode 100644 index 000000000..b36f624ec --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalAttributesExtractor.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.opentelemetry.tracer.instrumentation.internal.extractor; + +import io.gravitee.node.api.opentelemetry.internal.InternalRequest; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public class InternalAttributesExtractor implements AttributesExtractor { + + @Override + public void onStart( + final AttributesBuilder attributes, + final io.opentelemetry.context.Context parentContext, + final InternalRequest internalRequest + ) { + if (internalRequest.attributes() != null) { + internalRequest.attributes().forEach(attributes::put); + } + } + + @Override + public void onEnd( + final AttributesBuilder attributes, + final io.opentelemetry.context.Context context, + final InternalRequest httpRequest, + final Void response, + final Throwable error + ) {} +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalSpanNameExtractor.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalSpanNameExtractor.java new file mode 100644 index 000000000..5a4ce37ec --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/internal/extractor/InternalSpanNameExtractor.java @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.opentelemetry.tracer.instrumentation.internal.extractor; + +import io.gravitee.node.api.opentelemetry.internal.InternalRequest; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; + +public class InternalSpanNameExtractor implements SpanNameExtractor { + + @Override + public String extract(InternalRequest internalRequest) { + return internalRequest.name(); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracer.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracer.java new file mode 100644 index 000000000..80ea97dc8 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracer.java @@ -0,0 +1,148 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx; + +import io.gravitee.node.api.opentelemetry.Span; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpResponse; +import io.gravitee.node.opentelemetry.tracer.instrumentation.AbstractInstrumenterTracer; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.AdditionalServerAttributesExtractor; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.ClientSpanNameExtractor; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.HttpClientAttributesExtractor; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.HttpRequestTextMapGetter; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.HttpRequestTextMapSetter; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.RouteGetter; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor.ServerAttributesExtractor; +import io.gravitee.node.opentelemetry.tracer.span.OpenTelemetrySpan; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteSource; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; +import io.smallrye.common.vertx.VertxContext; +import io.vertx.core.Context; +import io.vertx.core.spi.observability.HttpRequest; +import lombok.RequiredArgsConstructor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + * + * See HttpInstrumenterVertxTracer.java + */ +@RequiredArgsConstructor +public class VertxHttpInstrumenterTracer extends AbstractInstrumenterTracer { + + private final OpenTelemetry openTelemetry; + private Instrumenter serverInstrumenter; + private Instrumenter clientInstrumenter; + + @Override + public String instrumentationName() { + return "io.gravitee.opentelemetry.http"; + } + + @Override + public boolean canHandle(final R request) { + return request instanceof ObservableHttpRequest; + } + + @Override + public Span startSpan(final Context vertxContext, final R request, final boolean root, final Span parent) { + Span span = super.startSpan(vertxContext, request, root, parent); + if (span instanceof OpenTelemetrySpan requestSpan) { + Context runningCtx = requestSpan.vertxContext(); + if (VertxContext.isDuplicatedContext(runningCtx)) { + String pathTemplate = runningCtx.getLocal("ClientUrlPathTemplate"); + if (pathTemplate != null && !pathTemplate.isEmpty()) { + io.opentelemetry.api.trace.Span + .fromContext(requestSpan.otelContext()) + .updateName(((HttpRequest) requestSpan.request()).method().name() + " " + pathTemplate); + } + } + } + return span; + } + + @Override + public void endSpan(final Context vertxContext, final Span span, final R response, final Throwable throwable) { + if (span instanceof OpenTelemetrySpan requestSpan && response instanceof ObservableHttpResponse observableHttpResponse) { + HttpServerRoute.update( + requestSpan.otelContext(), + HttpServerRouteSource.SERVER_FILTER, + RouteGetter.INSTANCE, + requestSpan, + observableHttpResponse + ); + } + + super.endSpan(vertxContext, span, response, throwable); + } + + @Override + protected Instrumenter getRootInstrumenter() { + if (serverInstrumenter == null) { + serverInstrumenter = createServerInstrumenter(openTelemetry); + } + return serverInstrumenter; + } + + @Override + protected Instrumenter getDefaultInstrumenter() { + if (clientInstrumenter == null) { + clientInstrumenter = createClientInstrumenter(openTelemetry); + } + return clientInstrumenter; + } + + private Instrumenter createServerInstrumenter(final OpenTelemetry openTelemetry) { + ServerAttributesExtractor serverAttributesExtractor = new ServerAttributesExtractor(); + + InstrumenterBuilder serverBuilder = Instrumenter.builder( + openTelemetry, + instrumentationName(), + HttpSpanNameExtractor.create(serverAttributesExtractor) + ); + + return serverBuilder + .setSpanStatusExtractor(HttpSpanStatusExtractor.create(serverAttributesExtractor)) + .addAttributesExtractor(HttpServerAttributesExtractor.create(serverAttributesExtractor)) + .addAttributesExtractor(new AdditionalServerAttributesExtractor()) + .addContextCustomizer(HttpServerRoute.create(serverAttributesExtractor)) + .buildServerInstrumenter(new HttpRequestTextMapGetter()); + } + + private Instrumenter createClientInstrumenter(final OpenTelemetry openTelemetry) { + ServerAttributesExtractor serverAttributesExtractor = new ServerAttributesExtractor(); + HttpClientAttributesExtractor httpClientAttributesExtractor = new HttpClientAttributesExtractor(); + + InstrumenterBuilder clientBuilder = io.opentelemetry.instrumentation.api.instrumenter.Instrumenter.builder( + openTelemetry, + instrumentationName(), + new ClientSpanNameExtractor(httpClientAttributesExtractor) + ); + + return clientBuilder + .setSpanStatusExtractor(HttpSpanStatusExtractor.create(serverAttributesExtractor)) + .addAttributesExtractor( + io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor.create(httpClientAttributesExtractor) + ) + .buildClientInstrumenter(new HttpRequestTextMapSetter()); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracerFactory.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracerFactory.java new file mode 100644 index 000000000..d57110100 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxHttpInstrumenterTracerFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 The Gravitee team (http://gravitee.io) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx; + +import io.gravitee.node.api.opentelemetry.InstrumenterTracer; +import io.gravitee.node.api.opentelemetry.InstrumenterTracerFactory; +import io.opentelemetry.api.OpenTelemetry; +import lombok.NoArgsConstructor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@NoArgsConstructor +public class VertxHttpInstrumenterTracerFactory implements InstrumenterTracerFactory { + + @Override + public InstrumenterTracer createInstrumenterTracer(final OpenTelemetry openTelemetry) { + return new VertxHttpInstrumenterTracer(openTelemetry); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxUtil.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxUtil.java new file mode 100644 index 000000000..1ae89db31 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/VertxUtil.java @@ -0,0 +1,93 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx; + +import io.vertx.core.http.HttpServerRequest; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class VertxUtil { + + private static final String X_FORWARDED_FOR = "X-Forwarded-For"; + private static final Pattern FORWARDED_FOR_PATTERN = Pattern.compile("for=\"?([^;,\"]+)\"?"); + private static final String FORWARDED = "Forwarded"; + private static final String COMMA_SPLITTER = ","; + private static final String COLON_SPLITTER = ":"; + private static final int SPLIT_LIMIT = -1; + + private static String getForwardedHeaderValue(HttpServerRequest httpServerRequest) { + var forwardedHeader = httpServerRequest.getHeader(FORWARDED); + if (forwardedHeader == null) { + return null; + } + var forwardedHeaderMatcher = FORWARDED_FOR_PATTERN.matcher(forwardedHeader); + if (forwardedHeaderMatcher.find()) { + return forwardedHeaderMatcher.group(1).trim(); + } + return null; + } + + private static String getXForwardedHeaderValue(HttpServerRequest httpServerRequest) { + var xForwardedForHeader = httpServerRequest.getHeader(X_FORWARDED_FOR); + if (xForwardedForHeader == null) { + return null; + } + return xForwardedForHeader.split(COMMA_SPLITTER, SPLIT_LIMIT)[0]; + } + + private static String getHostHeader(HttpServerRequest httpRequest) { + String header = httpRequest.getHeader("host"); + if (header == null) { + return null; + } + return header.split(COLON_SPLITTER, SPLIT_LIMIT)[0]; + } + + private static String getHostPortHeader(HttpServerRequest httpRequest) { + String header = httpRequest.getHeader("host"); + if (header == null) { + return null; + } + String[] headerValues = header.split(COLON_SPLITTER, SPLIT_LIMIT); + return headerValues.length > 1 ? headerValues[1] : null; + } + + public static String extractClientIP(HttpServerRequest httpServerRequest) { + // Tries to fetch Forwarded first since X-Forwarded can be lost by a proxy + // If Forwarded is not there tries to fetch the X-Forwarded-For header + // If none is found resorts to the remote address from the http request + + var forwardedHeaderValue = getForwardedHeaderValue(httpServerRequest); + if (forwardedHeaderValue != null) { + return forwardedHeaderValue; + } + var xForwardedHeaderValue = getXForwardedHeaderValue(httpServerRequest); + if (xForwardedHeaderValue != null) { + return xForwardedHeaderValue; + } + return httpServerRequest.remoteAddress() != null ? httpServerRequest.remoteAddress().host() : null; + } + + public static String extractRemoteHostname(HttpServerRequest httpRequest) { + String hostname = getHostHeader(httpRequest); + if (hostname != null) { + return hostname; + } + return httpRequest.remoteAddress() != null ? httpRequest.remoteAddress().hostName() : null; + } + + public static Long extractRemoteHostPort(HttpServerRequest httpRequest) { + String portString = getHostPortHeader(httpRequest); + if (portString != null) { + try { + return Long.parseLong(portString); + } catch (NumberFormatException e) { + //ignore + } + } + if (httpRequest.remoteAddress() != null) { + return Integer.toUnsignedLong(httpRequest.remoteAddress().port()); + } + return null; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/AdditionalServerAttributesExtractor.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/AdditionalServerAttributesExtractor.java new file mode 100644 index 000000000..a1606b29b --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/AdditionalServerAttributesExtractor.java @@ -0,0 +1,61 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import static io.opentelemetry.semconv.SemanticAttributes.CLIENT_ADDRESS; +import static io.opentelemetry.semconv.SemanticAttributes.HTTP_REQUEST_BODY_SIZE; +import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_BODY_SIZE; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpResponse; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpServerRequest; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.VertxUtil; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpHeaders; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class AdditionalServerAttributesExtractor implements AttributesExtractor { + + @Override + public void onStart( + final AttributesBuilder attributes, + final io.opentelemetry.context.Context parentContext, + final ObservableHttpRequest httpRequest + ) { + if (httpRequest instanceof ObservableHttpServerRequest observableServerObservableHttpRequest) { + String clientIp = VertxUtil.extractClientIP(observableServerObservableHttpRequest.httpServerRequest()); + if (clientIp != null) { + attributes.put(CLIENT_ADDRESS, clientIp); + } + } + } + + @Override + public void onEnd( + final AttributesBuilder attributes, + final io.opentelemetry.context.Context context, + final ObservableHttpRequest httpRequest, + final ObservableHttpResponse httpResponse, + final Throwable error + ) { + attributes.put(HTTP_REQUEST_BODY_SIZE, getContentLength(httpRequest.headers())); + if (httpResponse != null) { + attributes.put(HTTP_RESPONSE_BODY_SIZE, getContentLength(httpResponse.headers())); + } + } + + private static Long getContentLength(final MultiMap headers) { + String contentLength = headers.get(HttpHeaders.CONTENT_LENGTH); + if (contentLength != null && contentLength.length() > 0) { + try { + return Long.valueOf(contentLength); + } catch (NumberFormatException e) { + return null; + } + } else { + return null; + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ClientSpanNameExtractor.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ClientSpanNameExtractor.java new file mode 100644 index 000000000..9cf4a17de --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ClientSpanNameExtractor.java @@ -0,0 +1,30 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpClientRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; +import io.vertx.core.http.RequestOptions; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class ClientSpanNameExtractor implements SpanNameExtractor { + + private final SpanNameExtractor http; + + public ClientSpanNameExtractor(HttpClientAttributesExtractor clientAttributesExtractor) { + this.http = HttpSpanNameExtractor.create(clientAttributesExtractor); + } + + @Override + public String extract(ObservableHttpRequest httpRequest) { + if (httpRequest instanceof ObservableHttpClientRequest observableHttpClientRequest) { + RequestOptions requestOptions = observableHttpClientRequest.requestOptions(); + if (requestOptions.getTraceOperation() != null) { + return requestOptions.getTraceOperation(); + } + } + return http.extract(httpRequest); + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpClientAttributesExtractor.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpClientAttributesExtractor.java new file mode 100644 index 000000000..8434af164 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpClientAttributesExtractor.java @@ -0,0 +1,80 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpClientRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpResponse; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesGetter; +import io.vertx.core.http.HttpVersion; +import java.util.List; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class HttpClientAttributesExtractor implements HttpClientAttributesGetter { + + @Override + public String getUrlFull(final ObservableHttpRequest request) { + return request.absoluteURI(); + } + + @Override + public String getHttpRequestMethod(final ObservableHttpRequest request) { + return request.method().name(); + } + + @Override + public List getHttpRequestHeader(final ObservableHttpRequest request, final String name) { + return request.headers().getAll(name); + } + + @Override + public Integer getHttpResponseStatusCode(ObservableHttpRequest httpRequest, ObservableHttpResponse httpResponse, Throwable error) { + return httpResponse.statusCode(); + } + + @Override + public List getHttpResponseHeader( + final ObservableHttpRequest request, + final ObservableHttpResponse response, + final String name + ) { + return response.headers().getAll(name); + } + + @Override + public String getServerAddress(ObservableHttpRequest httpRequest) { + return httpRequest.remoteAddress() != null ? httpRequest.remoteAddress().hostName() : null; + } + + @Override + public Integer getServerPort(ObservableHttpRequest httpRequest) { + return httpRequest.remoteAddress() != null ? httpRequest.remoteAddress().port() : null; + } + + @Override + public String getNetworkProtocolName(final ObservableHttpRequest request, final ObservableHttpResponse response) { + return "http"; + } + + @Override + public String getNetworkProtocolVersion(final ObservableHttpRequest request, final ObservableHttpResponse response) { + return getHttpVersion(request); + } + + private String getHttpVersion(ObservableHttpRequest request) { + if (request instanceof ObservableHttpClientRequest observableHttpClientRequest) { + if (observableHttpClientRequest.httpClientRequest() != null) { + HttpVersion version = observableHttpClientRequest.httpClientRequest().version(); + if (version != null) { + return switch (version) { + case HTTP_1_0 -> "1.0"; + case HTTP_1_1 -> "1.1"; + case HTTP_2 -> "2.0"; + default -> version.alpnName(); // At that point version transformation will be needed for OTel semantics // Will be executed once Vert.x supports other versions + }; + } + } + } + return null; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapGetter.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapGetter.java new file mode 100644 index 000000000..de15b8762 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapGetter.java @@ -0,0 +1,33 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.opentelemetry.context.propagation.TextMapGetter; +import io.vertx.core.MultiMap; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class HttpRequestTextMapGetter implements TextMapGetter { + + @Override + public Iterable keys(final ObservableHttpRequest observableHttpRequest) { + MultiMap headers = observableHttpRequest.headers(); + if (headers != null) { + return headers.names(); + } + return null; + } + + @Override + public String get(final ObservableHttpRequest observableHttpRequest, final String key) { + if (observableHttpRequest == null) { + return null; + } + + MultiMap headers = observableHttpRequest.headers(); + if (headers != null) { + return headers.get(key); + } + return null; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapSetter.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapSetter.java new file mode 100644 index 000000000..0bb059299 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/HttpRequestTextMapSetter.java @@ -0,0 +1,17 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.opentelemetry.context.propagation.TextMapSetter; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class HttpRequestTextMapSetter implements TextMapSetter { + + @Override + public void set(final ObservableHttpRequest httpRequest, final String key, final String value) { + if (httpRequest != null && httpRequest.headers() != null) { + httpRequest.headers().set(key, value); + } + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/RouteGetter.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/RouteGetter.java new file mode 100644 index 000000000..2e850b541 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/RouteGetter.java @@ -0,0 +1,40 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpResponse; +import io.gravitee.node.opentelemetry.tracer.span.OpenTelemetrySpan; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBiGetter; +import io.vertx.core.spi.observability.HttpResponse; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class RouteGetter implements HttpServerRouteBiGetter, ObservableHttpResponse> { + + public static final RouteGetter INSTANCE = new RouteGetter(); + + @Override + public String get( + final io.opentelemetry.context.Context otelContext, + final OpenTelemetrySpan requestSpan, + final ObservableHttpResponse response + ) { + // RESTEasy + String route = requestSpan.vertxContext().getLocal("UrlPathTemplate"); + if (route == null) { + // Vert.x Router + route = requestSpan.vertxContext().getLocal("VertxRoute"); + } + + if (route != null && route.length() >= 1) { + return route; + } + + if (requestSpan.request() instanceof ObservableHttpRequest observableHttpRequest) { + return observableHttpRequest.uri(); + } + + return null; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ServerAttributesExtractor.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ServerAttributesExtractor.java new file mode 100644 index 000000000..addc53e57 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/instrumentation/vertx/extractor/ServerAttributesExtractor.java @@ -0,0 +1,101 @@ +package io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.extractor; + +import io.gravitee.node.api.opentelemetry.http.ObservableHttpRequest; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpResponse; +import io.gravitee.node.api.opentelemetry.http.ObservableHttpServerRequest; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.VertxUtil; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesGetter; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.spi.observability.HttpRequest; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; + +/** + * See HttpInstrumenterVertxTracer.java + */ +public class ServerAttributesExtractor implements HttpServerAttributesGetter { + + @Override + public String getNetworkProtocolName(ObservableHttpRequest request, ObservableHttpResponse response) { + return "http"; + } + + @Override + public String getNetworkPeerAddress(ObservableHttpRequest httpRequest, ObservableHttpResponse httpResponse) { + if (httpRequest instanceof ObservableHttpServerRequest observableServerHttpRequest) { + return VertxUtil.extractRemoteHostname(observableServerHttpRequest.httpServerRequest()); + } + return null; + } + + @Override + public Integer getNetworkPeerPort(ObservableHttpRequest httpRequest, ObservableHttpResponse httpResponse) { + if (httpRequest instanceof ObservableHttpServerRequest observableServerHttpRequest) { + Long remoteHostPort = VertxUtil.extractRemoteHostPort(observableServerHttpRequest.httpServerRequest()); + if (remoteHostPort == null) { + return null; + } + return remoteHostPort.intValue(); + } + return null; + } + + @Override + public String getUrlPath(final ObservableHttpRequest request) { + try { + URI uri = new URI(request.uri()); + return uri.getPath(); + } catch (URISyntaxException e) { + return null; + } + } + + @Override + public String getUrlQuery(ObservableHttpRequest request) { + try { + URI uri = new URI(request.uri()); + return uri.getQuery(); + } catch (URISyntaxException e) { + return null; + } + } + + @Override + public String getHttpRoute(final ObservableHttpRequest request) { + return null; + } + + @Override + public String getUrlScheme(final ObservableHttpRequest request) { + if (request instanceof ObservableHttpServerRequest observableServerHttpRequest) { + return observableServerHttpRequest.httpServerRequest().scheme(); + } + return null; + } + + @Override + public String getHttpRequestMethod(final ObservableHttpRequest request) { + return request.method().name(); + } + + @Override + public List getHttpRequestHeader(final ObservableHttpRequest request, final String name) { + return request.headers().getAll(name); + } + + @Override + public Integer getHttpResponseStatusCode(ObservableHttpRequest httpRequest, ObservableHttpResponse httpResponse, Throwable error) { + return httpResponse != null ? httpResponse.statusCode() : null; + } + + @Override + public List getHttpResponseHeader( + final ObservableHttpRequest request, + final ObservableHttpResponse response, + final String name + ) { + return response != null ? response.headers().getAll(name) : Collections.emptyList(); + } +} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/NoOpSpan.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpSpan.java similarity index 53% rename from gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/NoOpSpan.java rename to gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpSpan.java index 4a19ce886..791b0ad7b 100644 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/NoOpSpan.java +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpSpan.java @@ -1,11 +1,11 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,41 +13,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.gravitee.node.tracing; +package io.gravitee.node.opentelemetry.tracer.noop; -import io.gravitee.tracing.api.Span; +import io.gravitee.node.api.opentelemetry.Span; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; /** * @author David BRASSELY (david.brassely at graviteesource.com) * @author GraviteeSource Team */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class NoOpSpan implements Span { - @Override - public Span withAttribute(String name, String value) { - return this; - } + private final boolean root; - @Override - public Span withAttribute(String name, boolean value) { - return this; + public static Span asRoot() { + return new NoOpSpan(true); } - @Override - public Span withAttribute(String name, long value) { - return this; + public static Span asDefault() { + return new NoOpSpan(false); } @Override - public Span reportError(Throwable throwable) { - return this; + public boolean isRoot() { + return root; } @Override - public Span reportError(String message) { + public Span withAttribute(final String name, final T value) { return this; } - - @Override - public void end() {} } diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpTracer.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpTracer.java new file mode 100644 index 000000000..f1110087e --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/noop/NoOpTracer.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.tracer.noop; + +import io.gravitee.common.service.AbstractService; +import io.gravitee.node.api.opentelemetry.Span; +import io.gravitee.node.api.opentelemetry.Tracer; +import io.vertx.core.Context; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +public class NoOpTracer extends AbstractService implements Tracer { + + @Override + public Span startRootSpanFrom(final Context vertxContext, final R request) { + return NoOpSpan.asRoot(); + } + + @Override + public Span startSpanFrom(final Context vertxContext, final R request) { + return NoOpSpan.asDefault(); + } + + @Override + public Span startSpanWithParentFrom(final Context vertxContext, final Span parentSpan, final R request) { + return NoOpSpan.asDefault(); + } + + @Override + public void end(final Context vertxContext, final Span span) {} + + @Override + public void endOnError(final Context vertxContext, final Span span, final Throwable throwable) {} + + @Override + public void endOnError(final Context vertxContext, final Span span, final String message) {} + + @Override + public void endWithResponse(final Context vertxContext, final Span span, final R response) {} + + @Override + public void endWithResponseAndError(final Context vertxContext, final Span span, final R response, final Throwable throwable) {} + + @Override + public void endWithResponseAndError(final Context vertxContext, final Span span, final R response, final String message) {} +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/span/OpenTelemetrySpan.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/span/OpenTelemetrySpan.java new file mode 100644 index 000000000..b809e3aa2 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/span/OpenTelemetrySpan.java @@ -0,0 +1,84 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.tracer.span; + +import io.gravitee.node.api.opentelemetry.Span; +import io.opentelemetry.context.Scope; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@Slf4j +@Getter +@Accessors(fluent = true) +public class OpenTelemetrySpan implements Span { + + private final boolean root; + private final io.vertx.core.Context vertxContext; + private final io.opentelemetry.context.Context otelContext; + private final Scope scope; + private final R request; + + public OpenTelemetrySpan( + final io.vertx.core.Context vertxContext, + final io.opentelemetry.context.Context otelContext, + final io.opentelemetry.context.Scope scope, + final boolean root, + final R request + ) { + this.vertxContext = vertxContext; + this.otelContext = otelContext; + this.scope = scope; + this.root = root; + this.request = request; + } + + public R request() { + return request; + } + + public io.opentelemetry.api.trace.Span span() { + return io.opentelemetry.api.trace.Span.fromContext(otelContext()); + } + + @Override + public boolean isRoot() { + return root; + } + + @Override + public Span withAttribute(final String name, final T value) { + io.opentelemetry.api.trace.Span span = span(); + if (value != null) { + if (value instanceof String stringValue) { + span.setAttribute(name, stringValue); + } else if (value instanceof Long longValue) { + span.setAttribute(name, longValue); + } else if (value instanceof Integer integerValue) { + span.setAttribute(name, integerValue); + } else if (value instanceof Boolean booleanValue) { + span.setAttribute(name, booleanValue); + } else { + span.setAttribute(name, String.valueOf(value)); + } + } + return this; + } +} diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/vertx/VertxContextStorage.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/vertx/VertxContextStorage.java new file mode 100644 index 000000000..e7a3288d3 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/tracer/vertx/VertxContextStorage.java @@ -0,0 +1,110 @@ +package io.gravitee.node.opentelemetry.tracer.vertx; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextStorage; +import io.opentelemetry.context.Scope; +import io.smallrye.common.vertx.VertxContext; +import io.vertx.core.Vertx; +import lombok.extern.slf4j.Slf4j; + +/** + * See QuarkusContextStorage.java + */ +@Slf4j +public enum VertxContextStorage implements ContextStorage { + INSTANCE; + + private static final String OTEL_CONTEXT = VertxContextStorage.class.getName() + ".otelContext"; + + /** + * Attach the OpenTelemetry Context to the current Context. If a Vert.x Context is available, and it is a duplicated + * Vert.x Context the OpenTelemetry Context is attached to the Vert.x Context. Otherwise, fallback to the + * OpenTelemetry default ContextStorage. + * + * @param toAttach the OpenTelemetry Context to attach + * @return the Scope of the OpenTelemetry Context + */ + @Override + public Scope attach(Context toAttach) { + io.vertx.core.Context vertxContext = getVertxContext(); + return vertxContext != null && VertxContext.isDuplicatedContext(vertxContext) + ? attach(vertxContext, toAttach) + : ContextStorage.defaultStorage().attach(toAttach); + } + + /** + * Attach the OpenTelemetry Context in the Vert.x Context if it is a duplicated Vert.x Context. + * + * @param vertxContext the Vert.x Context to attach the OpenTelemetry Context + * @param toAttach the OpenTelemetry Context to attach + * @return the Scope of the OpenTelemetry Context + */ + public Scope attach(io.vertx.core.Context vertxContext, Context toAttach) { + if (vertxContext == null || toAttach == null) { + return Scope.noop(); + } + + // We don't allow to attach the OpenTelemetry Context to a Vert.x Context that is not a duplicate. + if (!VertxContext.isDuplicatedContext(vertxContext)) { + throw new IllegalArgumentException("The Vert.x Context to attach the OpenTelemetry Context must be a duplicated Context"); + } + + Context beforeAttach = getContext(vertxContext); + if (toAttach == beforeAttach) { + return Scope.noop(); + } + vertxContext.putLocal(OTEL_CONTEXT, toAttach); + + return () -> { + if (beforeAttach == null) { + vertxContext.removeLocal(OTEL_CONTEXT); + } else { + vertxContext.putLocal(OTEL_CONTEXT, beforeAttach); + } + }; + } + + /** + * Gets the current OpenTelemetry Context from the current Vert.x Context if one exists or from the default + * ContextStorage. The current Vert.x Context must be a duplicated Context. + * + * @return the current OpenTelemetry Context or null. + */ + @Override + public Context current() { + io.vertx.core.Context current = getVertxContext(); + if (current != null) { + return current.getLocal(OTEL_CONTEXT); + } else { + return ContextStorage.defaultStorage().current(); + } + } + + /** + * Gets the OpenTelemetry Context in a Vert.x Context. The Vert.x Context has to be a duplicate context. + * + * @param vertxContext a Vert.x Context. + * @return the OpenTelemetry Context if exists in the Vert.x Context or null. + */ + public static Context getContext(io.vertx.core.Context vertxContext) { + return vertxContext != null && VertxContext.isDuplicatedContext(vertxContext) ? vertxContext.getLocal(OTEL_CONTEXT) : null; + } + + /** + * Gets the current duplicated context or a new duplicated context if a Vert.x Context exists. Multiple invocations + * of this method may return the same or different context. If the current context is a duplicate one, multiple + * invocations always return the same context. If the current context is not duplicated, a new instance is returned + * with each method invocation. + * + * @return a duplicated Vert.x Context or null. + */ + public static io.vertx.core.Context getVertxContext() { + io.vertx.core.Context context = Vertx.currentContext(); + if (context != null && VertxContext.isOnDuplicatedContext()) { + return context; + } else if (context != null) { + return VertxContext.createNewDuplicatedContext(context); + } + return null; + } +} diff --git a/gravitee-node-opentelemetry/src/main/resources/META-INF/io.opentelemetry.context.ContextStorageProvider b/gravitee-node-opentelemetry/src/main/resources/META-INF/io.opentelemetry.context.ContextStorageProvider new file mode 100644 index 000000000..32f10e9fe --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/resources/META-INF/io.opentelemetry.context.ContextStorageProvider @@ -0,0 +1 @@ +io.gravitee.node.opentelemetry.tracer.vertx.VertxContextStorage \ No newline at end of file diff --git a/gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/OpenTelemetryTracerIntegrationTest.java b/gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/OpenTelemetryTracerIntegrationTest.java new file mode 100644 index 000000000..502892f9b --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/OpenTelemetryTracerIntegrationTest.java @@ -0,0 +1,426 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.gravitee.node.api.opentelemetry.internal.InternalRequest; +import io.gravitee.node.opentelemetry.configuration.OpenTelemetryConfiguration; +import io.gravitee.node.opentelemetry.configuration.Protocol; +import io.gravitee.node.opentelemetry.exporter.ExporterFactory; +import io.gravitee.node.opentelemetry.testcontainers.JaegerAllInOne; +import io.gravitee.node.opentelemetry.tracer.instrumentation.internal.InternalInstrumenterTracerFactory; +import io.gravitee.node.opentelemetry.tracer.instrumentation.vertx.VertxHttpInstrumenterTracerFactory; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.smallrye.common.vertx.VertxContext; +import io.vertx.core.Context; +import io.vertx.core.Vertx; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import io.vertx.junit5.VertxExtension; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import lombok.NonNull; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.env.MockEnvironment; +import org.testcontainers.containers.BindMode; + +@ExtendWith(value = { MockitoExtension.class, VertxExtension.class }) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +public class OpenTelemetryTracerIntegrationTest { + + private static final String JAEGER_DOCKER_IMAGE = "jaegertracing/all-in-one:1.62.0"; + private static final JaegerAllInOne container = new JaegerAllInOne(JAEGER_DOCKER_IMAGE); + private static final JaegerAllInOne containerTLS = new JaegerAllInOne(JAEGER_DOCKER_IMAGE) + .withClasspathResourceMapping("ssl/ca.pem", "/certs/ca.pem", BindMode.READ_WRITE) + .withClasspathResourceMapping("ssl/server.jaeger.crt", "/certs/server.jaeger.crt", BindMode.READ_WRITE) + .withClasspathResourceMapping("ssl/server.jaeger.key", "/certs/server.jaeger.key", BindMode.READ_WRITE) + .withClasspathResourceMapping("ssl/client.cer", "/certs/client.cer", BindMode.READ_WRITE) + .withClasspathResourceMapping("ssl/client.key", "/certs/client.key", BindMode.READ_WRITE) + .withEnv( + Map.ofEntries( + Map.entry("COLLECTOR_OTLP_GRPC_TLS_ENABLED", "true"), + Map.entry("COLLECTOR_OTLP_GRPC_TLS_CLIENT_CA", "/certs/ca.pem"), + Map.entry("COLLECTOR_OTLP_GRPC_TLS_CERT", "/certs/server.jaeger.crt"), + Map.entry("COLLECTOR_OTLP_GRPC_TLS_KEY", "/certs/server.jaeger.key"), + Map.entry("COLLECTOR_OTLP_HTTP_TLS_ENABLED", "true"), + Map.entry("COLLECTOR_OTLP_HTTP_TLS_CLIENT_CA", "/certs/ca.pem"), + Map.entry("COLLECTOR_OTLP_HTTP_TLS_CERT", "/certs/server.jaeger.crt"), + Map.entry("COLLECTOR_OTLP_HTTP_TLS_KEY", "/certs/server.jaeger.key") + ) + ); + + @BeforeAll + void beforeAll() { + container.start(); + containerTLS.start(); + } + + @AfterAll + void afterAll() { + container.stop(); + containerTLS.stop(); + } + + @BeforeEach + void beforeEach() { + GlobalOpenTelemetry.resetForTest(); + } + + @Test + void should_connect_to_jaeger_over_grpc(Vertx vertx) throws Exception { + var openTelemetryConfiguration = OpenTelemetryConfiguration + .builder() + .endpoint("http://localhost:" + container.getCollectorGrpcPort()) + .tracesEnabled(true) + .protocol(Protocol.GRPC.value()) + .environment(new MockEnvironment()) + .build(); + + var serviceName = "jaeger_grpc_unsecured"; + + OpenTelemetryFactory openTelemetryFactory = openTelemetryFactory(vertx, openTelemetryConfiguration); + var tracer = openTelemetryFactory.createTracer( + "serviceInstanceId", + serviceName, + "serviceNamespace", + "serviceVersion", + List.of(new VertxHttpInstrumenterTracerFactory(), new InternalInstrumenterTracerFactory()) + ); + tracer.start(); + + Context vertxContext = vertx.getOrCreateContext(); + Context duplicatedContext = VertxContext.createNewDuplicatedContext(vertxContext); + duplicatedContext.runOnContext(v -> { + var span = tracer.startSpanFrom(duplicatedContext, new InternalRequest("my-span", Map.of("custom", "value"))); + tracer.end(duplicatedContext, span); + }); + + await() + .atMost(30, SECONDS) + .untilAsserted(() -> { + var client = container.client(vertx); + var response = client + .get("/api/traces") + .addQueryParam("service", serviceName) + .send() + .toCompletionStage() + .toCompletableFuture() + .get(); + + assertThat(response.statusCode()).isEqualTo(200); + assertData(response.bodyAsJsonObject()); + }); + } + + @NonNull + private static OpenTelemetryFactory openTelemetryFactory( + final Vertx vertx, + final OpenTelemetryConfiguration openTelemetryConfiguration + ) { + return new OpenTelemetryFactory(openTelemetryConfiguration, new ExporterFactory(openTelemetryConfiguration, vertx)); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("generator") + void should_connect_to_a_secure_jaeger_over_grpc(String name, JsonObject sslConfig, Vertx vertx) throws Exception { + var keyStore = sslConfig.getJsonObject("keyStore"); + var trustStore = sslConfig.getJsonObject("trustStore"); + + var environment = new MockEnvironment(); + if (keyStore.getString("type").equals("PEM")) { + environment.withProperty("services.tracing.otel.ssl.keystore.certs[0]", keyStore.getString("cert")); + environment.withProperty("services.tracing.otel.ssl.keystore.keys[0]", keyStore.getString("key")); + } + + var openTelemetryConfiguration = OpenTelemetryConfiguration + .builder() + .environment(environment) + .keystoreType(keyStore.getString("type")) + .keystorePath(keyStore.getString("path")) + .keystorePassword(keyStore.getString("password")) + .truststoreType(trustStore.getString("type")) + .truststorePath(trustStore.getString("path")) + .truststorePassword(trustStore.getString("password")) + .endpoint("https://localhost:" + containerTLS.getCollectorGrpcPort()) + .tracesEnabled(true) + .protocol(Protocol.GRPC.value()) + .build(); + + var serviceName = "otel_grpc_" + keyStore.getString("type"); + OpenTelemetryFactory openTelemetryFactory = openTelemetryFactory(vertx, openTelemetryConfiguration); + + var tracer = openTelemetryFactory.createTracer( + "serviceInstanceId", + serviceName, + "serviceNamespace", + "serviceVersion", + List.of(new VertxHttpInstrumenterTracerFactory(), new InternalInstrumenterTracerFactory()) + ); + tracer.start(); + + Context vertxContext = vertx.getOrCreateContext(); + Context duplicatedContext = VertxContext.createNewDuplicatedContext(vertxContext); + duplicatedContext.runOnContext(v -> { + var span = tracer.startSpanFrom(duplicatedContext, new InternalRequest("my-span", Map.of("custom", "value"))); + tracer.end(duplicatedContext, span); + }); + + await() + .atMost(30, SECONDS) + .untilAsserted(() -> { + var client = containerTLS.client(vertx); + var response = client + .get("/api/traces") + .addQueryParam("service", serviceName) + .send() + .toCompletionStage() + .toCompletableFuture() + .get(); + + assertThat(response.statusCode()).isEqualTo(200); + assertData(response.bodyAsJsonObject()); + }); + } + + @Test + void should_connect_to_jaeger_over_http(Vertx vertx) throws Exception { + var openTelemetryConfiguration = OpenTelemetryConfiguration + .builder() + .endpoint("http://localhost:" + container.getCollectorHttpPort()) + .tracesEnabled(true) + .protocol(Protocol.HTTP_PROTOBUF.value()) + .environment(new MockEnvironment()) + .build(); + + var serviceName = "jaeger_http_unsecured"; + OpenTelemetryFactory openTelemetryFactory = openTelemetryFactory(vertx, openTelemetryConfiguration); + var tracer = openTelemetryFactory.createTracer( + "serviceInstanceId", + serviceName, + "serviceNamespace", + "serviceVersion", + List.of(new VertxHttpInstrumenterTracerFactory(), new InternalInstrumenterTracerFactory()) + ); + tracer.start(); + + Context vertxContext = vertx.getOrCreateContext(); + Context duplicatedContext = VertxContext.createNewDuplicatedContext(vertxContext); + duplicatedContext.runOnContext(v -> { + var span = tracer.startSpanFrom(duplicatedContext, new InternalRequest("my-span", Map.of("custom", "value"))); + tracer.end(duplicatedContext, span); + }); + + await() + .atMost(30, SECONDS) + .untilAsserted(() -> { + var client = container.client(vertx); + var response = client + .get("/api/traces") + .addQueryParam("service", serviceName) + .send() + .toCompletionStage() + .toCompletableFuture() + .get(); + + assertThat(response.statusCode()).isEqualTo(200); + assertData(response.bodyAsJsonObject()); + }); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("generator") + void should_connect_to_a_secure_jaeger_over_http(String name, JsonObject sslConfig, Vertx vertx) throws Exception { + var keyStore = sslConfig.getJsonObject("keyStore"); + var trustStore = sslConfig.getJsonObject("trustStore"); + + var environment = new MockEnvironment(); + if (keyStore.getString("type").equals("PEM")) { + environment.withProperty("services.tracing.otel.ssl.keystore.certs[0]", keyStore.getString("cert")); + environment.withProperty("services.tracing.otel.ssl.keystore.keys[0]", keyStore.getString("key")); + } + + var openTelemetryConfiguration = OpenTelemetryConfiguration + .builder() + .environment(environment) + .keystoreType(keyStore.getString("type")) + .keystorePath(keyStore.getString("path")) + .keystorePassword(keyStore.getString("password")) + .truststoreType(trustStore.getString("type")) + .truststorePath(trustStore.getString("path")) + .truststorePassword(trustStore.getString("password")) + .endpoint("https://localhost:" + containerTLS.getCollectorHttpPort()) + .tracesEnabled(true) + .protocol(Protocol.HTTP_PROTOBUF.value()) + .build(); + + var serviceName = "otel_http_" + keyStore.getString("type"); + OpenTelemetryFactory openTelemetryFactory = openTelemetryFactory(vertx, openTelemetryConfiguration); + var tracer = openTelemetryFactory.createTracer( + "serviceInstanceId", + serviceName, + "serviceNamespace", + "serviceVersion", + List.of(new VertxHttpInstrumenterTracerFactory(), new InternalInstrumenterTracerFactory()) + ); + tracer.start(); + + Context vertxContext = vertx.getOrCreateContext(); + Context duplicatedContext = VertxContext.createNewDuplicatedContext(vertxContext); + duplicatedContext.runOnContext(v -> { + var span = tracer.startSpanFrom(duplicatedContext, new InternalRequest("my-span", Map.of("custom", "value"))); + tracer.end(duplicatedContext, span); + }); + + await() + .atMost(30, SECONDS) + .untilAsserted(() -> { + var client = containerTLS.client(vertx); + var response = client + .get("/api/traces") + .addQueryParam("service", serviceName) + .send() + .toCompletionStage() + .toCompletableFuture() + .get(); + + assertThat(response.statusCode()).isEqualTo(200); + assertData(response.bodyAsJsonObject()); + }); + } + + private static Stream generator() { + return Stream.of( + Arguments.of( + "using a jks file", + new JsonObject( + Map.ofEntries( + Map.entry( + "keyStore", + new JsonObject( + Map.ofEntries( + Map.entry("type", "JKS"), + Map.entry("path", "src/test/resources/ssl/client-keystore.jks"), + Map.entry("password", "gravitee"), + Map.entry("alias", "jaeger-client") + ) + ) + ), + Map.entry( + "trustStore", + new JsonObject( + Map.ofEntries( + Map.entry("type", "JKS"), + Map.entry("path", "src/test/resources/ssl/client-truststore.jks"), + Map.entry("password", "gravitee") + ) + ) + ) + ) + ) + ), + Arguments.of( + "using a PKCS12 file", + new JsonObject( + Map.ofEntries( + Map.entry( + "keyStore", + new JsonObject( + Map.ofEntries( + Map.entry("type", "PKCS12"), + Map.entry("path", "src/test/resources/ssl/client-keystore.p12"), + Map.entry("password", "gravitee"), + Map.entry("alias", "jaeger-client") + ) + ) + ), + Map.entry( + "trustStore", + new JsonObject( + Map.ofEntries( + Map.entry("type", "PKCS12"), + Map.entry("path", "src/test/resources/ssl/client-truststore.p12"), + Map.entry("password", "gravitee") + ) + ) + ) + ) + ) + ), + Arguments.of( + "using a PEM file", + new JsonObject( + Map.ofEntries( + Map.entry( + "keyStore", + new JsonObject( + Map.ofEntries( + Map.entry("type", "PEM"), + Map.entry("cert", "src/test/resources/ssl/client.cer"), + Map.entry("key", "src/test/resources/ssl/client.key") + ) + ) + ), + Map.entry( + "trustStore", + new JsonObject( + Map.ofEntries( + Map.entry("type", "PEM"), + Map.entry("path", "src/test/resources/ssl/client-truststore.pem"), + Map.entry("password", "gravitee") + ) + ) + ) + ) + ) + ) + ); + } + + private void assertData(JsonObject json) { + var data = json.getJsonArray("data"); + assertThat(data).isNotEmpty(); + + var trace = data.getJsonObject(0); + var spans = trace.getJsonArray("spans"); + assertThat(spans).isNotEmpty(); + + var span = spans.getJsonObject(0); + assertThat(span.getString("operationName")).isEqualTo("my-span"); + JsonArray tags = span.getJsonArray("tags"); + JsonObject customTags = tags.getJsonObject(0); + assertThat(customTags.getString("key")).isEqualTo("custom"); + assertThat(customTags.getString("value")).isEqualTo("value"); + JsonObject spanKind = tags.getJsonObject(3); + assertThat(spanKind.getString("key")).isEqualTo("span.kind"); + assertThat(spanKind.getString("value")).isEqualTo("internal"); + } +} diff --git a/gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/testcontainers/JaegerAllInOne.java b/gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/testcontainers/JaegerAllInOne.java new file mode 100644 index 000000000..1b4837b26 --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/java/io/gravitee/node/opentelemetry/testcontainers/JaegerAllInOne.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.node.opentelemetry.testcontainers; + +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +public class JaegerAllInOne extends GenericContainer { + + public static final int JAEGER_COLLECTOR_GRPC_PORT = 4317; + public static final int JAEGER_COLLECTOR_HTTP_PORT = 4318; + public static final int JAEGER_ADMIN_PORT = 14269; + public static final int JAEGER_FRONTEND_PORT = 16686; + + public JaegerAllInOne(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public JaegerAllInOne(DockerImageName imageName) { + super(imageName); + setWaitStrategy(Wait.forHttp("/").forPort(JAEGER_ADMIN_PORT).forStatusCode(200)); + withExposedPorts(JAEGER_ADMIN_PORT, JAEGER_COLLECTOR_GRPC_PORT, JAEGER_COLLECTOR_HTTP_PORT, JAEGER_FRONTEND_PORT); + } + + public WebClient client(Vertx vertx) { + return WebClient.create(vertx, new WebClientOptions().setDefaultHost(getHost()).setDefaultPort(getJaegerFrontendPort())); + } + + public int getCollectorGrpcPort() { + return getMappedPort(JAEGER_COLLECTOR_GRPC_PORT); + } + + public int getCollectorHttpPort() { + return getMappedPort(JAEGER_COLLECTOR_HTTP_PORT); + } + + public int getJaegerFrontendPort() { + return getMappedPort(JAEGER_FRONTEND_PORT); + } +} diff --git a/gravitee-node-opentelemetry/src/test/resources/logback-test.xml b/gravitee-node-opentelemetry/src/test/resources/logback-test.xml new file mode 100644 index 000000000..e619b2d0a --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + %d{HH:mm:ss.SSS} %-5level: [%thread] [%logger{20}] : %msg%n + + + + + + + + + + diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/ca.key b/gravitee-node-opentelemetry/src/test/resources/ssl/ca.key new file mode 100755 index 000000000..b8f46bf3a --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/ca.key @@ -0,0 +1,54 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +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 +8MRg/uQoOlNWc4QKgpJHfeOkTUW4xwmE +-----END ENCRYPTED PRIVATE KEY----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/ca.pem b/gravitee-node-opentelemetry/src/test/resources/ssl/ca.pem new file mode 100755 index 000000000..9755b00eb --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/ca.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGDTCCA/WgAwIBAgIUUf6xiCCW3JtMajRPdT/9G+k5xBowDQYJKoZIhvcNAQEL +BQAwgZUxKTAnBgkqhkiG9w0BCQEWGmNvbnRhY3RAZ3Jhdml0ZWVzb3VyY2UuY29t +MRIwEAYDVQQDDAlqYWVnZXItY2ExDTALBgNVBAsMBEFQSU0xFzAVBgNVBAoMDkdy +YXZpdGVlU291cmNlMQ4wDAYDVQQHDAVMaWxsZTEPMA0GA1UECAwGRnJhbmNlMQsw +CQYDVQQGEwJGUjAeFw0yNDA2MTQwODQ1MDdaFw0zNDA2MTIwODQ1MDdaMIGVMSkw +JwYJKoZIhvcNAQkBFhpjb250YWN0QGdyYXZpdGVlc291cmNlLmNvbTESMBAGA1UE +AwwJamFlZ2VyLWNhMQ0wCwYDVQQLDARBUElNMRcwFQYDVQQKDA5HcmF2aXRlZVNv +dXJjZTEOMAwGA1UEBwwFTGlsbGUxDzANBgNVBAgMBkZyYW5jZTELMAkGA1UEBhMC +RlIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCQTWPOPKmSLJrYjGMs +q98wFG1sUxJBTxqsPMcBiUTWh8FhNX7tdSxJadJ/d8DWy1FmJAO9Y/0q0h1VZsa1 +i/iWv61WQV6B923cWpedcAJa9SGpeb7uXk5Gx8lEIbgLaZ+TX04xcOSNVLO9q+Ti +BwHCbC4wexlMvgvGPaBh1cXhy9oNN/ZsM0wukE1rfoyNd4S7KEoc1FUDtAKndS/J +LOPQujdx9Y7ThXQmvL09M7ntqDigbBdBvaqrQFhKnTYGfJFfOmdZjH/mLujxKEOV +wrcu524FYD334LHGk9SrsMuxA+cZfq6uZgLFBDDMiSD7aEi/psfK9rtx5CxofTXQ +nuaB31wk6/XmollSDui5UCKBQwhOo6EbN5sBGL6nrb5+fRKWh9D1+XOuvSNvqMZ6 +MEK5jnH94OuiL38Z0WDXSJ3iXWA1cgXoN0kKuEx+DEmtxjUT9ncA/YCUEcyjLpXz +pJXE7gEl4S2+6D/ZRWHwfMUSIhUSQk+JlokWpiNE8zkGWqwWkRPW/WplBl8r54LQ +KNKs4Rg28GgvfnsqRuQfMfvaiDC4c1jQzz3erOYBJRhDix8KFaSPlYsjA9kfmB8A +Vlb3ljPyyd3P/QjBbQFISacIEW4JVTdy1lzXCDe1mkblYxW4IfDvLgvKSXNbLHzY +hU2RKP1z2ojFqh2DE2hbYLzeDQIDAQABo1MwUTAdBgNVHQ4EFgQUp1xiyFFi+WVA +hKRVv1DgG6dxbtAwHwYDVR0jBBgwFoAUp1xiyFFi+WVAhKRVv1DgG6dxbtAwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEADo0H8QHNBrZoBvqkZV3o +kAe+oMKThFx5E8xXgmecbY2ZWJwgpu4EQ8s/lQYjbNZBp7gRWIdWUXjQvzdy66v9 +ZmYg3j8CCiN4kwnMBegJqQlUpeu0nKd8P59Y3EPt2D53n4Ar026fZFlxgZnrUecA +3RbxoHOFCzdhG8OPf1HoYlXdkpoXfT81h2xaH50u/seFkE49TdDhoiCNrNhj/B9A +TVZ7QSUJetRejk4rKIMdKsNVgzFZalVxbyhbXWUriUwtXTJkBSEQqBvcbdivvH4+ +UROFyR1bp7lRjp/ARAHzEDahWnsib7V83oaYtLuZaeA8vDXVQGwRy/5XNml7sdeP +NkFJms3F9qbkKdyn0kH86/2uezTkdoHXJuKnnKpv8TLNGt4oteTSvWiHqgSCFkx2 +0tdc7LYMtImu0QkU50hOAPfNo1jafAdlmNiXI9aFNjl/gy6wsB8kzLVMunqvPo58 +NMiZt4aycYun5mMM+uo7/kx29ayHKVJL4VJhzgiEfBj26QxYdjzmamj3XDpJxvI4 +cs0Senavi1tesXfb6HxREqDPqk0LdAp6SochykescRGksL7ehbPd8GqcVmFaC2Et +TB6jpXplqNmMzQb6jsCW2ECI2tZMO6BWorl6fssiP73Dk9SUKawALAWQ2P/4XtDW +oijpazzv+p0OF1uaxPv7ywc= +-----END CERTIFICATE----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client-keystore.jks b/gravitee-node-opentelemetry/src/test/resources/ssl/client-keystore.jks new file mode 100755 index 0000000000000000000000000000000000000000..57549513fdeb57efbcc4292ac633a3b624ec67d6 GIT binary patch literal 3907 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 literal 0 HcmV?d00001 diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client-keystore.p12 b/gravitee-node-opentelemetry/src/test/resources/ssl/client-keystore.p12 new file mode 100755 index 0000000000000000000000000000000000000000..33fdd7d9d0fc7ef0613cc32b181ac49dd2c30342 GIT binary patch literal 4398 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 PSnaVfPP{h$?^XC8Q_&ec literal 0 HcmV?d00001 diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.jks b/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.jks new file mode 100755 index 0000000000000000000000000000000000000000..05990cf91bf46f373f712305b800e51f910ce14c GIT binary patch literal 3102 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 Ye1hc@zL+DlMFZ$iYi>nT*0K`+@0rQ|B>(^b literal 0 HcmV?d00001 diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.p12 b/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.p12 new file mode 100755 index 0000000000000000000000000000000000000000..fb672ee3876f0814c662b4977945a2acf789587d GIT binary patch literal 3494 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 UDr(5rYj;9nmcPcvnF0bQ5b58YJpcdz literal 0 HcmV?d00001 diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.pem b/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.pem new file mode 100755 index 000000000..c456d2902 --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/client-truststore.pem @@ -0,0 +1,78 @@ +Bag Attributes + friendlyName: jaeger-ca + Trusted key usage (Oracle): Any Extended Key Usage (2.5.29.37.0) +subject=emailAddress=contact@graviteesource.com, CN=jaeger-ca, OU=APIM, O=GraviteeSource, L=Lille, ST=France, C=FR +issuer=emailAddress=contact@graviteesource.com, CN=jaeger-ca, OU=APIM, O=GraviteeSource, L=Lille, ST=France, C=FR +-----BEGIN CERTIFICATE----- +MIIGDTCCA/WgAwIBAgIUUf6xiCCW3JtMajRPdT/9G+k5xBowDQYJKoZIhvcNAQEL +BQAwgZUxKTAnBgkqhkiG9w0BCQEWGmNvbnRhY3RAZ3Jhdml0ZWVzb3VyY2UuY29t +MRIwEAYDVQQDDAlqYWVnZXItY2ExDTALBgNVBAsMBEFQSU0xFzAVBgNVBAoMDkdy +YXZpdGVlU291cmNlMQ4wDAYDVQQHDAVMaWxsZTEPMA0GA1UECAwGRnJhbmNlMQsw +CQYDVQQGEwJGUjAeFw0yNDA2MTQwODQ1MDdaFw0zNDA2MTIwODQ1MDdaMIGVMSkw +JwYJKoZIhvcNAQkBFhpjb250YWN0QGdyYXZpdGVlc291cmNlLmNvbTESMBAGA1UE +AwwJamFlZ2VyLWNhMQ0wCwYDVQQLDARBUElNMRcwFQYDVQQKDA5HcmF2aXRlZVNv +dXJjZTEOMAwGA1UEBwwFTGlsbGUxDzANBgNVBAgMBkZyYW5jZTELMAkGA1UEBhMC +RlIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCQTWPOPKmSLJrYjGMs +q98wFG1sUxJBTxqsPMcBiUTWh8FhNX7tdSxJadJ/d8DWy1FmJAO9Y/0q0h1VZsa1 +i/iWv61WQV6B923cWpedcAJa9SGpeb7uXk5Gx8lEIbgLaZ+TX04xcOSNVLO9q+Ti +BwHCbC4wexlMvgvGPaBh1cXhy9oNN/ZsM0wukE1rfoyNd4S7KEoc1FUDtAKndS/J +LOPQujdx9Y7ThXQmvL09M7ntqDigbBdBvaqrQFhKnTYGfJFfOmdZjH/mLujxKEOV +wrcu524FYD334LHGk9SrsMuxA+cZfq6uZgLFBDDMiSD7aEi/psfK9rtx5CxofTXQ +nuaB31wk6/XmollSDui5UCKBQwhOo6EbN5sBGL6nrb5+fRKWh9D1+XOuvSNvqMZ6 +MEK5jnH94OuiL38Z0WDXSJ3iXWA1cgXoN0kKuEx+DEmtxjUT9ncA/YCUEcyjLpXz +pJXE7gEl4S2+6D/ZRWHwfMUSIhUSQk+JlokWpiNE8zkGWqwWkRPW/WplBl8r54LQ +KNKs4Rg28GgvfnsqRuQfMfvaiDC4c1jQzz3erOYBJRhDix8KFaSPlYsjA9kfmB8A +Vlb3ljPyyd3P/QjBbQFISacIEW4JVTdy1lzXCDe1mkblYxW4IfDvLgvKSXNbLHzY +hU2RKP1z2ojFqh2DE2hbYLzeDQIDAQABo1MwUTAdBgNVHQ4EFgQUp1xiyFFi+WVA +hKRVv1DgG6dxbtAwHwYDVR0jBBgwFoAUp1xiyFFi+WVAhKRVv1DgG6dxbtAwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEADo0H8QHNBrZoBvqkZV3o +kAe+oMKThFx5E8xXgmecbY2ZWJwgpu4EQ8s/lQYjbNZBp7gRWIdWUXjQvzdy66v9 +ZmYg3j8CCiN4kwnMBegJqQlUpeu0nKd8P59Y3EPt2D53n4Ar026fZFlxgZnrUecA +3RbxoHOFCzdhG8OPf1HoYlXdkpoXfT81h2xaH50u/seFkE49TdDhoiCNrNhj/B9A +TVZ7QSUJetRejk4rKIMdKsNVgzFZalVxbyhbXWUriUwtXTJkBSEQqBvcbdivvH4+ +UROFyR1bp7lRjp/ARAHzEDahWnsib7V83oaYtLuZaeA8vDXVQGwRy/5XNml7sdeP +NkFJms3F9qbkKdyn0kH86/2uezTkdoHXJuKnnKpv8TLNGt4oteTSvWiHqgSCFkx2 +0tdc7LYMtImu0QkU50hOAPfNo1jafAdlmNiXI9aFNjl/gy6wsB8kzLVMunqvPo58 +NMiZt4aycYun5mMM+uo7/kx29ayHKVJL4VJhzgiEfBj26QxYdjzmamj3XDpJxvI4 +cs0Senavi1tesXfb6HxREqDPqk0LdAp6SochykescRGksL7ehbPd8GqcVmFaC2Et +TB6jpXplqNmMzQb6jsCW2ECI2tZMO6BWorl6fssiP73Dk9SUKawALAWQ2P/4XtDW +oijpazzv+p0OF1uaxPv7ywc= +-----END CERTIFICATE----- +Bag Attributes + friendlyName: jaeger-server + Trusted key usage (Oracle): Any Extended Key Usage (2.5.29.37.0) +subject=CN=server.jaeger +issuer=emailAddress=contact@graviteesource.com, CN=jaeger-ca, OU=APIM, O=GraviteeSource, L=Lille, ST=France, C=FR +-----BEGIN CERTIFICATE----- +MIIFoTCCA4mgAwIBAgIBZDANBgkqhkiG9w0BAQsFADCBlTEpMCcGCSqGSIb3DQEJ +ARYaY29udGFjdEBncmF2aXRlZXNvdXJjZS5jb20xEjAQBgNVBAMMCWphZWdlci1j +YTENMAsGA1UECwwEQVBJTTEXMBUGA1UECgwOR3Jhdml0ZWVTb3VyY2UxDjAMBgNV +BAcMBUxpbGxlMQ8wDQYDVQQIDAZGcmFuY2UxCzAJBgNVBAYTAkZSMB4XDTI0MDYx +NDA4NDUwN1oXDTI4MDYxMzA4NDUwN1owGDEWMBQGA1UEAwwNc2VydmVyLmphZWdl +cjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKq/ZeZqWwefww26jYW5 +HTkUMvSxbPsAfopr0Nc81KkiQQWXwt5nGIsKDObJl6gT6vXKjc4xTQQq1GNX3Xzx +pI2NqgodHGESncO9QH2Q2utbXu5CX6JLzgn4yz0bSTZaCYOi9FSs3v2sIqXnRww1 +rXDHb2hbBJ2WG78FUD+PmRjvR+1bpO1s4xO7RrX2ceZIFpAJ4eWsS5u9M4ZsU+eG +CEIoBvBsx14tXGwLEjWXCHxnUQxPr3d4soUA0dESmeII8RM9Fcfs/vOheXzm4KYA +Y2njhFto1PbfrRdkrL5eWhBlAB0Cpx6L/5gWTSkcOzFg1p4TXFkzIoh/dgTKef1K +MKR8GYAHvB1UbjZRuu2dg9i5jT+YJHSUKTQ66I6vBO35YwIsJDJJEBXU1UdKOohe +TUHnCoDagQMIn9Mf0p+C+b5MripZZjPE8cJXaQFyFLN/h4PzRmekOopmnBX+brbT +3TQAzQds8gaN5lC4975XchrdQ7Yet4n3EKtEA78W3tLS8W8mZVUAtErH+sEu3eoi +Fa9qNHzW93w3HwkgxYGct9ZUsgYA3I2E4OMlmy74JYr2jbYhLgNNl0qL2X7cOJ/2 +P9+KbeFx2xuMartYzaMaVbohNj/fwCzP6NEtActjA8knQ/ktzF8c8EElTFqXT946 +VUQJTzTIXVEjTKurhPl1TTXjAgMBAAGjeDB2MAkGA1UdEwQCMAAwKQYDVR0RBCIw +IIINc2VydmVyLmphZWdlcoIJbG9jYWxob3N0hwR/AAABMB0GA1UdDgQWBBSeS4gR +T7cW729LgmdMmkcfQcdoITAfBgNVHSMEGDAWgBSnXGLIUWL5ZUCEpFW/UOAbp3Fu +0DANBgkqhkiG9w0BAQsFAAOCAgEAhxibPKbPVdn3GnmGVVrTxS45etqOqem5OlK6 +9x1cX/KZhC3VPad43Htg8MwHaVe3wlNGwJb4voXUnf3lOrZ//LR4ZWvZWDbQr/JV +7a3MJmMo/VcInbLSh97E61hQRN3NmvbmkOt2LYtgAm6JSrrE+dIJZ4nJqp6MRSjB +nwT5o6PRWI1gi2n+QqYFNj9CXyjQHeO76vLNJExZLNCR3APuhAJraoa96ejaNpbA +cpoG8+CbzS4T94W1vriIRkfVhnSKHxFuFjIu15c0I0OjIJarI3T/lPiv48H9ClE1 +nsA33YL5iuWlrW7qzJx2rcqBGtFc5P+lQK2SywqaqyxTeuYEvQEQIKJ1sXVJIvkO +K04eib2VyOWhWDW1OKvl95+7gKjEUrAejh/OIKNhlJNrU6+AoD97nDyi8qqJcnyT +5yRGxJ1av5dhi30CV/MR/fR69INyGTWl47ooQ3blZwt0Za2M6uJEOHSZNyeV7bjg +qcp0U8dKoNJPmvcVqkUpJ+S/SCm8kPxeiUK4y+6zz3UZaKPh7O2JwjGwJVn8+lVb +2mV3FPwd3Un2wVucRfrgI+jpwLs3NbIUDIkNlYZ/V9VEbMYxANwlWDJ2ZLLNdaFc +iV6/1oo4qGyrGwPBoloMVsEXdAiTuEFtc9SfAaPL9oKkSZxBlZv2ECqNspVuOaaP +f99BFp8= +-----END CERTIFICATE----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client.cer b/gravitee-node-opentelemetry/src/test/resources/ssl/client.cer new file mode 100755 index 000000000..4239dc00e --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/client.cer @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIBZTANBgkqhkiG9w0BAQsFADCBlTEpMCcGCSqGSIb3DQEJ +ARYaY29udGFjdEBncmF2aXRlZXNvdXJjZS5jb20xEjAQBgNVBAMMCWphZWdlci1j +YTENMAsGA1UECwwEQVBJTTEXMBUGA1UECgwOR3Jhdml0ZWVTb3VyY2UxDjAMBgNV +BAcMBUxpbGxlMQ8wDQYDVQQIDAZGcmFuY2UxCzAJBgNVBAYTAkZSMB4XDTI0MDYx +NDA4NDUwOVoXDTI1MDYxNDA4NDUwOVowGDEWMBQGA1UEAwwNY2xpZW50LmphZWdl +cjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJYrqNh7Ng5vBp0FOXkE +paOHBnuxyGW3YBAsdX0RowdwBS3nTwcpb/zknxJ2fC6T89PcWT0Gyc/HsYsNInoY +7yid5VBv92xS5/YrqET5We+84acvDZYi4cpMmrNfdtUtSs1WwraaG3kcQN9zQFC4 +yxp3LzbZe7Sbj5EDJZEKCqC5i/vBOvj0qVBYaXmyalhrSpz/Gdk/nP13VVQPt9WB +mNHiKXCePpT9pRe1Uh921dulTCXcH+y0FlJcvQpGsSeEVgKZJTjOw8VzdEsOEAH3 +dT8dBYqaGIgQ/mM7hhC3pu+EAjmPayD4xuHGQN9sPjzxXmtWpFVis+3R2qJ0djP4 +8oEnqpotuei83r4SyVMYwAJc5WHM+GcCct2UXUC9RVGCug9G81gsegdwuECgq8uz +jUiGwjc9JZz41giwHyx+pKFYMLRcJPiK+lJMcuONjYYxQGIphE4GbuBetgXF98el +KFiPDr5pxdQTh5vX2pEMt0IbA6v8C8JIim6sZJlZEsvXXbK0VthjzVv5cd9OODtt +eZuMFiGoeLDgbei713ZbNnjKZT0OZJBJKJtxBUF2bx0ddZAISUOKu3qblhLFv774 +ygQT1HusQzDyjARXgBoG1tuQKVgEUgRJvXuhOO7Fkkc2QNUu6VOWrP48IXOAPpq2 +1Ps95mUSESFqJH5qw1Hn5p8RAgMBAAGjQjBAMB0GA1UdDgQWBBQYlwTFDs4XHLDm +hZOkdBgpy/7xpTAfBgNVHSMEGDAWgBSnXGLIUWL5ZUCEpFW/UOAbp3Fu0DANBgkq +hkiG9w0BAQsFAAOCAgEAbtWrR0+/au4S1XmsktlpBl4Sn1ikF3cfMLJkHciNOuFF +GwszKEaAhKsuYi22M/Jw/e+nqcLFfDhFVqfDMVXItL1wcFoOlCMYdJWVudM2PzZ1 +HcS0uc+IqnIYqc2YFjHcERmPCVtopqclGImB6tXTixOmfj9GJuFoxislVNEL/H0o +yj/wgQkDy4E2MLeFfRoWPfHClxgTIq9GadiRLEGBBF66K4noAubUn7PTToD0cWQX +LaYzQTcBdQP9fpK/SzAIsU528532H2FTz4rjKXjLOv2HPAaLzzQ5yC/wehqZ1Pd8 +07GVlt2oQCUptrXR2JJtZQ4klEOH5Wt5bRC97LMqh1heVy4gCaKe3BHjQthJbDcs +P5KhyTCz/am/kJWmsDBBzU2zUSXE6R+3SkZDiSZ3b8P2ZVoj+Im1ZKV3DUrfoA80 +d/Wtpf50756DglQc4D094WeUsy0jXRvTMcNAHqxb2Ekp1fMXmDc/UBGUi2uzI1m6 +L3by96PkqfrJjR98r1/c+H1iS1gBNXO/f4PFNw1ce4K2qaN4ABx5FKPO3+kH8KuL +l56lveAQMvUfg9HbISFBTTWMoj3QD7lzp+FOe45BK2TFOWFCQItcNKL4IQhilMps +iy8kzl85Z4b12+W8Ez0h503EC3gdRsupvR8Vhm74BqM8Gv0vhGCTbriMUymNRss= +-----END CERTIFICATE----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client.csr b/gravitee-node-opentelemetry/src/test/resources/ssl/client.csr new file mode 100755 index 000000000..9423e55df --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/client.csr @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEXTCCAkUCAQAwGDEWMBQGA1UEAwwNY2xpZW50LmphZWdlcjCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAJYrqNh7Ng5vBp0FOXkEpaOHBnuxyGW3YBAs +dX0RowdwBS3nTwcpb/zknxJ2fC6T89PcWT0Gyc/HsYsNInoY7yid5VBv92xS5/Yr +qET5We+84acvDZYi4cpMmrNfdtUtSs1WwraaG3kcQN9zQFC4yxp3LzbZe7Sbj5ED +JZEKCqC5i/vBOvj0qVBYaXmyalhrSpz/Gdk/nP13VVQPt9WBmNHiKXCePpT9pRe1 +Uh921dulTCXcH+y0FlJcvQpGsSeEVgKZJTjOw8VzdEsOEAH3dT8dBYqaGIgQ/mM7 +hhC3pu+EAjmPayD4xuHGQN9sPjzxXmtWpFVis+3R2qJ0djP48oEnqpotuei83r4S +yVMYwAJc5WHM+GcCct2UXUC9RVGCug9G81gsegdwuECgq8uzjUiGwjc9JZz41giw +Hyx+pKFYMLRcJPiK+lJMcuONjYYxQGIphE4GbuBetgXF98elKFiPDr5pxdQTh5vX +2pEMt0IbA6v8C8JIim6sZJlZEsvXXbK0VthjzVv5cd9OODtteZuMFiGoeLDgbei7 +13ZbNnjKZT0OZJBJKJtxBUF2bx0ddZAISUOKu3qblhLFv774ygQT1HusQzDyjARX +gBoG1tuQKVgEUgRJvXuhOO7Fkkc2QNUu6VOWrP48IXOAPpq21Ps95mUSESFqJH5q +w1Hn5p8RAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAMQ9mWJ3DWTOQtlgr5WlK +Ny8EevstJYbhe9axjXaOmnse7K/WIZA9vou4Z5xXlGw1hqGOyukGfig3ZfKUgXLX +u5MOJiulu0HwwJ2tRr8jdSPXztHOuuBsUnobEaM0RxPFqBVFRjmACy2V7oZavf5A +A/s6BW99zX/UQ77NA0LVXvdsv39eyUXtzJAYjeAsQNurKpAFTYR9o0n0ReCQCOxK +zoAfOlHcfKIuVNsW9cTcRrpPpxjWT+5m1sgE5g3McGLCPxLEe/NyjHeYe1oaysAX +KUm97RvdJm9IdOZwPURdmtuGtifXW8B6a2MyIMK3zGGQHC3AE/9K/Z0TNrpy+pyS +NZdRnNiXuxbsCUF1H1kcUgppwMuIHKZoCHw3YPdH5jUv7LWn1svgbQ1VuHa2LPXd +XY3Om/BEV7st/HR0LHidAYxrtc8ohvdg73i6XDA/98eSU83kfHbFljGXIggZef6O +doZWgARF+k0LN+NPW0HRB3rBlgTtKSe3joPygAvfok7cbJ5+7+V/dNDESgL7Pl4t +fL0rGJXNOirky0UCGOZhtH/wcnnnne7nVkt0oh+2oGC65X/+xvZyOLNQLMF1x77+ +Hf3FkT5mocFeQLL62Y2DefbGzab7rR+MS8k9RfHy4nIfzhSucZkKBmpboFxJL5RD +Vc+cSlMRhv07ZKrdZC/0ygk= +-----END CERTIFICATE REQUEST----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/client.key b/gravitee-node-opentelemetry/src/test/resources/ssl/client.key new file mode 100755 index 000000000..65795826d --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/client.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +lHJITDtin/jlMJD5qt9wqCr26gS3Lw== +-----END PRIVATE KEY----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/generate-certificates.sh b/gravitee-node-opentelemetry/src/test/resources/ssl/generate-certificates.sh new file mode 100755 index 000000000..928010352 --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/generate-certificates.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +#set -e + +CONFIG_SSL_PATH="." + +echo +echo "Welcome to the Jaeger SSL keystore and truststore generator script." + +echo +echo -n "First, do you need to generate truststore and jaeger server certificate [yn] " +read generate_trust_store + +if [ "$generate_trust_store" == "y" ]; then + + echo + echo "Generating certificate authority with truststore" + + # Create a certificate authority. + openssl req -newkey rsa:4096 -keyform PEM -keyout $CONFIG_SSL_PATH/ca.key -x509 -days 3650 -subj "/emailAddress=contact@graviteesource.com/CN=jaeger-ca/OU=APIM/O=GraviteeSource/L=Lille/ST=France/C=FR" -passout pass:gravitee -outform PEM -out $CONFIG_SSL_PATH/ca.pem + + echo + echo "Certificate authority generated!" + + # Jaeger server key (host: server.jaeger san: localhost) + echo + echo "Generating Jaeger server certificate" + + openssl genrsa -out $CONFIG_SSL_PATH/server.jaeger.key 4096 + openssl req -new -key $CONFIG_SSL_PATH/server.jaeger.key -out $CONFIG_SSL_PATH/server.jaeger.csr -sha256 -subj "/CN=server.jaeger" + + echo "[ req ] + distinguished_name = req_dn + req_extensions = req_ext + + [req_dn] + CN = *.jaeger + + [ req_ext ] + basicConstraints=CA:FALSE + subjectAltName = @alt_names + + [alt_names] + DNS.1 = server.jaeger + DNS.2 = localhost + IP.1 = 127.0.0.1" > $CONFIG_SSL_PATH/server.jaeger.cnf + + openssl x509 -req -in $CONFIG_SSL_PATH/server.jaeger.csr -CA $CONFIG_SSL_PATH/ca.pem -CAkey $CONFIG_SSL_PATH/ca.key -set_serial 100 -days 1460 -outform PEM -out $CONFIG_SSL_PATH/server.jaeger.crt -sha256 -passin pass:gravitee -extensions req_ext -extfile $CONFIG_SSL_PATH/server.jaeger.cnf + rm $CONFIG_SSL_PATH/server.jaeger.cnf + + echo + echo "Jaeger server certificate generated!" +fi + +echo +echo -n "Do you need to generate a client certificate to use for MTLS scenario [yn] " +read generate_client_cert + +if [ "$generate_client_cert" == "y" ]; then + echo + echo "Generating client certificate" + + # Keystore + openssl genrsa -out $CONFIG_SSL_PATH/client.key 4096 + openssl req -new -key $CONFIG_SSL_PATH/client.key -out $CONFIG_SSL_PATH/client.csr -subj "/CN=client.jaeger" + openssl x509 -req -in $CONFIG_SSL_PATH/client.csr -CA $CONFIG_SSL_PATH/ca.pem -CAkey $CONFIG_SSL_PATH/ca.key -set_serial 101 -extensions client -days 365 -outform PEM -out $CONFIG_SSL_PATH/client.cer -passin pass:gravitee + + openssl pkcs12 -export -inkey $CONFIG_SSL_PATH/client.key -in $CONFIG_SSL_PATH/client.cer -out $CONFIG_SSL_PATH/client-keystore.p12 -passout pass:gravitee -name jaeger-client + keytool -importkeystore -srckeystore $CONFIG_SSL_PATH/client-keystore.p12 -destkeystore $CONFIG_SSL_PATH/client-keystore.jks -srcstoretype PKCS12 -deststoretype JKS -srcstorepass gravitee -deststorepass gravitee + + # Truststore + # Add the ca. + keytool -import -file $CONFIG_SSL_PATH/ca.pem -storetype JKS -keystore $CONFIG_SSL_PATH/client-truststore.jks -storepass gravitee -noprompt -alias jaeger-ca + + # Add the server cert + keytool -import -file $CONFIG_SSL_PATH/server.jaeger.crt -storetype JKS -keystore $CONFIG_SSL_PATH/client-truststore.jks -storepass gravitee -noprompt -alias jaeger-server + + # Do some useful conversions. + keytool -importkeystore -srckeystore $CONFIG_SSL_PATH/client-truststore.jks -srcstorepass gravitee -destkeystore $CONFIG_SSL_PATH/client-truststore.p12 -storepass gravitee -deststoretype pkcs12 + openssl pkcs12 -nodes -in $CONFIG_SSL_PATH/client-truststore.p12 -out $CONFIG_SSL_PATH/client-truststore.pem -passin pass:gravitee + + echo + echo "Client certificate generated!" +fi diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.crt b/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.crt new file mode 100755 index 000000000..13df6177e --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFoTCCA4mgAwIBAgIBZDANBgkqhkiG9w0BAQsFADCBlTEpMCcGCSqGSIb3DQEJ +ARYaY29udGFjdEBncmF2aXRlZXNvdXJjZS5jb20xEjAQBgNVBAMMCWphZWdlci1j +YTENMAsGA1UECwwEQVBJTTEXMBUGA1UECgwOR3Jhdml0ZWVTb3VyY2UxDjAMBgNV +BAcMBUxpbGxlMQ8wDQYDVQQIDAZGcmFuY2UxCzAJBgNVBAYTAkZSMB4XDTI0MDYx +NDA4NDUwN1oXDTI4MDYxMzA4NDUwN1owGDEWMBQGA1UEAwwNc2VydmVyLmphZWdl +cjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKq/ZeZqWwefww26jYW5 +HTkUMvSxbPsAfopr0Nc81KkiQQWXwt5nGIsKDObJl6gT6vXKjc4xTQQq1GNX3Xzx +pI2NqgodHGESncO9QH2Q2utbXu5CX6JLzgn4yz0bSTZaCYOi9FSs3v2sIqXnRww1 +rXDHb2hbBJ2WG78FUD+PmRjvR+1bpO1s4xO7RrX2ceZIFpAJ4eWsS5u9M4ZsU+eG +CEIoBvBsx14tXGwLEjWXCHxnUQxPr3d4soUA0dESmeII8RM9Fcfs/vOheXzm4KYA +Y2njhFto1PbfrRdkrL5eWhBlAB0Cpx6L/5gWTSkcOzFg1p4TXFkzIoh/dgTKef1K +MKR8GYAHvB1UbjZRuu2dg9i5jT+YJHSUKTQ66I6vBO35YwIsJDJJEBXU1UdKOohe +TUHnCoDagQMIn9Mf0p+C+b5MripZZjPE8cJXaQFyFLN/h4PzRmekOopmnBX+brbT +3TQAzQds8gaN5lC4975XchrdQ7Yet4n3EKtEA78W3tLS8W8mZVUAtErH+sEu3eoi +Fa9qNHzW93w3HwkgxYGct9ZUsgYA3I2E4OMlmy74JYr2jbYhLgNNl0qL2X7cOJ/2 +P9+KbeFx2xuMartYzaMaVbohNj/fwCzP6NEtActjA8knQ/ktzF8c8EElTFqXT946 +VUQJTzTIXVEjTKurhPl1TTXjAgMBAAGjeDB2MAkGA1UdEwQCMAAwKQYDVR0RBCIw +IIINc2VydmVyLmphZWdlcoIJbG9jYWxob3N0hwR/AAABMB0GA1UdDgQWBBSeS4gR +T7cW729LgmdMmkcfQcdoITAfBgNVHSMEGDAWgBSnXGLIUWL5ZUCEpFW/UOAbp3Fu +0DANBgkqhkiG9w0BAQsFAAOCAgEAhxibPKbPVdn3GnmGVVrTxS45etqOqem5OlK6 +9x1cX/KZhC3VPad43Htg8MwHaVe3wlNGwJb4voXUnf3lOrZ//LR4ZWvZWDbQr/JV +7a3MJmMo/VcInbLSh97E61hQRN3NmvbmkOt2LYtgAm6JSrrE+dIJZ4nJqp6MRSjB +nwT5o6PRWI1gi2n+QqYFNj9CXyjQHeO76vLNJExZLNCR3APuhAJraoa96ejaNpbA +cpoG8+CbzS4T94W1vriIRkfVhnSKHxFuFjIu15c0I0OjIJarI3T/lPiv48H9ClE1 +nsA33YL5iuWlrW7qzJx2rcqBGtFc5P+lQK2SywqaqyxTeuYEvQEQIKJ1sXVJIvkO +K04eib2VyOWhWDW1OKvl95+7gKjEUrAejh/OIKNhlJNrU6+AoD97nDyi8qqJcnyT +5yRGxJ1av5dhi30CV/MR/fR69INyGTWl47ooQ3blZwt0Za2M6uJEOHSZNyeV7bjg +qcp0U8dKoNJPmvcVqkUpJ+S/SCm8kPxeiUK4y+6zz3UZaKPh7O2JwjGwJVn8+lVb +2mV3FPwd3Un2wVucRfrgI+jpwLs3NbIUDIkNlYZ/V9VEbMYxANwlWDJ2ZLLNdaFc +iV6/1oo4qGyrGwPBoloMVsEXdAiTuEFtc9SfAaPL9oKkSZxBlZv2ECqNspVuOaaP +f99BFp8= +-----END CERTIFICATE----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.csr b/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.csr new file mode 100755 index 000000000..7c341b313 --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.csr @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEXTCCAkUCAQAwGDEWMBQGA1UEAwwNc2VydmVyLmphZWdlcjCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAKq/ZeZqWwefww26jYW5HTkUMvSxbPsAfopr +0Nc81KkiQQWXwt5nGIsKDObJl6gT6vXKjc4xTQQq1GNX3XzxpI2NqgodHGESncO9 +QH2Q2utbXu5CX6JLzgn4yz0bSTZaCYOi9FSs3v2sIqXnRww1rXDHb2hbBJ2WG78F +UD+PmRjvR+1bpO1s4xO7RrX2ceZIFpAJ4eWsS5u9M4ZsU+eGCEIoBvBsx14tXGwL +EjWXCHxnUQxPr3d4soUA0dESmeII8RM9Fcfs/vOheXzm4KYAY2njhFto1PbfrRdk +rL5eWhBlAB0Cpx6L/5gWTSkcOzFg1p4TXFkzIoh/dgTKef1KMKR8GYAHvB1UbjZR +uu2dg9i5jT+YJHSUKTQ66I6vBO35YwIsJDJJEBXU1UdKOoheTUHnCoDagQMIn9Mf +0p+C+b5MripZZjPE8cJXaQFyFLN/h4PzRmekOopmnBX+brbT3TQAzQds8gaN5lC4 +975XchrdQ7Yet4n3EKtEA78W3tLS8W8mZVUAtErH+sEu3eoiFa9qNHzW93w3Hwkg +xYGct9ZUsgYA3I2E4OMlmy74JYr2jbYhLgNNl0qL2X7cOJ/2P9+KbeFx2xuMartY +zaMaVbohNj/fwCzP6NEtActjA8knQ/ktzF8c8EElTFqXT946VUQJTzTIXVEjTKur +hPl1TTXjAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEADQ0/D1cX0x4luOp0M5Hd +BOmF6wp6OzHzc/7jmXJ1QfmP8kVEUpuoCGUz4rMuLAj7Xv/lVPXNW/63yjEusioZ +0m90PhPTTehyoGwlXkq3OJdOmzH2vOnts8iBHH5FT5crkqzj5hlXsrMkwPztbzpj +vQ6y/WMx+cmQGjLxdu6Ffq3ZgNUP56K6d6q2sRpDahoH28ijEE3HA1HBzaBhT2W+ +lGOYaLHYMH4pkXUEV+6BIhn2gVMV5T5kGq3gKCtb0jNiSGmaWXxcDwr1G+ZF9odJ +ypYH00wO5Hqn/iwOmOJPUbJiO/y5LY7pnCP1CiNUMVInd4giFJy7lY6wPdvyBy8H +jwD/u8Wu3Gc4xRWNiPqojrUL1iuOemB5njW0E/NOfSKvl/Ww+cyW/qztxier4MrD +IcI9RhapVdMyP3iwAbN43jO6p0r3KeQrDJjujESPfEuo+bj+1lO0/1+D41fGHSBn +UbHNc4Wgd4X3W6KUc+cPcLVm5hpUAzONjCKF3v6R2PWvydRUDVdpDBA2KaS70gMg +poitWXI7YRjFK/eZ7xJer0FQq+Ak5iNCEOQVRKUrKnBSHwQyDNsU/zdO4udDfS9Y +rsd1wMnf9feOFnrQDjTupspMtVU6nhDgFf7GFoiQfJ1H20+Yt/g+PajjuBgPEbw9 +6/z7feCoMR44Uiv7ZRw42UI= +-----END CERTIFICATE REQUEST----- diff --git a/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.key b/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.key new file mode 100755 index 000000000..edb948e14 --- /dev/null +++ b/gravitee-node-opentelemetry/src/test/resources/ssl/server.jaeger.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +lEee7wbqlVLubBsEBDFXYVJGVB5FxaM= +-----END PRIVATE KEY----- diff --git a/gravitee-node-plugins/gravitee-node-plugins-service/pom.xml b/gravitee-node-plugins/gravitee-node-plugins-service/pom.xml index 28932d79f..7bd612cc0 100644 --- a/gravitee-node-plugins/gravitee-node-plugins-service/pom.xml +++ b/gravitee-node-plugins/gravitee-node-plugins-service/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node-plugins - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-plugins-service diff --git a/gravitee-node-plugins/pom.xml b/gravitee-node-plugins/pom.xml index c11d31e85..023c5d925 100644 --- a/gravitee-node-plugins/pom.xml +++ b/gravitee-node-plugins/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-plugins diff --git a/gravitee-node-reporter/pom.xml b/gravitee-node-reporter/pom.xml index 9b50fe04c..6e6e9bd73 100644 --- a/gravitee-node-reporter/pom.xml +++ b/gravitee-node-reporter/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-reporter diff --git a/gravitee-node-secrets/gravitee-node-secrets-plugin-handler/pom.xml b/gravitee-node-secrets/gravitee-node-secrets-plugin-handler/pom.xml index a87242aea..c0a4ab3a1 100644 --- a/gravitee-node-secrets/gravitee-node-secrets-plugin-handler/pom.xml +++ b/gravitee-node-secrets/gravitee-node-secrets-plugin-handler/pom.xml @@ -23,7 +23,7 @@ io.gravitee.node gravitee-node-secrets - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-secrets-plugin-handler diff --git a/gravitee-node-secrets/gravitee-node-secrets-service/pom.xml b/gravitee-node-secrets/gravitee-node-secrets-service/pom.xml index 30d036116..ace79b919 100644 --- a/gravitee-node-secrets/gravitee-node-secrets-service/pom.xml +++ b/gravitee-node-secrets/gravitee-node-secrets-service/pom.xml @@ -23,7 +23,7 @@ io.gravitee.node gravitee-node-secrets - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-secrets-service diff --git a/gravitee-node-secrets/pom.xml b/gravitee-node-secrets/pom.xml index d28b6b446..f8b5a97e0 100644 --- a/gravitee-node-secrets/pom.xml +++ b/gravitee-node-secrets/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-secrets diff --git a/gravitee-node-services/gravitee-node-services-initializer/pom.xml b/gravitee-node-services/gravitee-node-services-initializer/pom.xml index 4ec901f45..7cbf5734b 100644 --- a/gravitee-node-services/gravitee-node-services-initializer/pom.xml +++ b/gravitee-node-services/gravitee-node-services-initializer/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node.services gravitee-node-services - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-services-initializer diff --git a/gravitee-node-services/gravitee-node-services-upgrader/pom.xml b/gravitee-node-services/gravitee-node-services-upgrader/pom.xml index ea449a97e..0c28811a8 100644 --- a/gravitee-node-services/gravitee-node-services-upgrader/pom.xml +++ b/gravitee-node-services/gravitee-node-services-upgrader/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node.services gravitee-node-services - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-services-upgrader diff --git a/gravitee-node-services/pom.xml b/gravitee-node-services/pom.xml index 519d62c62..d6fda179d 100644 --- a/gravitee-node-services/pom.xml +++ b/gravitee-node-services/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT io.gravitee.node.services diff --git a/gravitee-node-tracing/pom.xml b/gravitee-node-tracing/pom.xml deleted file mode 100644 index d42afa37f..000000000 --- a/gravitee-node-tracing/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - 4.0.0 - - - io.gravitee.node - gravitee-node - 6.5.0 - - - gravitee-node-tracing - Gravitee.io - Node - Tracing - - - - - io.gravitee.node - gravitee-node-api - - - - io.gravitee.tracing - gravitee-tracing-api - - - - io.gravitee.plugin - gravitee-plugin-core - - - - - io.vertx - vertx-core - - - - - org.springframework - spring-core - provided - - - org.springframework - spring-context - provided - - - - - io.opentelemetry - opentelemetry-api - - - diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/LazyTracer.java b/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/LazyTracer.java deleted file mode 100644 index a6d7eb6a1..000000000 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/LazyTracer.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.gravitee.node.tracing; - -import io.gravitee.tracing.api.Span; -import io.gravitee.tracing.api.Tracer; - -/** - * @author David BRASSELY (david.brassely at graviteesource.com) - * @author GraviteeSource Team - */ -public class LazyTracer implements Tracer, TracingService.TracerListener { - - private io.gravitee.node.api.tracing.Tracer tracer; - - @Override - public Span span(String spanName) { - if (tracer != null) { - return tracer.trace(spanName); - } - - return new NoOpSpan(); - } - - @Override - public void onRegister(io.gravitee.node.api.tracing.Tracer tracer) { - this.tracer = tracer; - } -} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/TracingService.java b/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/TracingService.java deleted file mode 100644 index ead37097a..000000000 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/TracingService.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.gravitee.node.tracing; - -import io.gravitee.node.api.tracing.Tracer; -import io.gravitee.plugin.core.api.Plugin; -import io.gravitee.plugin.core.api.PluginClassLoader; -import io.gravitee.plugin.core.api.PluginClassLoaderFactory; -import io.gravitee.plugin.core.api.PluginContextFactory; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.core.env.Environment; - -/** - * @author David BRASSELY (david.brassely at graviteesource.com) - * @author GraviteeSource Team - */ -public class TracingService implements InitializingBean { - - private final Logger logger = LoggerFactory.getLogger(TracingService.class); - - private final List listeners = new ArrayList<>(); - - @Autowired - private PluginClassLoaderFactory pluginClassLoaderFactory; - - @Autowired - private Environment environment; - - @Autowired - private PluginContextFactory pluginContextFactory; - - public void register(Plugin plugin) { - String tracerType = environment.getProperty("services.tracing.type"); - - if (tracerType != null && plugin.id().contains(tracerType)) { - try { - PluginClassLoader classLoader = pluginClassLoaderFactory.getOrCreateClassLoader(plugin); - Class clazz = classLoader.loadClass(plugin.clazz()); - - ApplicationContext context = this.pluginContextFactory.create(plugin); - Tracer tracer = (Tracer) context.getBean(clazz); - - tracer.start(); - - for (TracerListener listener : listeners) { - listener.onRegister(tracer); - } - } catch (Exception ex) { - logger.error("Unable to create an instance of Tracer: {}", plugin.id(), ex); - } - } else { - logger.warn("Tracing support is enabled for tracer name[{}]. Skipping the {} tracer installation", tracerType, plugin.id()); - } - } - - public void addTracerListener(TracerListener listener) { - listeners.add(listener); - } - - @Override - public void afterPropertiesSet() throws Exception { - String tracerType = environment.getProperty("services.tracing.type"); - logger.info("Tracing support is enabled with tracer: name[{}]", tracerType); - } - - public interface TracerListener { - void onRegister(Tracer tracer); - } -} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracingPluginHandler.java b/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracingPluginHandler.java deleted file mode 100644 index 4bebde574..000000000 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/plugin/TracingPluginHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.gravitee.node.tracing.plugin; - -import io.gravitee.node.tracing.TracingService; -import io.gravitee.plugin.core.api.AbstractPluginHandler; -import io.gravitee.plugin.core.api.Plugin; -import io.gravitee.plugin.core.api.PluginClassLoaderFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; - -/** - * @author David BRASSELY (david.brassely at graviteesource.com) - * @author GraviteeSource Team - */ -public class TracingPluginHandler extends AbstractPluginHandler { - - @Autowired - private PluginClassLoaderFactory pluginClassLoaderFactory; - - @Autowired - private TracingService tracingService; - - @Autowired - private Environment environment; - - @Override - public boolean canHandle(Plugin plugin) { - return ( - environment.getProperty("services.tracing.enabled", Boolean.class, false) && - TracerPlugin.PLUGIN_TYPE.equalsIgnoreCase(plugin.type()) - ); - } - - @Override - protected String type() { - return "tracers"; - } - - @Override - protected ClassLoader getClassLoader(Plugin plugin) throws Exception { - return pluginClassLoaderFactory.getOrCreateClassLoader(plugin, this.getClass().getClassLoader()); - } - - @Override - protected void handle(Plugin plugin, Class aClass) { - tracingService.register(plugin); - } -} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/spring/TracingConfiguration.java b/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/spring/TracingConfiguration.java deleted file mode 100644 index 785347cf2..000000000 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/spring/TracingConfiguration.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.gravitee.node.tracing.spring; - -import io.gravitee.node.tracing.LazyTracer; -import io.gravitee.node.tracing.TracingService; -import io.gravitee.node.tracing.vertx.LazyVertxTracerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author David BRASSELY (david.brassely at graviteesource.com) - * @author GraviteeSource Team - */ -@Configuration -public class TracingConfiguration { - - @Bean - public TracingService tracingService() { - return new TracingService(); - } - - @Bean - public LazyVertxTracerFactory vertxTracerFactory(TracingService tracingService) { - return new LazyVertxTracerFactory(tracingService); - } - - @Bean - public LazyTracer lazyTracer(TracingService tracingService) { - LazyTracer tracer = new LazyTracer(); - tracingService.addTracerListener(tracer); - return tracer; - } -} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracer.java b/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracer.java deleted file mode 100644 index 2c8080b66..000000000 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracer.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.gravitee.node.tracing.vertx; - -import io.gravitee.node.api.tracing.Tracer; -import io.gravitee.node.tracing.TracingService; -import io.vertx.core.Context; -import io.vertx.core.spi.tracing.SpanKind; -import io.vertx.core.spi.tracing.TagExtractor; -import io.vertx.core.spi.tracing.VertxTracer; -import io.vertx.core.tracing.TracingPolicy; -import java.util.Map; -import java.util.function.BiConsumer; - -/** - * @author David BRASSELY (david.brassely at graviteesource.com) - * @author GraviteeSource Team - */ -public class LazyVertxTracer implements VertxTracer, TracingService.TracerListener { - - private io.gravitee.node.tracing.vertx.VertxTracer tracer; - - @Override - public Object receiveRequest( - Context context, - SpanKind kind, - TracingPolicy policy, - R request, - String operation, - Iterable> headers, - TagExtractor tagExtractor - ) { - if (tracer != null) { - return tracer.receiveRequest(context, kind, policy, request, operation, headers, tagExtractor); - } - - return request; - } - - @Override - public void sendResponse(Context context, R response, Object payload, Throwable failure, TagExtractor tagExtractor) { - if (tracer != null) { - tracer.sendResponse(context, response, payload, failure, tagExtractor); - } - } - - @Override - public Object sendRequest( - Context context, - SpanKind kind, - TracingPolicy policy, - R request, - String operation, - BiConsumer headers, - TagExtractor tagExtractor - ) { - if (tracer != null) { - return tracer.sendRequest(context, kind, policy, request, operation, headers, tagExtractor); - } - - return request; - } - - @Override - public void receiveResponse(Context context, R response, Object payload, Throwable failure, TagExtractor tagExtractor) { - if (tracer != null) { - tracer.receiveResponse(context, response, payload, failure, tagExtractor); - } - } - - @Override - public void close() { - if (tracer != null) { - tracer.close(); - } - } - - @Override - public void onRegister(Tracer tracer) { - if (tracer instanceof io.gravitee.node.tracing.vertx.VertxTracer) { - this.tracer = (io.gravitee.node.tracing.vertx.VertxTracer) tracer; - } - } -} diff --git a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracerFactory.java b/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracerFactory.java deleted file mode 100644 index 9645bd278..000000000 --- a/gravitee-node-tracing/src/main/java/io/gravitee/node/tracing/vertx/LazyVertxTracerFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (C) 2015 The Gravitee team (http://gravitee.io) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.gravitee.node.tracing.vertx; - -import io.gravitee.node.tracing.TracingService; -import io.vertx.core.impl.VertxBuilder; -import io.vertx.core.json.JsonObject; -import io.vertx.core.spi.VertxTracerFactory; -import io.vertx.core.spi.tracing.VertxTracer; -import io.vertx.core.tracing.TracingOptions; - -/** - * @author David BRASSELY (david.brassely at graviteesource.com) - * @author GraviteeSource Team - */ -public class LazyVertxTracerFactory implements VertxTracerFactory { - - private final TracingService tracingService; - - public LazyVertxTracerFactory(final TracingService tracingService) { - this.tracingService = tracingService; - } - - @Override - public void init(VertxBuilder builder) { - VertxTracerFactory.super.init(builder); - } - - @Override - public VertxTracer tracer(TracingOptions options) { - LazyVertxTracer tracer = new LazyVertxTracer(); - tracingService.addTracerListener(tracer); - return tracer; - } - - @Override - public TracingOptions newOptions() { - return VertxTracerFactory.super.newOptions(); - } - - @Override - public TracingOptions newOptions(JsonObject jsonObject) { - return VertxTracerFactory.super.newOptions(jsonObject); - } -} diff --git a/gravitee-node-tracing/src/main/resources/META-INF/spring.factories b/gravitee-node-tracing/src/main/resources/META-INF/spring.factories deleted file mode 100644 index d93ed86e9..000000000 --- a/gravitee-node-tracing/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -io.gravitee.plugin.core.api.PluginHandler=\ - io.gravitee.node.tracing.plugin.TracingPluginHandler \ No newline at end of file diff --git a/gravitee-node-vertx/pom.xml b/gravitee-node-vertx/pom.xml index aaee3a754..3cb604baa 100644 --- a/gravitee-node-vertx/pom.xml +++ b/gravitee-node-vertx/pom.xml @@ -24,7 +24,7 @@ io.gravitee.node gravitee-node - 6.5.0 + 7.0.0-archi-401-opentelemetry-SNAPSHOT gravitee-node-vertx @@ -40,10 +40,6 @@ io.gravitee.node gravitee-node-api - - io.gravitee.node - gravitee-node-tracing - io.gravitee.node gravitee-node-certificates diff --git a/gravitee-node-vertx/src/main/java/io/gravitee/node/vertx/VertxFactory.java b/gravitee-node-vertx/src/main/java/io/gravitee/node/vertx/VertxFactory.java index 23f96db72..092246917 100644 --- a/gravitee-node-vertx/src/main/java/io/gravitee/node/vertx/VertxFactory.java +++ b/gravitee-node-vertx/src/main/java/io/gravitee/node/vertx/VertxFactory.java @@ -15,17 +15,13 @@ */ package io.gravitee.node.vertx; -import static java.util.stream.Collectors.*; -import static java.util.stream.StreamSupport.stream; +import static java.util.stream.Collectors.toList; -import io.gravitee.common.util.EnvironmentUtils; import io.gravitee.node.api.Node; -import io.gravitee.node.tracing.vertx.LazyVertxTracerFactory; import io.gravitee.node.vertx.metrics.ExcludeTagsFilter; import io.gravitee.node.vertx.metrics.RenameVertxFilter; import io.gravitee.node.vertx.verticle.factory.SpringVerticleFactory; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; @@ -34,17 +30,23 @@ import io.micrometer.core.instrument.binder.system.ProcessorMetrics; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; -import io.vertx.core.tracing.TracingOptions; -import io.vertx.micrometer.*; +import io.vertx.micrometer.Label; +import io.vertx.micrometer.MetricsDomain; +import io.vertx.micrometer.MetricsNaming; +import io.vertx.micrometer.MicrometerMetricsOptions; +import io.vertx.micrometer.VertxPrometheusOptions; import io.vertx.micrometer.backends.BackendRegistries; -import java.util.*; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; /** @@ -66,9 +68,6 @@ public class VertxFactory implements FactoryBean { @Autowired private SpringVerticleFactory springVerticleFactory; - @Autowired - private LazyVertxTracerFactory vertxTracerFactory; - private Set + + io.gravitee.node + gravitee-node-opentelemetry + ${project.version} + io.gravitee.node gravitee-node-license @@ -228,11 +238,6 @@ gravitee-node-services-upgrader ${project.version} - - io.gravitee.node - gravitee-node-tracing - ${project.version} - io.gravitee.node gravitee-node-vertx @@ -251,12 +256,6 @@ ${gravitee-reporter-api.version} - - io.gravitee.tracing - gravitee-tracing-api - ${gravitee-tracing-api.version} - - io.gravitee.plugin gravitee-plugin-core @@ -306,6 +305,49 @@ ${license3j.version} + + + io.opentelemetry + opentelemetry-bom + ${opentelemetry.version} + pom + import + + + io.opentelemetry + opentelemetry-bom-alpha + ${opentelemetry.version}-alpha + pom + import + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-bom-alpha + ${opentelemetry-instrumentation.version} + pom + import + + + + io.opentelemetry.semconv + opentelemetry-semconv + ${opentelemetry-semconv.version} + + + io.smallrye.reactive + mutiny-bom + ${smallrye-mutiny.version} + import + pom + + + io.smallrye.common + smallrye-common-bom + ${smallrye-common.version} + import + pom + + org.jmockit @@ -319,6 +361,13 @@ ${awaitability.version} test + + org.testcontainers + testcontainers-bom + ${testcontainers.version} + pom + import +