mirror of https://github.com/grpc/grpc-java.git
interop-test: add opentelemetry tracing context propagation test (#11538)
This commit is contained in:
parent
fa18fec36e
commit
d169a5de6f
|
|
@ -13,6 +13,7 @@ dependencies {
|
|||
implementation project(path: ':grpc-alts', configuration: 'shadow'),
|
||||
project(':grpc-auth'),
|
||||
project(':grpc-census'),
|
||||
project(':grpc-opentelemetry'),
|
||||
project(':grpc-gcp-csm-observability'),
|
||||
project(':grpc-netty'),
|
||||
project(':grpc-okhttp'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright 2024 The gRPC Authors
|
||||
*
|
||||
* 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.grpc.testing.integration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import io.grpc.ForwardingServerCallListener;
|
||||
import io.grpc.InsecureServerCredentials;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.ServerBuilder;
|
||||
import io.grpc.ServerCall;
|
||||
import io.grpc.ServerCallHandler;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.netty.InternalNettyChannelBuilder;
|
||||
import io.grpc.netty.NettyChannelBuilder;
|
||||
import io.grpc.netty.NettyServerBuilder;
|
||||
import io.grpc.opentelemetry.GrpcOpenTelemetry;
|
||||
import io.grpc.opentelemetry.GrpcTraceBinContextPropagator;
|
||||
import io.grpc.opentelemetry.InternalGrpcOpenTelemetry;
|
||||
import io.grpc.testing.integration.Messages.SimpleRequest;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class OpenTelemetryContextPropagationTest extends AbstractInteropTest {
|
||||
private final OpenTelemetrySdk openTelemetrySdk;
|
||||
private final Tracer tracer;
|
||||
private final GrpcOpenTelemetry grpcOpenTelemetry;
|
||||
private final AtomicReference<Span> applicationSpan = new AtomicReference<>();
|
||||
private final boolean censusClient;
|
||||
|
||||
@Parameterized.Parameters(name = "ContextPropagator={0}, CensusClient={1}")
|
||||
public static Iterable<Object[]> data() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
{W3CTraceContextPropagator.getInstance(), false},
|
||||
{GrpcTraceBinContextPropagator.defaultInstance(), false},
|
||||
{GrpcTraceBinContextPropagator.defaultInstance(), true}
|
||||
});
|
||||
}
|
||||
|
||||
public OpenTelemetryContextPropagationTest(TextMapPropagator textMapPropagator,
|
||||
boolean isCensusClient) {
|
||||
this.openTelemetrySdk = OpenTelemetrySdk.builder()
|
||||
.setTracerProvider(SdkTracerProvider.builder().build())
|
||||
.setPropagators(ContextPropagators.create(TextMapPropagator.composite(
|
||||
textMapPropagator
|
||||
)))
|
||||
.build();
|
||||
this.tracer = openTelemetrySdk
|
||||
.getTracer("grpc-java-interop-test");
|
||||
GrpcOpenTelemetry.Builder grpcOpentelemetryBuilder = GrpcOpenTelemetry.newBuilder()
|
||||
.sdk(openTelemetrySdk);
|
||||
InternalGrpcOpenTelemetry.enableTracing(grpcOpentelemetryBuilder, true);
|
||||
grpcOpenTelemetry = grpcOpentelemetryBuilder.build();
|
||||
this.censusClient = isCensusClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerBuilder<?> getServerBuilder() {
|
||||
NettyServerBuilder builder = NettyServerBuilder.forPort(0, InsecureServerCredentials.create())
|
||||
.maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE);
|
||||
builder.intercept(new ServerInterceptor() {
|
||||
@Override
|
||||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
|
||||
Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
||||
ServerCall.Listener<ReqT> listener = next.startCall(call, headers);
|
||||
return new ForwardingServerCallListener<ReqT>() {
|
||||
@Override
|
||||
protected ServerCall.Listener<ReqT> delegate() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ReqT request) {
|
||||
applicationSpan.set(tracer.spanBuilder("InteropTest.Application.Span").startSpan());
|
||||
delegate().onMessage(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHalfClose() {
|
||||
maybeCloseSpan(applicationSpan);
|
||||
delegate().onHalfClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
maybeCloseSpan(applicationSpan);
|
||||
delegate().onCancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
maybeCloseSpan(applicationSpan);
|
||||
delegate().onComplete();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
// To ensure proper propagation of remote spans from gRPC to your application, this interceptor
|
||||
// must be after any application interceptors that interact with spans. This allows the tracing
|
||||
// information to be correctly passed along. However, it's fine for application-level onMessage
|
||||
// handlers to access the span.
|
||||
grpcOpenTelemetry.configureServerBuilder(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void maybeCloseSpan(AtomicReference<Span> applicationSpan) {
|
||||
Span tmp = applicationSpan.get();
|
||||
if (tmp != null) {
|
||||
tmp.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean metricsExpected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ManagedChannelBuilder<?> createChannelBuilder() {
|
||||
NettyChannelBuilder builder = NettyChannelBuilder.forAddress(getListenAddress())
|
||||
.maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE)
|
||||
.usePlaintext();
|
||||
if (!censusClient) {
|
||||
// Disabling census-tracing is necessary to avoid trace ID mismatches.
|
||||
// This is because census-tracing overrides the grpc-trace-bin header with
|
||||
// OpenTelemetry's GrpcTraceBinPropagator.
|
||||
InternalNettyChannelBuilder.setTracingEnabled(builder, false);
|
||||
grpcOpenTelemetry.configureChannelBuilder(builder);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void otelSpanContextPropagation() {
|
||||
Assume.assumeFalse(censusClient);
|
||||
Span parentSpan = tracer.spanBuilder("Test.interopTest").startSpan();
|
||||
try (Scope scope = Context.current().with(parentSpan).makeCurrent()) {
|
||||
blockingStub.unaryCall(SimpleRequest.getDefaultInstance());
|
||||
}
|
||||
assertEquals(parentSpan.getSpanContext().getTraceId(),
|
||||
applicationSpan.get().getSpanContext().getTraceId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void censusToOtelGrpcTraceBinPropagator() {
|
||||
Assume.assumeTrue(censusClient);
|
||||
io.opencensus.trace.Tracer censusTracer = io.opencensus.trace.Tracing.getTracer();
|
||||
io.opencensus.trace.Span parentSpan = censusTracer.spanBuilder("Test.interopTest")
|
||||
.startSpan();
|
||||
io.grpc.Context context = io.opencensus.trace.unsafe.ContextUtils.withValue(
|
||||
io.grpc.Context.current(), parentSpan);
|
||||
io.grpc.Context previous = context.attach();
|
||||
try {
|
||||
blockingStub.unaryCall(SimpleRequest.getDefaultInstance());
|
||||
assertEquals(parentSpan.getContext().getTraceId().toLowerBase16(),
|
||||
applicationSpan.get().getSpanContext().getTraceId());
|
||||
} finally {
|
||||
context.detach(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue