diff --git a/gravitee-node-container/src/main/java/io/gravitee/node/container/AbstractNode.java b/gravitee-node-container/src/main/java/io/gravitee/node/container/AbstractNode.java index abf9a47e1..bce8817d9 100644 --- a/gravitee-node-container/src/main/java/io/gravitee/node/container/AbstractNode.java +++ b/gravitee-node-container/src/main/java/io/gravitee/node/container/AbstractNode.java @@ -28,6 +28,7 @@ import io.gravitee.node.monitoring.healthcheck.NodeHealthCheckService; import io.gravitee.node.monitoring.infos.NodeInfosService; import io.gravitee.node.monitoring.monitor.NodeMonitorService; +import io.gravitee.node.opentelemetry.exporter.SpanExporterFactory; import io.gravitee.node.plugins.service.ServiceManager; import io.gravitee.node.reporter.ReporterManager; import io.gravitee.plugin.core.api.PluginRegistry; @@ -134,6 +135,7 @@ public String hostname() { public List> components() { List> components = new ArrayList<>(); + components.add(SpanExporterFactory.class); components.add(PluginEventListener.class); components.add(PluginRegistry.class); components.add(NodeClusterService.class); 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 index d9f30a364..3716ef6e5 100644 --- 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 @@ -19,7 +19,7 @@ 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.exporter.SpanExporterFactory; import io.gravitee.node.opentelemetry.tracer.OpenTelemetryTracer; import io.gravitee.node.opentelemetry.tracer.noop.NoOpTracer; import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; @@ -54,7 +54,7 @@ public class OpenTelemetryFactory implements TracerFactory { private static final AttributeKey ATTRIBUTE_KEY_SERVICE_NAMESPACE = AttributeKey.stringKey("service.namespace"); private final OpenTelemetryConfiguration configuration; - private final ExporterFactory exporterFactory; + private final SpanExporterFactory spanExporterFactory; @Override public Tracer createTracer( @@ -77,7 +77,7 @@ public Tracer createTracer( SdkTracerProvider tracerProvider = SdkTracerProvider .builder() - .addSpanProcessor(BatchSpanProcessor.builder(exporterFactory.createSpanExporter()).build()) + .addSpanProcessor(BatchSpanProcessor.builder(spanExporterFactory.getSpanExporter()).build()) .setResource(resource) .build(); 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 index 9279b8a60..a724503aa 100644 --- 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 @@ -1,3 +1,18 @@ +/* + * 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 java.net.URI; diff --git a/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/SharedSpanExporter.java b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/SharedSpanExporter.java new file mode 100644 index 000000000..60926d5f7 --- /dev/null +++ b/gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/SharedSpanExporter.java @@ -0,0 +1,58 @@ +/* + * 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 io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Collection; +import lombok.RequiredArgsConstructor; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@RequiredArgsConstructor +public class SharedSpanExporter implements SpanExporter { + + private final SpanExporter delegate; + + @Override + public CompletableResultCode export(final Collection spans) { + return delegate.export(spans); + } + + @Override + public CompletableResultCode flush() { + return delegate.flush(); + } + + @Override + public CompletableResultCode shutdown() { + // Shutdown could be called when tracer or span processor are shutting down + // so we are flushing it but we don't want to close it + return this.delegate.flush(); + } + + @Override + public void close() { + // Should call globalShutdown(); + } + + public CompletableResultCode globalShutdown() { + return this.delegate.shutdown(); + } +} 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/SpanExporterFactory.java similarity index 91% rename from gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/ExporterFactory.java rename to gravitee-node-opentelemetry/src/main/java/io/gravitee/node/opentelemetry/exporter/SpanExporterFactory.java index c83f2a801..31e8dd0ee 100644 --- 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/SpanExporterFactory.java @@ -16,6 +16,7 @@ package io.gravitee.node.opentelemetry.exporter; import com.google.common.base.Strings; +import io.gravitee.common.service.AbstractService; import io.gravitee.node.opentelemetry.configuration.CompressionType; import io.gravitee.node.opentelemetry.configuration.OpenTelemetryConfiguration; import io.gravitee.node.opentelemetry.configuration.Protocol; @@ -28,6 +29,7 @@ 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.common.CompletableResultCode; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClientOptions; @@ -50,13 +52,34 @@ */ @RequiredArgsConstructor @Slf4j -public class ExporterFactory { +public class SpanExporterFactory extends AbstractService { private static final String OTLP_VALUE = "otlp"; private final OpenTelemetryConfiguration openTelemetryConfiguration; private final Vertx vertx; + private SharedSpanExporter sharedExporter; - public SpanExporter createSpanExporter() { + @Override + public SpanExporterFactory postStop() { + if (sharedExporter != null) { + CompletableResultCode completableResultCode = this.sharedExporter.globalShutdown(); + completableResultCode.whenComplete(() -> { + if (!completableResultCode.isSuccess()) { + log.warn("Unable to shutdown underlying span exporter"); + } + }); + } + return this; + } + + public SpanExporter getSpanExporter() { + if (sharedExporter == null) { + this.sharedExporter = new SharedSpanExporter(createSpanExporter()); + } + return this.sharedExporter; + } + + private SpanExporter createSpanExporter() { URI tracesUri = getTracesUri(); Protocol protocol = getProtocol(); if (protocol == Protocol.HTTP_PROTOBUF || protocol == Protocol.HTTP) { 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 index 427b57424..a0483114e 100644 --- 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 @@ -1,3 +1,18 @@ +/* + * 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.tracing; import io.opentelemetry.exporter.internal.grpc.GrpcExporter; 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 index da564656b..b7460f729 100644 --- 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 @@ -1,3 +1,18 @@ +/* + * 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.tracing; import io.opentelemetry.exporter.internal.http.HttpExporter; 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 index 78a9e2c6d..10ae2eee4 100644 --- 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 @@ -15,17 +15,14 @@ */ 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.exporter.SpanExporterFactory; 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; /** @@ -41,16 +38,16 @@ public OpenTelemetryConfiguration openTelemetryConfiguration(final ConfigurableE } @Bean - public ExporterFactory exporterFactory(final OpenTelemetryConfiguration openTelemetryConfiguration, final Vertx vertx) { - return new ExporterFactory(openTelemetryConfiguration, vertx); + public SpanExporterFactory exporterFactory(final OpenTelemetryConfiguration openTelemetryConfiguration, final Vertx vertx) { + return new SpanExporterFactory(openTelemetryConfiguration, vertx); } @Bean public OpenTelemetryFactory openTelemetryFactory( final OpenTelemetryConfiguration openTelemetryConfiguration, - final ExporterFactory exporterFactory + final SpanExporterFactory spanExporterFactory ) { - return new OpenTelemetryFactory(openTelemetryConfiguration, exporterFactory); + return new OpenTelemetryFactory(openTelemetryConfiguration, spanExporterFactory); } @Bean 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 index 913d6ee0c..97b1f7356 100644 --- 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 @@ -171,7 +171,7 @@ public void injectSpanContext(final Context vertxContext, final BiConsumer textMapSetter.accept(key, value)); + .inject(currentContext, null, (nullCarrier, key, value) -> textMapSetter.accept(key, value)); } } @@ -180,7 +180,7 @@ public void injectSpanContext(final Context vertxContext, final Span span, final if (span instanceof OpenTelemetrySpan openTelemetrySpan) { W3CTraceContextPropagator .getInstance() - .inject(openTelemetrySpan.otelContext(), null, (carrier1, key, value) -> textMapSetter.accept(key, value)); + .inject(openTelemetrySpan.otelContext(), null, (nullCarrier, key, value) -> textMapSetter.accept(key, value)); } } } 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 index 502892f9b..64b46c313 100644 --- 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 @@ -22,7 +22,7 @@ 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.exporter.SpanExporterFactory; 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; @@ -146,7 +146,7 @@ private static OpenTelemetryFactory openTelemetryFactory( final Vertx vertx, final OpenTelemetryConfiguration openTelemetryConfiguration ) { - return new OpenTelemetryFactory(openTelemetryConfiguration, new ExporterFactory(openTelemetryConfiguration, vertx)); + return new OpenTelemetryFactory(openTelemetryConfiguration, new SpanExporterFactory(openTelemetryConfiguration, vertx)); } @ParameterizedTest(name = "{0}")