diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java index 49f39505e1..f00a91a1d3 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java @@ -297,7 +297,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable } public Optional getJsonRpcSocketPort() { - if (isWebSocketsRpcEnabled()) { + if (isJsonRpcEnabled()) { return Optional.of(Integer.valueOf(portsProperties.getProperty("json-rpc"))); } else { return Optional.empty(); diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index e4f26ba467..a56ab48cda 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -41,6 +41,10 @@ dependencies { testImplementation 'io.opentelemetry:opentelemetry-sdk' testImplementation 'io.opentelemetry:opentelemetry-sdk-trace' testImplementation 'io.opentelemetry:opentelemetry-exporter-otlp' + testImplementation 'io.opentracing.contrib:opentracing-okhttp3' + testImplementation 'io.opentracing:opentracing-api' + testImplementation 'io.opentracing:opentracing-util' + testImplementation 'io.jaegertracing:jaeger-client' testImplementation 'junit:junit' testImplementation 'net.consensys:orion' testImplementation 'org.apache.commons:commons-compress' diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/OpenTelemetryAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/OpenTelemetryAcceptanceTest.java index 2496fb84ee..14a3da92fe 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/OpenTelemetryAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/OpenTelemetryAcceptanceTest.java @@ -28,10 +28,12 @@ import java.util.ArrayList; import java.util.List; import com.google.common.io.Closer; +import com.google.protobuf.ByteString; import io.grpc.Server; import io.grpc.Status; import io.grpc.netty.NettyServerBuilder; import io.grpc.stub.StreamObserver; +import io.jaegertracing.Configuration; import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse; import io.opentelemetry.proto.collector.metrics.v1.MetricsServiceGrpc; @@ -40,6 +42,15 @@ import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse; import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc; import io.opentelemetry.proto.metrics.v1.ResourceMetrics; import io.opentelemetry.proto.trace.v1.ResourceSpans; +import io.opentelemetry.proto.trace.v1.Span; +import io.opentracing.Tracer; +import io.opentracing.contrib.okhttp3.TracingCallFactory; +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -166,6 +177,53 @@ public class OpenTelemetryAcceptanceTest extends AcceptanceTestBase { net.netVersion().verify(metricsNode); List spans = fakeTracesCollector.getReceivedSpans(); assertThat(spans.isEmpty()).isFalse(); + Span internalSpan = spans.get(0).getInstrumentationLibrarySpans(0).getSpans(0); + assertThat(internalSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_INTERNAL); + ByteString parent = internalSpan.getParentSpanId(); + assertThat(parent.isEmpty()).isFalse(); + Span serverSpan = spans.get(0).getInstrumentationLibrarySpans(0).getSpans(1); + assertThat(serverSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_SERVER); + ByteString rootSpanId = serverSpan.getParentSpanId(); + assertThat(rootSpanId.isEmpty()).isTrue(); + }); + } + + @Test + public void traceReportingWithTraceId() { + + WaitUtils.waitFor( + 30, + () -> { + // call the json RPC endpoint to generate a trace - with trace metadata of our own + OkHttpClient okClient = new OkHttpClient(); + Configuration config = + new Configuration("okhttp") + .withSampler( + Configuration.SamplerConfiguration.fromEnv().withType("const").withParam(1)); + + Tracer tracer = config.getTracer(); + Call.Factory client = new TracingCallFactory(okClient, tracer); + Request request = + new Request.Builder() + .url("http://localhost:" + metricsNode.getJsonRpcSocketPort().get()) + .post( + RequestBody.create( + "{\"jsonrpc\":\"2.0\",\"method\":\"net_version\",\"params\":[],\"id\":255}", + MediaType.get("application/json"))) + .build(); + Response response = client.newCall(request).execute(); + assertThat(response.code()).isEqualTo(200); + List spans = new ArrayList<>(fakeTracesCollector.getReceivedSpans()); + fakeTracesCollector.getReceivedSpans().clear(); + assertThat(spans.isEmpty()).isFalse(); + Span internalSpan = spans.get(0).getInstrumentationLibrarySpans(0).getSpans(0); + assertThat(internalSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_INTERNAL); + ByteString parent = internalSpan.getParentSpanId(); + assertThat(parent.isEmpty()).isFalse(); + Span serverSpan = spans.get(0).getInstrumentationLibrarySpans(0).getSpans(1); + assertThat(serverSpan.getKind()).isEqualTo(Span.SpanKind.SPAN_KIND_SERVER); + ByteString rootSpanId = serverSpan.getParentSpanId(); + assertThat(rootSpanId.isEmpty()).isFalse(); }); } } diff --git a/docker/graalvm/Dockerfile b/docker/graalvm/Dockerfile index 5154c172cc..addf60fe6c 100644 --- a/docker/graalvm/Dockerfile +++ b/docker/graalvm/Dockerfile @@ -1,5 +1,6 @@ FROM ghcr.io/graalvm/graalvm-ce:ol7-java11-21.0.0 +ARG VERSION="dev" RUN adduser --home /opt/besu besu && \ chown besu:besu /opt/besu @@ -22,7 +23,7 @@ ENV BESU_RPC_WS_HOST 0.0.0.0 ENV BESU_GRAPHQL_HTTP_HOST 0.0.0.0 ENV BESU_PID_PATH "/tmp/pid" -ENV OTEL_RESOURCE_ATTRIBUTES="service.name=besu-$VERSION" +ENV OTEL_RESOURCE_ATTRIBUTES="service.name=besu,service.version=$VERSION" ENV PATH="/opt/besu/bin:${PATH}" ENTRYPOINT ["besu"] @@ -31,7 +32,6 @@ HEALTHCHECK --start-period=5s --interval=5s --timeout=1s --retries=10 CMD bash - # Build-time metadata as defined at http://label-schema.org ARG BUILD_DATE ARG VCS_REF -ARG VERSION LABEL org.label-schema.build-date=$BUILD_DATE \ org.label-schema.name="Besu" \ org.label-schema.description="Enterprise Ethereum client" \ diff --git a/docker/openjdk-11/Dockerfile b/docker/openjdk-11/Dockerfile index 61da5830c5..3207b03222 100644 --- a/docker/openjdk-11/Dockerfile +++ b/docker/openjdk-11/Dockerfile @@ -1,5 +1,6 @@ FROM openjdk:11.0.7-jre-slim-buster +ARG VERSION="dev" RUN adduser --disabled-password --gecos "" --home /opt/besu besu && \ chown besu:besu /opt/besu @@ -22,7 +23,7 @@ ENV BESU_RPC_WS_HOST 0.0.0.0 ENV BESU_GRAPHQL_HTTP_HOST 0.0.0.0 ENV BESU_PID_PATH "/tmp/pid" -ENV OTEL_RESOURCE_ATTRIBUTES="service.name=besu-$VERSION" +ENV OTEL_RESOURCE_ATTRIBUTES="service.name=besu,service.version=$VERSION" ENV PATH="/opt/besu/bin:${PATH}" ENTRYPOINT ["besu"] @@ -31,7 +32,6 @@ HEALTHCHECK --start-period=5s --interval=5s --timeout=1s --retries=10 CMD bash - # Build-time metadata as defined at http://label-schema.org ARG BUILD_DATE ARG VCS_REF -ARG VERSION LABEL org.label-schema.build-date=$BUILD_DATE \ org.label-schema.name="Besu" \ org.label-schema.description="Enterprise Ethereum client" \ diff --git a/docker/openjdk-latest/Dockerfile b/docker/openjdk-latest/Dockerfile index 4d29841ca5..c5adeab64a 100644 --- a/docker/openjdk-latest/Dockerfile +++ b/docker/openjdk-latest/Dockerfile @@ -1,5 +1,6 @@ FROM openjdk:slim-buster +ARG VERSION="dev" RUN adduser --disabled-password --gecos "" --home /opt/besu besu && \ chown besu:besu /opt/besu @@ -22,7 +23,7 @@ ENV BESU_RPC_WS_HOST 0.0.0.0 ENV BESU_GRAPHQL_HTTP_HOST 0.0.0.0 ENV BESU_PID_PATH "/tmp/pid" -ENV OTEL_RESOURCE_ATTRIBUTES="service.name=besu-$VERSION" +ENV OTEL_RESOURCE_ATTRIBUTES="service.name=besu,service.version=$VERSION" ENV PATH="/opt/besu/bin:${PATH}" ENTRYPOINT ["besu"] @@ -31,7 +32,6 @@ HEALTHCHECK --start-period=5s --interval=5s --timeout=1s --retries=10 CMD bash - # Build-time metadata as defined at http://label-schema.org ARG BUILD_DATE ARG VCS_REF -ARG VERSION LABEL org.label-schema.build-date=$BUILD_DATE \ org.label-schema.name="Besu" \ org.label-schema.description="Enterprise Ethereum client" \ diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index 0eafc55c16..dccc167a4d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -67,12 +67,15 @@ import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import io.netty.handler.codec.http.HttpResponseStatus; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.extension.trace.propagation.B3Propagator; +import io.opentelemetry.extension.trace.propagation.JaegerPropagator; +import io.opentelemetry.extension.trace.propagation.TraceMultiPropagator; import io.vertx.core.CompositeFuture; import io.vertx.core.Future; import io.vertx.core.Handler; @@ -108,6 +111,12 @@ public class JsonRpcHttpService { private static final JsonRpcResponse NO_RESPONSE = new JsonRpcNoResponse(); private static final String EMPTY_RESPONSE = ""; + private static final TextMapPropagator traceFormats = + TraceMultiPropagator.create( + JaegerPropagator.getInstance(), + B3Propagator.getInstance(), + W3CBaggagePropagator.getInstance()); + private static final TextMapPropagator.Getter requestAttributesGetter = new TextMapPropagator.Getter<>() { @Override @@ -313,17 +322,15 @@ public class JsonRpcHttpService { final SocketAddress address = routingContext.request().connection().remoteAddress(); Context parent = - B3Propagator.getInstance() - .extract(Context.current(), routingContext.request(), requestAttributesGetter); + traceFormats.extract(Context.current(), routingContext.request(), requestAttributesGetter); final Span serverSpan = tracer .spanBuilder(address.host() + ":" + address.port()) .setParent(parent) .setSpanKind(Span.Kind.SERVER) .startSpan(); - routingContext.put(SPAN_CONTEXT, Context.root().with(serverSpan)); + routingContext.put(SPAN_CONTEXT, Context.current().with(serverSpan)); - routingContext.addBodyEndHandler(event -> serverSpan.end()); routingContext.addEndHandler( event -> { if (event.failed()) { diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 0cb74a5fba..b6224f54f9 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -65,6 +65,11 @@ dependencyManagement { dependency 'io.opentelemetry:opentelemetry-sdk-trace:0.13.1' dependency 'io.opentelemetry:opentelemetry-sdk:0.13.1' + dependency 'io.opentracing.contrib:opentracing-okhttp3:3.0.0' + dependency 'io.opentracing:opentracing-api:0.33.0' + dependency 'io.opentracing:opentracing-util:0.33.0' + dependency 'io.jaegertracing:jaeger-client:1.5.0' + dependency 'io.pkts:pkts-core:3.0.7' dependency 'io.prometheus:simpleclient:0.9.0'