Split out gRPC library instrumentation. (#1329)
* Split out gRPC library instrumentation. * Simpler status
This commit is contained in:
parent
9523f9ffe6
commit
525b3f729d
|
@ -5,4 +5,12 @@
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.api.tracer;
|
package io.opentelemetry.instrumentation.api.tracer;
|
||||||
|
|
||||||
public abstract class RpcClientTracer extends BaseTracer {}
|
import io.opentelemetry.trace.Tracer;
|
||||||
|
|
||||||
|
public abstract class RpcClientTracer extends BaseTracer {
|
||||||
|
protected RpcClientTracer() {}
|
||||||
|
|
||||||
|
protected RpcClientTracer(Tracer tracer) {
|
||||||
|
super(tracer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,9 +9,16 @@ import static io.opentelemetry.OpenTelemetry.getPropagators;
|
||||||
|
|
||||||
import io.grpc.Context;
|
import io.grpc.Context;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
|
import io.opentelemetry.trace.Tracer;
|
||||||
|
|
||||||
public abstract class RpcServerTracer<REQUEST> extends BaseTracer {
|
public abstract class RpcServerTracer<REQUEST> extends BaseTracer {
|
||||||
|
|
||||||
|
protected RpcServerTracer() {}
|
||||||
|
|
||||||
|
protected RpcServerTracer(Tracer tracer) {
|
||||||
|
super(tracer);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract TextMapPropagator.Getter<REQUEST> getGetter();
|
protected abstract TextMapPropagator.Getter<REQUEST> getGetter();
|
||||||
|
|
||||||
protected <C> Context extract(C carrier, TextMapPropagator.Getter<C> getter) {
|
protected <C> Context extract(C carrier, TextMapPropagator.Getter<C> getter) {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
apply from: "$rootDir/gradle/instrumentation.gradle"
|
||||||
|
|
||||||
|
muzzle {
|
||||||
|
pass {
|
||||||
|
group = "io.grpc"
|
||||||
|
module = "grpc-core"
|
||||||
|
versions = "[1.5.0,)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def grpcVersion = '1.5.0'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':instrumentation:grpc-1.5:library')
|
||||||
|
|
||||||
|
library group: 'io.grpc', name: 'grpc-core', version: grpcVersion
|
||||||
|
|
||||||
|
testLibrary group: 'io.grpc', name: 'grpc-netty', version: grpcVersion
|
||||||
|
testLibrary group: 'io.grpc', name: 'grpc-protobuf', version: grpcVersion
|
||||||
|
testLibrary group: 'io.grpc', name: 'grpc-stub', version: grpcVersion
|
||||||
|
|
||||||
|
testImplementation project(':instrumentation:grpc-1.5:testing')
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.auto.grpc.v1_5;
|
||||||
|
|
||||||
|
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
||||||
|
|
||||||
|
abstract class AbstractGrpcInstrumentation extends Instrumenter.Default {
|
||||||
|
|
||||||
|
public AbstractGrpcInstrumentation() {
|
||||||
|
super("grpc");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String[] helperClassNames() {
|
||||||
|
return new String[] {
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.common.GrpcHelper",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.client.GrpcClientTracer",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.client.GrpcInjectAdapter",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor$TracingClientCall",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor$TracingClientCallListener",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.server.GrpcExtractAdapter",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.server.GrpcServerTracer",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor$TracingServerCall",
|
||||||
|
"io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor$TracingServerCallListener",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
package io.opentelemetry.instrumentation.auto.grpc.v1_5;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
|
@ -13,11 +13,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.grpc.ClientInterceptor;
|
import io.grpc.ClientInterceptor;
|
||||||
import io.grpc.ManagedChannelBuilder;
|
import io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor;
|
||||||
import io.opentelemetry.instrumentation.auto.api.ContextStore;
|
|
||||||
import io.opentelemetry.instrumentation.auto.api.InstrumentationContext;
|
|
||||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
@ -26,7 +23,7 @@ import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
@AutoService(Instrumenter.class)
|
||||||
public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcClientInstrumentation {
|
public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcInstrumentation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
|
@ -45,7 +42,6 @@ public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcClientIns
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void addInterceptor(
|
public static void addInterceptor(
|
||||||
@Advice.This ManagedChannelBuilder thiz,
|
|
||||||
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors) {
|
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors) {
|
||||||
boolean shouldRegister = true;
|
boolean shouldRegister = true;
|
||||||
for (ClientInterceptor interceptor : interceptors) {
|
for (ClientInterceptor interceptor : interceptors) {
|
||||||
|
@ -55,10 +51,7 @@ public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcClientIns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldRegister) {
|
if (shouldRegister) {
|
||||||
ContextStore<ManagedChannelBuilder, InetSocketAddress> contextStore =
|
interceptors.add(0, TracingClientInterceptor.newInterceptor());
|
||||||
InstrumentationContext.get(ManagedChannelBuilder.class, InetSocketAddress.class);
|
|
||||||
InetSocketAddress sockAddr = contextStore.get(thiz);
|
|
||||||
interceptors.add(0, new TracingClientInterceptor(sockAddr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.server;
|
package io.opentelemetry.instrumentation.auto.grpc.v1_5;
|
||||||
|
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
|
@ -11,6 +11,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.grpc.ServerInterceptor;
|
import io.grpc.ServerInterceptor;
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor;
|
||||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -20,29 +21,13 @@ import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
@AutoService(Instrumenter.class)
|
||||||
public class GrpcServerBuilderInstrumentation extends Instrumenter.Default {
|
public class GrpcServerBuilderInstrumentation extends AbstractGrpcInstrumentation {
|
||||||
|
|
||||||
public GrpcServerBuilderInstrumentation() {
|
|
||||||
super("grpc", "grpc-server");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
return named("io.grpc.internal.AbstractServerImplBuilder");
|
return named("io.grpc.internal.AbstractServerImplBuilder");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
packageName + ".GrpcServerTracer",
|
|
||||||
packageName + ".GrpcExtractAdapter",
|
|
||||||
packageName + ".TracingServerInterceptor",
|
|
||||||
packageName + ".TracingServerInterceptor$TracingServerCall",
|
|
||||||
packageName + ".TracingServerInterceptor$TracingServerCallListener",
|
|
||||||
"io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||||
return singletonMap(
|
return singletonMap(
|
||||||
|
@ -63,7 +48,7 @@ public class GrpcServerBuilderInstrumentation extends Instrumenter.Default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldRegister) {
|
if (shouldRegister) {
|
||||||
interceptors.add(0, TracingServerInterceptor.INSTANCE);
|
interceptors.add(0, TracingServerInterceptor.newInterceptor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.auto.grpc.v1_5
|
||||||
|
|
||||||
|
import io.grpc.ManagedChannelBuilder
|
||||||
|
import io.grpc.ServerBuilder
|
||||||
|
import io.opentelemetry.auto.test.AgentTestTrait
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.AbstractGrpcStreamingTest
|
||||||
|
|
||||||
|
class GrpcStreamingTest extends AbstractGrpcStreamingTest implements AgentTestTrait {
|
||||||
|
@Override
|
||||||
|
ServerBuilder configureServer(ServerBuilder server) {
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ManagedChannelBuilder configureClient(ManagedChannelBuilder client) {
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.auto.grpc.v1_5
|
||||||
|
|
||||||
|
import io.grpc.ManagedChannelBuilder
|
||||||
|
import io.grpc.ServerBuilder
|
||||||
|
import io.opentelemetry.auto.test.AgentTestTrait
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.AbstractGrpcTest
|
||||||
|
|
||||||
|
class GrpcTest extends AbstractGrpcTest implements AgentTestTrait {
|
||||||
|
@Override
|
||||||
|
ServerBuilder configureServer(ServerBuilder server) {
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ManagedChannelBuilder configureClient(ManagedChannelBuilder client) {
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
apply from: "$rootDir/gradle/instrumentation.gradle"
|
|
||||||
|
|
||||||
apply plugin: 'com.google.protobuf'
|
|
||||||
apply plugin: 'idea'
|
|
||||||
|
|
||||||
muzzle {
|
|
||||||
pass {
|
|
||||||
group = "io.grpc"
|
|
||||||
module = "grpc-core"
|
|
||||||
versions = "[1.5.0,)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
jcenter()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def grpcVersion = '1.5.0'
|
|
||||||
protobuf {
|
|
||||||
protoc {
|
|
||||||
// Download compiler rather than using locally installed version:
|
|
||||||
artifact = 'com.google.protobuf:protoc:3.3.0'
|
|
||||||
}
|
|
||||||
plugins {
|
|
||||||
grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" }
|
|
||||||
}
|
|
||||||
generateProtoTasks {
|
|
||||||
all()*.plugins { grpc {} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
library group: 'io.grpc', name: 'grpc-core', version: grpcVersion
|
|
||||||
|
|
||||||
testLibrary group: 'io.grpc', name: 'grpc-netty', version: grpcVersion
|
|
||||||
testLibrary group: 'io.grpc', name: 'grpc-protobuf', version: grpcVersion
|
|
||||||
testLibrary group: 'io.grpc', name: 'grpc-stub', version: grpcVersion
|
|
||||||
|
|
||||||
testImplementation group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
|
|
||||||
|
|
||||||
// this instrumentation needs to be able to be able to reference the OpenTelemetry API's gRPC Context
|
|
||||||
// that is shaded in the bootstrap class loader (for sending telemetry to the agent),
|
|
||||||
// separately from the gRPC Context that is brought by gRPC
|
|
||||||
compileOnly project(path: ':opentelemetry-api-beta-shaded-for-instrumenting', configuration: 'shadow')
|
|
||||||
|
|
||||||
testImplementation project(path: ':opentelemetry-api-beta-shaded-for-instrumenting', configuration: 'shadow')
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
apply from: "$rootDir/gradle/instrumentation-library.gradle"
|
||||||
|
|
||||||
|
def grpcVersion = '1.5.0'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
library group: 'io.grpc', name: 'grpc-core', version: grpcVersion
|
||||||
|
|
||||||
|
testLibrary group: 'io.grpc', name: 'grpc-netty', version: grpcVersion
|
||||||
|
testLibrary group: 'io.grpc', name: 'grpc-protobuf', version: grpcVersion
|
||||||
|
testLibrary group: 'io.grpc', name: 'grpc-stub', version: grpcVersion
|
||||||
|
|
||||||
|
testImplementation project(':instrumentation:grpc-1.5:testing')
|
||||||
|
}
|
|
@ -3,19 +3,25 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
package io.opentelemetry.instrumentation.grpc.v1_5.client;
|
||||||
|
|
||||||
import static io.opentelemetry.trace.Span.Kind.CLIENT;
|
import static io.opentelemetry.trace.Span.Kind.CLIENT;
|
||||||
|
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.RpcClientTracer;
|
import io.opentelemetry.instrumentation.api.tracer.RpcClientTracer;
|
||||||
import io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper;
|
import io.opentelemetry.instrumentation.grpc.v1_5.common.GrpcHelper;
|
||||||
import io.opentelemetry.trace.Span;
|
import io.opentelemetry.trace.Span;
|
||||||
import io.opentelemetry.trace.Span.Builder;
|
import io.opentelemetry.trace.Span.Builder;
|
||||||
|
import io.opentelemetry.trace.Tracer;
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||||
|
|
||||||
public class GrpcClientTracer extends RpcClientTracer {
|
public class GrpcClientTracer extends RpcClientTracer {
|
||||||
public static final GrpcClientTracer TRACER = new GrpcClientTracer();
|
|
||||||
|
protected GrpcClientTracer() {}
|
||||||
|
|
||||||
|
protected GrpcClientTracer(Tracer tracer) {
|
||||||
|
super(tracer);
|
||||||
|
}
|
||||||
|
|
||||||
public Span startSpan(String name) {
|
public Span startSpan(String name) {
|
||||||
Builder spanBuilder = tracer.spanBuilder(name).setSpanKind(CLIENT);
|
Builder spanBuilder = tracer.spanBuilder(name).setSpanKind(CLIENT);
|
|
@ -3,14 +3,14 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
package io.opentelemetry.instrumentation.grpc.v1_5.client;
|
||||||
|
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
|
|
||||||
public final class GrpcInjectAdapter implements TextMapPropagator.Setter<Metadata> {
|
final class GrpcInjectAdapter implements TextMapPropagator.Setter<Metadata> {
|
||||||
|
|
||||||
public static final GrpcInjectAdapter SETTER = new GrpcInjectAdapter();
|
static final GrpcInjectAdapter SETTER = new GrpcInjectAdapter();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(Metadata carrier, String key, String value) {
|
public void set(Metadata carrier, String key, String value) {
|
|
@ -3,84 +3,106 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
package io.opentelemetry.instrumentation.grpc.v1_5.client;
|
||||||
|
|
||||||
import static io.opentelemetry.context.ContextUtils.withScopedContext;
|
import static io.opentelemetry.context.ContextUtils.withScopedContext;
|
||||||
import static io.opentelemetry.instrumentation.auto.grpc.client.GrpcClientTracer.TRACER;
|
import static io.opentelemetry.instrumentation.grpc.v1_5.client.GrpcInjectAdapter.SETTER;
|
||||||
import static io.opentelemetry.instrumentation.auto.grpc.client.GrpcInjectAdapter.SETTER;
|
|
||||||
import static io.opentelemetry.trace.TracingContextUtils.getSpan;
|
|
||||||
import static io.opentelemetry.trace.TracingContextUtils.withSpan;
|
import static io.opentelemetry.trace.TracingContextUtils.withSpan;
|
||||||
|
|
||||||
import io.grpc.CallOptions;
|
import io.grpc.CallOptions;
|
||||||
import io.grpc.Channel;
|
import io.grpc.Channel;
|
||||||
import io.grpc.ClientCall;
|
import io.grpc.ClientCall;
|
||||||
|
import io.grpc.ClientCall.Listener;
|
||||||
import io.grpc.ClientInterceptor;
|
import io.grpc.ClientInterceptor;
|
||||||
import io.grpc.Context;
|
import io.grpc.Context;
|
||||||
import io.grpc.ForwardingClientCall;
|
import io.grpc.ForwardingClientCall;
|
||||||
import io.grpc.ForwardingClientCallListener;
|
import io.grpc.ForwardingClientCallListener;
|
||||||
|
import io.grpc.Grpc;
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
import io.grpc.MethodDescriptor;
|
import io.grpc.MethodDescriptor;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.opentelemetry.OpenTelemetry;
|
import io.opentelemetry.OpenTelemetry;
|
||||||
import io.opentelemetry.common.Attributes;
|
import io.opentelemetry.common.Attributes;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper;
|
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.common.GrpcHelper;
|
||||||
import io.opentelemetry.trace.Span;
|
import io.opentelemetry.trace.Span;
|
||||||
|
import io.opentelemetry.trace.Tracer;
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public class TracingClientInterceptor implements ClientInterceptor {
|
public class TracingClientInterceptor implements ClientInterceptor {
|
||||||
private final InetSocketAddress peerAddress;
|
|
||||||
|
|
||||||
public TracingClientInterceptor(InetSocketAddress peerAddress) {
|
public static ClientInterceptor newInterceptor() {
|
||||||
this.peerAddress = peerAddress;
|
return newInterceptor(new GrpcClientTracer());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientInterceptor newInterceptor(Tracer tracer) {
|
||||||
|
return newInterceptor(new GrpcClientTracer(tracer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientInterceptor newInterceptor(GrpcClientTracer tracer) {
|
||||||
|
return new TracingClientInterceptor(tracer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final GrpcClientTracer tracer;
|
||||||
|
|
||||||
|
private TracingClientInterceptor(GrpcClientTracer tracer) {
|
||||||
|
this.tracer = tracer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
||||||
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
||||||
|
|
||||||
String methodName = method.getFullMethodName();
|
String methodName = method.getFullMethodName();
|
||||||
Span span = TRACER.startSpan(methodName);
|
Span span = tracer.startSpan(methodName);
|
||||||
|
GrpcHelper.prepareSpan(span, methodName);
|
||||||
Context context = withSpan(span, Context.current());
|
Context context = withSpan(span, Context.current());
|
||||||
|
final ClientCall<ReqT, RespT> result;
|
||||||
try (Scope ignored = withScopedContext(context)) {
|
try (Scope ignored = withScopedContext(context)) {
|
||||||
GrpcHelper.prepareSpan(span, methodName, peerAddress, false);
|
|
||||||
|
|
||||||
ClientCall<ReqT, RespT> result;
|
|
||||||
try {
|
try {
|
||||||
// call other interceptors
|
// call other interceptors
|
||||||
result = next.newCall(method, callOptions);
|
result = next.newCall(method, callOptions);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
return new TracingClientCall<>(context, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SocketAddress address = result.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
|
||||||
|
if (address instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) address;
|
||||||
|
NetPeerUtils.setNetPeer(span, inetSocketAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TracingClientCall<>(result, span, context, tracer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class TracingClientCall<ReqT, RespT>
|
static final class TracingClientCall<ReqT, RespT>
|
||||||
extends ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT> {
|
extends ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT> {
|
||||||
final Context context;
|
|
||||||
|
|
||||||
TracingClientCall(Context context, ClientCall<ReqT, RespT> delegate) {
|
private final Span span;
|
||||||
|
private final Context context;
|
||||||
|
private final GrpcClientTracer tracer;
|
||||||
|
|
||||||
|
TracingClientCall(
|
||||||
|
ClientCall<ReqT, RespT> delegate, Span span, Context context, GrpcClientTracer tracer) {
|
||||||
super(delegate);
|
super(delegate);
|
||||||
|
this.span = span;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.tracer = tracer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Listener<RespT> responseListener, Metadata headers) {
|
public void start(Listener<RespT> responseListener, Metadata headers) {
|
||||||
// this reference to io.grpc.Context will be shaded during the build
|
|
||||||
// see instrumentation.gradle: "relocate OpenTelemetry API dependency usage"
|
|
||||||
// (luckily the grpc instrumentation doesn't need to reference unshaded grpc Context, so we
|
|
||||||
// don't need to worry about distinguishing them like in the opentelemetry-api
|
|
||||||
// instrumentation)
|
|
||||||
OpenTelemetry.getPropagators().getTextMapPropagator().inject(context, headers, SETTER);
|
OpenTelemetry.getPropagators().getTextMapPropagator().inject(context, headers, SETTER);
|
||||||
try (Scope ignored = withScopedContext(context)) {
|
try (Scope ignored = withScopedContext(context)) {
|
||||||
super.start(new TracingClientCallListener<>(context, responseListener), headers);
|
super.start(
|
||||||
|
new TracingClientCallListener<>(responseListener, span, context, tracer), headers);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Span span = getSpan(context);
|
tracer.endExceptionally(span, e);
|
||||||
TRACER.endExceptionally(span, e);
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +112,7 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
||||||
try (Scope ignored = withScopedContext(context)) {
|
try (Scope ignored = withScopedContext(context)) {
|
||||||
super.sendMessage(message);
|
super.sendMessage(message);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Span span = getSpan(context);
|
tracer.endExceptionally(span, e);
|
||||||
TRACER.endExceptionally(span, e);
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,17 +120,22 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
||||||
|
|
||||||
static final class TracingClientCallListener<RespT>
|
static final class TracingClientCallListener<RespT>
|
||||||
extends ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT> {
|
extends ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT> {
|
||||||
|
private final Span span;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private final GrpcClientTracer tracer;
|
||||||
|
|
||||||
private final AtomicLong messageId = new AtomicLong();
|
private final AtomicLong messageId = new AtomicLong();
|
||||||
|
|
||||||
TracingClientCallListener(Context context, ClientCall.Listener<RespT> delegate) {
|
TracingClientCallListener(
|
||||||
|
Listener<RespT> delegate, Span span, Context context, GrpcClientTracer tracer) {
|
||||||
super(delegate);
|
super(delegate);
|
||||||
|
this.span = span;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.tracer = tracer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(RespT message) {
|
public void onMessage(RespT message) {
|
||||||
Span span = getSpan(context);
|
|
||||||
Attributes attributes =
|
Attributes attributes =
|
||||||
Attributes.of(
|
Attributes.of(
|
||||||
SemanticAttributes.GRPC_MESSAGE_TYPE,
|
SemanticAttributes.GRPC_MESSAGE_TYPE,
|
||||||
|
@ -119,19 +145,20 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
||||||
span.addEvent("message", attributes);
|
span.addEvent("message", attributes);
|
||||||
try (Scope ignored = withScopedContext(context)) {
|
try (Scope ignored = withScopedContext(context)) {
|
||||||
delegate().onMessage(message);
|
delegate().onMessage(message);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
tracer.addThrowable(span, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(Status status, Metadata trailers) {
|
public void onClose(Status status, Metadata trailers) {
|
||||||
Span span = getSpan(context);
|
|
||||||
try (Scope ignored = withScopedContext(context)) {
|
try (Scope ignored = withScopedContext(context)) {
|
||||||
delegate().onClose(status, trailers);
|
delegate().onClose(status, trailers);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
TRACER.endSpan(span, status);
|
tracer.endSpan(span, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,8 +166,7 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
||||||
try (Scope ignored = withScopedContext(context)) {
|
try (Scope ignored = withScopedContext(context)) {
|
||||||
delegate().onReady();
|
delegate().onReady();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Span span = getSpan(context);
|
tracer.endExceptionally(span, e);
|
||||||
TRACER.endExceptionally(span, e);
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.grpc.v1_5.common;
|
||||||
|
|
||||||
|
import io.grpc.Status.Code;
|
||||||
|
import io.opentelemetry.trace.Span;
|
||||||
|
import io.opentelemetry.trace.StatusCanonicalCode;
|
||||||
|
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||||
|
|
||||||
|
public final class GrpcHelper {
|
||||||
|
public static void prepareSpan(Span span, String fullMethodName) {
|
||||||
|
|
||||||
|
int slash = fullMethodName.indexOf('/');
|
||||||
|
String serviceName = slash == -1 ? fullMethodName : fullMethodName.substring(0, slash);
|
||||||
|
String methodName = slash == -1 ? null : fullMethodName.substring(slash + 1);
|
||||||
|
|
||||||
|
span.setAttribute(SemanticAttributes.RPC_SERVICE, serviceName);
|
||||||
|
span.setAttribute(SemanticAttributes.RPC_METHOD, methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StatusCanonicalCode statusFromGrpcStatus(io.grpc.Status grpcStatus) {
|
||||||
|
return codeFromGrpcCode(grpcStatus.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StatusCanonicalCode codeFromGrpcCode(Code grpcCode) {
|
||||||
|
return grpcCode.equals(Code.OK) ? StatusCanonicalCode.UNSET : StatusCanonicalCode.ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GrpcHelper() {}
|
||||||
|
}
|
|
@ -3,14 +3,14 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.server;
|
package io.opentelemetry.instrumentation.grpc.v1_5.server;
|
||||||
|
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||||
|
|
||||||
public final class GrpcExtractAdapter implements TextMapPropagator.Getter<Metadata> {
|
final class GrpcExtractAdapter implements TextMapPropagator.Getter<Metadata> {
|
||||||
|
|
||||||
public static final GrpcExtractAdapter GETTER = new GrpcExtractAdapter();
|
static final GrpcExtractAdapter GETTER = new GrpcExtractAdapter();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(Metadata carrier, String key) {
|
public String get(Metadata carrier, String key) {
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.server;
|
package io.opentelemetry.instrumentation.grpc.v1_5.server;
|
||||||
|
|
||||||
import static io.opentelemetry.trace.Span.Kind.SERVER;
|
import static io.opentelemetry.trace.Span.Kind.SERVER;
|
||||||
|
|
||||||
|
@ -11,13 +11,19 @@ import io.grpc.Metadata;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.opentelemetry.context.propagation.TextMapPropagator.Getter;
|
import io.opentelemetry.context.propagation.TextMapPropagator.Getter;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.RpcServerTracer;
|
import io.opentelemetry.instrumentation.api.tracer.RpcServerTracer;
|
||||||
import io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper;
|
import io.opentelemetry.instrumentation.grpc.v1_5.common.GrpcHelper;
|
||||||
import io.opentelemetry.trace.Span;
|
import io.opentelemetry.trace.Span;
|
||||||
import io.opentelemetry.trace.Span.Builder;
|
import io.opentelemetry.trace.Span.Builder;
|
||||||
|
import io.opentelemetry.trace.Tracer;
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||||
|
|
||||||
public class GrpcServerTracer extends RpcServerTracer<Metadata> {
|
public class GrpcServerTracer extends RpcServerTracer<Metadata> {
|
||||||
public static final GrpcServerTracer TRACER = new GrpcServerTracer();
|
|
||||||
|
GrpcServerTracer() {}
|
||||||
|
|
||||||
|
GrpcServerTracer(Tracer tracer) {
|
||||||
|
super(tracer);
|
||||||
|
}
|
||||||
|
|
||||||
public Span startSpan(String name, Metadata headers) {
|
public Span startSpan(String name, Metadata headers) {
|
||||||
Builder spanBuilder =
|
Builder spanBuilder =
|
|
@ -3,9 +3,8 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.server;
|
package io.opentelemetry.instrumentation.grpc.v1_5.server;
|
||||||
|
|
||||||
import static io.opentelemetry.instrumentation.auto.grpc.server.GrpcServerTracer.TRACER;
|
|
||||||
import static io.opentelemetry.trace.TracingContextUtils.currentContextWith;
|
import static io.opentelemetry.trace.TracingContextUtils.currentContextWith;
|
||||||
|
|
||||||
import io.grpc.ForwardingServerCall;
|
import io.grpc.ForwardingServerCall;
|
||||||
|
@ -13,13 +12,15 @@ import io.grpc.ForwardingServerCallListener;
|
||||||
import io.grpc.Grpc;
|
import io.grpc.Grpc;
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
import io.grpc.ServerCall;
|
import io.grpc.ServerCall;
|
||||||
|
import io.grpc.ServerCall.Listener;
|
||||||
import io.grpc.ServerCallHandler;
|
import io.grpc.ServerCallHandler;
|
||||||
import io.grpc.ServerInterceptor;
|
import io.grpc.ServerInterceptor;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.opentelemetry.common.Attributes;
|
import io.opentelemetry.common.Attributes;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper;
|
import io.opentelemetry.instrumentation.grpc.v1_5.common.GrpcHelper;
|
||||||
import io.opentelemetry.trace.Span;
|
import io.opentelemetry.trace.Span;
|
||||||
|
import io.opentelemetry.trace.Tracer;
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
@ -27,20 +28,39 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public class TracingServerInterceptor implements ServerInterceptor {
|
public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
|
|
||||||
public static final TracingServerInterceptor INSTANCE = new TracingServerInterceptor();
|
public static ServerInterceptor newInterceptor() {
|
||||||
|
return newInterceptor(new GrpcServerTracer());
|
||||||
|
}
|
||||||
|
|
||||||
private TracingServerInterceptor() {}
|
public static ServerInterceptor newInterceptor(Tracer tracer) {
|
||||||
|
return newInterceptor(new GrpcServerTracer(tracer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerInterceptor newInterceptor(GrpcServerTracer tracer) {
|
||||||
|
return new TracingServerInterceptor(tracer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final GrpcServerTracer tracer;
|
||||||
|
|
||||||
|
private TracingServerInterceptor(GrpcServerTracer tracer) {
|
||||||
|
this.tracer = tracer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
|
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
|
||||||
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
||||||
|
|
||||||
String methodName = call.getMethodDescriptor().getFullMethodName();
|
String methodName = call.getMethodDescriptor().getFullMethodName();
|
||||||
Span span = TRACER.startSpan(methodName, headers);
|
Span span = tracer.startSpan(methodName, headers);
|
||||||
|
|
||||||
SocketAddress addr = call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
|
SocketAddress address = call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
|
||||||
InetSocketAddress iAddr = addr instanceof InetSocketAddress ? (InetSocketAddress) addr : null;
|
if (address instanceof InetSocketAddress) {
|
||||||
GrpcHelper.prepareSpan(span, methodName, iAddr, true);
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) address;
|
||||||
|
span.setAttribute(SemanticAttributes.NET_PEER_PORT, inetSocketAddress.getPort());
|
||||||
|
span.setAttribute(
|
||||||
|
SemanticAttributes.NET_PEER_IP, inetSocketAddress.getAddress().getHostAddress());
|
||||||
|
}
|
||||||
|
GrpcHelper.prepareSpan(span, methodName);
|
||||||
|
|
||||||
ServerCall.Listener<ReqT> result;
|
ServerCall.Listener<ReqT> result;
|
||||||
try (Scope ignored = currentContextWith(span)) {
|
try (Scope ignored = currentContextWith(span)) {
|
||||||
|
@ -48,36 +68,39 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
try {
|
try {
|
||||||
// Wrap the server call so that we can decorate the span
|
// Wrap the server call so that we can decorate the span
|
||||||
// with the resulting status
|
// with the resulting status
|
||||||
TracingServerCall<ReqT, RespT> tracingServerCall = new TracingServerCall<>(span, call);
|
TracingServerCall<ReqT, RespT> tracingServerCall =
|
||||||
|
new TracingServerCall<>(call, span, tracer);
|
||||||
|
|
||||||
// call other interceptors
|
// call other interceptors
|
||||||
result = next.startCall(tracingServerCall, headers);
|
result = next.startCall(tracingServerCall, headers);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This ensures the server implementation can see the span in scope
|
// This ensures the server implementation can see the span in scope
|
||||||
return new TracingServerCallListener<>(span, result);
|
return new TracingServerCallListener<>(result, span, tracer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class TracingServerCall<ReqT, RespT>
|
static final class TracingServerCall<ReqT, RespT>
|
||||||
extends ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT> {
|
extends ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT> {
|
||||||
final Span span;
|
private final Span span;
|
||||||
|
private final GrpcServerTracer tracer;
|
||||||
|
|
||||||
TracingServerCall(Span span, ServerCall<ReqT, RespT> delegate) {
|
TracingServerCall(ServerCall<ReqT, RespT> delegate, Span span, GrpcServerTracer tracer) {
|
||||||
super(delegate);
|
super(delegate);
|
||||||
this.span = span;
|
this.span = span;
|
||||||
|
this.tracer = tracer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close(Status status, Metadata trailers) {
|
public void close(Status status, Metadata trailers) {
|
||||||
TRACER.setStatus(span, status);
|
tracer.setStatus(span, status);
|
||||||
try (Scope ignored = currentContextWith(span)) {
|
try (Scope ignored = currentContextWith(span)) {
|
||||||
delegate().close(status, trailers);
|
delegate().close(status, trailers);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,11 +109,14 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
static final class TracingServerCallListener<ReqT>
|
static final class TracingServerCallListener<ReqT>
|
||||||
extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
|
extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
|
||||||
private final Span span;
|
private final Span span;
|
||||||
|
private final GrpcServerTracer tracer;
|
||||||
|
|
||||||
private final AtomicLong messageId = new AtomicLong();
|
private final AtomicLong messageId = new AtomicLong();
|
||||||
|
|
||||||
TracingServerCallListener(Span span, ServerCall.Listener<ReqT> delegate) {
|
TracingServerCallListener(Listener<ReqT> delegate, Span span, GrpcServerTracer tracer) {
|
||||||
super(delegate);
|
super(delegate);
|
||||||
this.span = span;
|
this.span = span;
|
||||||
|
this.tracer = tracer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,7 +138,7 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
try (Scope ignored = currentContextWith(span)) {
|
try (Scope ignored = currentContextWith(span)) {
|
||||||
delegate().onHalfClose();
|
delegate().onHalfClose();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,10 +149,10 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
delegate().onCancel();
|
delegate().onCancel();
|
||||||
span.setAttribute("canceled", true);
|
span.setAttribute("canceled", true);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
TRACER.end(span);
|
tracer.end(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -134,10 +160,10 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
try (Scope ignored = currentContextWith(span)) {
|
try (Scope ignored = currentContextWith(span)) {
|
||||||
delegate().onComplete();
|
delegate().onComplete();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
TRACER.end(span);
|
tracer.end(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -145,7 +171,7 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
||||||
try (Scope ignored = currentContextWith(span)) {
|
try (Scope ignored = currentContextWith(span)) {
|
||||||
delegate().onReady();
|
delegate().onReady();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
TRACER.endExceptionally(span, e);
|
tracer.endExceptionally(span, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.grpc.v1_5
|
||||||
|
|
||||||
|
import io.grpc.ManagedChannelBuilder
|
||||||
|
import io.grpc.ServerBuilder
|
||||||
|
import io.opentelemetry.auto.test.InstrumentationTestTrait
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor
|
||||||
|
|
||||||
|
class GrpcStreamingTest extends AbstractGrpcStreamingTest implements InstrumentationTestTrait {
|
||||||
|
@Override
|
||||||
|
ServerBuilder configureServer(ServerBuilder server) {
|
||||||
|
return server.intercept(TracingServerInterceptor.newInterceptor())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ManagedChannelBuilder configureClient(ManagedChannelBuilder client) {
|
||||||
|
return client.intercept(TracingClientInterceptor.newInterceptor())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.grpc.v1_5
|
||||||
|
|
||||||
|
import io.grpc.ManagedChannelBuilder
|
||||||
|
import io.grpc.ServerBuilder
|
||||||
|
import io.opentelemetry.auto.test.InstrumentationTestTrait
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor
|
||||||
|
import io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor
|
||||||
|
|
||||||
|
class GrpcTest extends AbstractGrpcTest implements InstrumentationTestTrait {
|
||||||
|
@Override
|
||||||
|
ServerBuilder configureServer(ServerBuilder server) {
|
||||||
|
return server.intercept(TracingServerInterceptor.newInterceptor())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ManagedChannelBuilder configureClient(ManagedChannelBuilder client) {
|
||||||
|
return client.intercept(TracingClientInterceptor.newInterceptor())
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.common
|
package io.opentelemetry.instrumentation.grpc.v1_5.common
|
||||||
|
|
||||||
import io.grpc.Status
|
import io.grpc.Status
|
||||||
import io.opentelemetry.trace.StatusCanonicalCode
|
import io.opentelemetry.trace.StatusCanonicalCode
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
|
||||||
|
|
||||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
abstract class AbstractGrpcClientInstrumentation extends Instrumenter.Default {
|
|
||||||
|
|
||||||
public AbstractGrpcClientInstrumentation() {
|
|
||||||
super("grpc", "grpc-client");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] helperClassNames() {
|
|
||||||
return new String[] {
|
|
||||||
packageName + ".GrpcClientTracer",
|
|
||||||
packageName + ".GrpcInjectAdapter",
|
|
||||||
packageName + ".TracingClientInterceptor",
|
|
||||||
packageName + ".TracingClientInterceptor$TracingClientCall",
|
|
||||||
packageName + ".TracingClientInterceptor$TracingClientCallListener",
|
|
||||||
"io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, String> contextStore() {
|
|
||||||
return Collections.singletonMap(
|
|
||||||
"io.grpc.ManagedChannelBuilder", InetSocketAddress.class.getName());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.tooling.bytebuddy.matcher.AgentElementMatchers.extendsClass;
|
|
||||||
import static java.util.Collections.singletonMap;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
|
||||||
import io.grpc.ManagedChannelBuilder;
|
|
||||||
import io.opentelemetry.instrumentation.auto.api.ContextStore;
|
|
||||||
import io.opentelemetry.instrumentation.auto.api.InstrumentationContext;
|
|
||||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.Map;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.method.MethodDescription;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
|
||||||
|
|
||||||
@AutoService(Instrumenter.class)
|
|
||||||
public class GrpcClientBuilderForAddressInstrumentation extends AbstractGrpcClientInstrumentation {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return extendsClass(named("io.grpc.ManagedChannelBuilder"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
|
||||||
return singletonMap(
|
|
||||||
isMethod().and(named("forAddress").and(ElementMatchers.takesArguments(2))),
|
|
||||||
GrpcClientBuilderForAddressInstrumentation.class.getName() + "$ForAddressAdvice");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ForAddressAdvice {
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
|
||||||
public static final void forAddress(
|
|
||||||
@Advice.Argument(0) String address,
|
|
||||||
@Advice.Argument(1) int port,
|
|
||||||
@Advice.Return ManagedChannelBuilder builder) {
|
|
||||||
ContextStore<ManagedChannelBuilder, InetSocketAddress> contextStore =
|
|
||||||
InstrumentationContext.get(ManagedChannelBuilder.class, InetSocketAddress.class);
|
|
||||||
contextStore.put(builder, InetSocketAddress.createUnresolved(address, port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.auto.grpc.common;
|
|
||||||
|
|
||||||
import io.grpc.Status.Code;
|
|
||||||
import io.opentelemetry.instrumentation.api.tracer.utils.NetPeerUtils;
|
|
||||||
import io.opentelemetry.trace.Span;
|
|
||||||
import io.opentelemetry.trace.StatusCanonicalCode;
|
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class GrpcHelper {
|
|
||||||
private static final Map<Code, StatusCanonicalCode> CODE_MAP;
|
|
||||||
|
|
||||||
static {
|
|
||||||
EnumMap<Code, StatusCanonicalCode> codeMap = new EnumMap<>(Code.class);
|
|
||||||
codeMap.put(Code.CANCELLED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.INVALID_ARGUMENT, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.DEADLINE_EXCEEDED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.NOT_FOUND, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.ALREADY_EXISTS, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.PERMISSION_DENIED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.RESOURCE_EXHAUSTED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.FAILED_PRECONDITION, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.ABORTED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.OUT_OF_RANGE, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.UNIMPLEMENTED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.INTERNAL, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.UNAVAILABLE, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.DATA_LOSS, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.UNAUTHENTICATED, StatusCanonicalCode.ERROR);
|
|
||||||
codeMap.put(Code.UNKNOWN, StatusCanonicalCode.ERROR);
|
|
||||||
CODE_MAP = Collections.unmodifiableMap(codeMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void prepareSpan(
|
|
||||||
Span span, String fullMethodName, InetSocketAddress peerAddress, boolean server) {
|
|
||||||
|
|
||||||
int slash = fullMethodName.indexOf('/');
|
|
||||||
String serviceName = slash == -1 ? fullMethodName : fullMethodName.substring(0, slash);
|
|
||||||
String methodName = slash == -1 ? null : fullMethodName.substring(slash + 1);
|
|
||||||
|
|
||||||
span.setAttribute(SemanticAttributes.RPC_SERVICE, serviceName);
|
|
||||||
if (methodName != null) {
|
|
||||||
span.setAttribute(SemanticAttributes.RPC_METHOD, methodName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peerAddress != null) {
|
|
||||||
span.setAttribute(SemanticAttributes.NET_PEER_PORT, (long) peerAddress.getPort());
|
|
||||||
if (server) {
|
|
||||||
span.setAttribute(
|
|
||||||
SemanticAttributes.NET_PEER_IP, peerAddress.getAddress().getHostAddress());
|
|
||||||
} else {
|
|
||||||
NetPeerUtils.setNetPeer(span, peerAddress.getHostName(), null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// The spec says these fields must be populated, so put some values in even if we don't have
|
|
||||||
// an address recorded.
|
|
||||||
span.setAttribute(SemanticAttributes.NET_PEER_PORT, 0L);
|
|
||||||
NetPeerUtils.setNetPeer(span, "(unknown)", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StatusCanonicalCode statusFromGrpcStatus(io.grpc.Status grpcStatus) {
|
|
||||||
return codeFromGrpcCode(grpcStatus.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StatusCanonicalCode codeFromGrpcCode(Code grpcCode) {
|
|
||||||
StatusCanonicalCode code = CODE_MAP.get(grpcCode);
|
|
||||||
return code != null ? code : StatusCanonicalCode.UNSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GrpcHelper() {}
|
|
||||||
}
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
plugins {
|
||||||
|
id "java-library"
|
||||||
|
id "com.google.protobuf" version "0.8.13"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/gradle/java.gradle"
|
||||||
|
|
||||||
|
def grpcVersion = '1.5.0'
|
||||||
|
|
||||||
|
protobuf {
|
||||||
|
protoc {
|
||||||
|
// Download compiler rather than using locally installed version:
|
||||||
|
artifact = 'com.google.protobuf:protoc:3.3.0'
|
||||||
|
}
|
||||||
|
plugins {
|
||||||
|
grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" }
|
||||||
|
}
|
||||||
|
generateProtoTasks {
|
||||||
|
all()*.plugins { grpc {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api project(':testing-common')
|
||||||
|
|
||||||
|
api group: 'io.grpc', name: 'grpc-core', version: grpcVersion
|
||||||
|
api group: 'io.grpc', name: 'grpc-protobuf', version: grpcVersion
|
||||||
|
api group: 'io.grpc', name: 'grpc-stub', version: grpcVersion
|
||||||
|
|
||||||
|
implementation group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
|
||||||
|
|
||||||
|
implementation deps.guava
|
||||||
|
|
||||||
|
implementation deps.groovy
|
||||||
|
implementation deps.opentelemetryApi
|
||||||
|
implementation deps.spock
|
||||||
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.grpc.v1_5
|
||||||
|
|
||||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||||
import static io.opentelemetry.trace.Span.Kind.SERVER
|
import static io.opentelemetry.trace.Span.Kind.SERVER
|
||||||
|
|
||||||
|
@ -14,16 +16,22 @@ import io.grpc.ManagedChannelBuilder
|
||||||
import io.grpc.Server
|
import io.grpc.Server
|
||||||
import io.grpc.ServerBuilder
|
import io.grpc.ServerBuilder
|
||||||
import io.grpc.stub.StreamObserver
|
import io.grpc.stub.StreamObserver
|
||||||
import io.opentelemetry.auto.test.AgentTestRunner
|
import io.opentelemetry.auto.test.InstrumentationSpecification
|
||||||
import io.opentelemetry.auto.test.utils.PortUtils
|
import io.opentelemetry.auto.test.utils.PortUtils
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes
|
import io.opentelemetry.trace.attributes.SemanticAttributes
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class GrpcStreamingTest extends AgentTestRunner {
|
@Unroll
|
||||||
|
abstract class AbstractGrpcStreamingTest extends InstrumentationSpecification {
|
||||||
|
|
||||||
def "test conversation #name"() {
|
abstract ServerBuilder configureServer(ServerBuilder server)
|
||||||
|
|
||||||
|
abstract ManagedChannelBuilder configureClient(ManagedChannelBuilder client)
|
||||||
|
|
||||||
|
def "test conversation #paramName"() {
|
||||||
setup:
|
setup:
|
||||||
def msgCount = serverMessageCount
|
def msgCount = serverMessageCount
|
||||||
def serverReceived = new CopyOnWriteArrayList<>()
|
def serverReceived = new CopyOnWriteArrayList<>()
|
||||||
|
@ -58,8 +66,8 @@ class GrpcStreamingTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def port = PortUtils.randomOpenPort()
|
def port = PortUtils.randomOpenPort()
|
||||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||||
|
|
||||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||||
try {
|
try {
|
||||||
|
@ -94,12 +102,6 @@ class GrpcStreamingTest extends AgentTestRunner {
|
||||||
observer.onCompleted()
|
observer.onCompleted()
|
||||||
|
|
||||||
then:
|
then:
|
||||||
error.get() == null
|
|
||||||
TEST_WRITER.waitForTraces(1)
|
|
||||||
error.get() == null
|
|
||||||
serverReceived == clientRange.collect { "call $it" }
|
|
||||||
clientReceived == serverRange.collect { clientRange.collect { "call $it" } }.flatten().sort()
|
|
||||||
|
|
||||||
assertTraces(1) {
|
assertTraces(1) {
|
||||||
trace(0, 2) {
|
trace(0, 2) {
|
||||||
span(0) {
|
span(0) {
|
||||||
|
@ -111,8 +113,6 @@ class GrpcStreamingTest extends AgentTestRunner {
|
||||||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||||
"${SemanticAttributes.RPC_METHOD.key()}" "Conversation"
|
"${SemanticAttributes.RPC_METHOD.key()}" "Conversation"
|
||||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
|
||||||
"${SemanticAttributes.NET_PEER_PORT.key()}" port
|
|
||||||
}
|
}
|
||||||
(1..(clientMessageCount * serverMessageCount)).each {
|
(1..(clientMessageCount * serverMessageCount)).each {
|
||||||
def messageId = it
|
def messageId = it
|
||||||
|
@ -150,6 +150,9 @@ class GrpcStreamingTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
error.get() == null
|
||||||
|
serverReceived == clientRange.collect { "call $it" }
|
||||||
|
clientReceived == serverRange.collect { clientRange.collect { "call $it" } }.flatten().sort()
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
channel?.shutdownNow()?.awaitTermination(10, TimeUnit.SECONDS)
|
channel?.shutdownNow()?.awaitTermination(10, TimeUnit.SECONDS)
|
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.grpc.v1_5
|
||||||
|
|
||||||
import static io.opentelemetry.auto.test.utils.TraceUtils.basicSpan
|
import static io.opentelemetry.auto.test.utils.TraceUtils.basicSpan
|
||||||
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
||||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||||
|
@ -18,15 +20,21 @@ import io.grpc.ServerBuilder
|
||||||
import io.grpc.Status
|
import io.grpc.Status
|
||||||
import io.grpc.StatusRuntimeException
|
import io.grpc.StatusRuntimeException
|
||||||
import io.grpc.stub.StreamObserver
|
import io.grpc.stub.StreamObserver
|
||||||
import io.opentelemetry.auto.test.AgentTestRunner
|
import io.opentelemetry.auto.test.InstrumentationSpecification
|
||||||
import io.opentelemetry.auto.test.utils.PortUtils
|
import io.opentelemetry.auto.test.utils.PortUtils
|
||||||
import io.opentelemetry.instrumentation.auto.grpc.common.GrpcHelper
|
import io.opentelemetry.trace.StatusCanonicalCode
|
||||||
import io.opentelemetry.trace.attributes.SemanticAttributes
|
import io.opentelemetry.trace.attributes.SemanticAttributes
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
import spock.lang.Unroll
|
||||||
|
|
||||||
class GrpcTest extends AgentTestRunner {
|
@Unroll
|
||||||
|
abstract class AbstractGrpcTest extends InstrumentationSpecification {
|
||||||
|
|
||||||
def "test request-response"() {
|
abstract ServerBuilder configureServer(ServerBuilder server)
|
||||||
|
|
||||||
|
abstract ManagedChannelBuilder configureClient(ManagedChannelBuilder client)
|
||||||
|
|
||||||
|
def "test request-response #paramName"() {
|
||||||
setup:
|
setup:
|
||||||
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,8 +46,8 @@ class GrpcTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def port = PortUtils.randomOpenPort()
|
def port = PortUtils.randomOpenPort()
|
||||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||||
|
|
||||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||||
try {
|
try {
|
||||||
|
@ -77,8 +85,6 @@ class GrpcTest extends AgentTestRunner {
|
||||||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||||
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
||||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
|
||||||
"${SemanticAttributes.NET_PEER_PORT.key()}" port
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(2) {
|
span(2) {
|
||||||
|
@ -112,7 +118,7 @@ class GrpcTest extends AgentTestRunner {
|
||||||
paramName << ["some name", "some other name"]
|
paramName << ["some name", "some other name"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def "test error - #name"() {
|
def "test error - #paramName"() {
|
||||||
setup:
|
setup:
|
||||||
def error = grpcStatus.asException()
|
def error = grpcStatus.asException()
|
||||||
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
||||||
|
@ -123,8 +129,8 @@ class GrpcTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def port = PortUtils.randomOpenPort()
|
def port = PortUtils.randomOpenPort()
|
||||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||||
|
|
||||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||||
try {
|
try {
|
||||||
|
@ -148,13 +154,11 @@ class GrpcTest extends AgentTestRunner {
|
||||||
kind CLIENT
|
kind CLIENT
|
||||||
hasNoParent()
|
hasNoParent()
|
||||||
errored true
|
errored true
|
||||||
status(GrpcHelper.statusFromGrpcStatus(grpcStatus))
|
status(StatusCanonicalCode.ERROR)
|
||||||
attributes {
|
attributes {
|
||||||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||||
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
||||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
|
||||||
"${SemanticAttributes.NET_PEER_PORT.key()}" port
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
|
@ -162,7 +166,7 @@ class GrpcTest extends AgentTestRunner {
|
||||||
kind SERVER
|
kind SERVER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored true
|
errored true
|
||||||
status(GrpcHelper.statusFromGrpcStatus(grpcStatus))
|
status(StatusCanonicalCode.ERROR)
|
||||||
event(0) {
|
event(0) {
|
||||||
eventName "message"
|
eventName "message"
|
||||||
attributes {
|
attributes {
|
||||||
|
@ -198,7 +202,7 @@ class GrpcTest extends AgentTestRunner {
|
||||||
"StatusRuntime - description" | Status.UNIMPLEMENTED.withDescription("some description")
|
"StatusRuntime - description" | Status.UNIMPLEMENTED.withDescription("some description")
|
||||||
}
|
}
|
||||||
|
|
||||||
def "test error thrown - #name"() {
|
def "test error thrown - #paramName"() {
|
||||||
setup:
|
setup:
|
||||||
def error = grpcStatus.asRuntimeException()
|
def error = grpcStatus.asRuntimeException()
|
||||||
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
||||||
|
@ -209,8 +213,8 @@ class GrpcTest extends AgentTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def port = PortUtils.randomOpenPort()
|
def port = PortUtils.randomOpenPort()
|
||||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||||
|
|
||||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||||
try {
|
try {
|
||||||
|
@ -240,8 +244,6 @@ class GrpcTest extends AgentTestRunner {
|
||||||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||||
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
||||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
|
||||||
"${SemanticAttributes.NET_PEER_PORT.key()}" Long
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span(1) {
|
span(1) {
|
||||||
|
@ -249,7 +251,7 @@ class GrpcTest extends AgentTestRunner {
|
||||||
kind SERVER
|
kind SERVER
|
||||||
childOf span(0)
|
childOf span(0)
|
||||||
errored true
|
errored true
|
||||||
status(GrpcHelper.statusFromGrpcStatus(grpcStatus))
|
status(StatusCanonicalCode.ERROR)
|
||||||
event(0) {
|
event(0) {
|
||||||
eventName "message"
|
eventName "message"
|
||||||
attributes {
|
attributes {
|
|
@ -88,7 +88,9 @@ include ':instrumentation:geode-1.4'
|
||||||
include ':instrumentation:google-http-client-1.19'
|
include ':instrumentation:google-http-client-1.19'
|
||||||
include ':instrumentation:grizzly-2.0'
|
include ':instrumentation:grizzly-2.0'
|
||||||
include ':instrumentation:grizzly-client-1.9'
|
include ':instrumentation:grizzly-client-1.9'
|
||||||
include ':instrumentation:grpc-1.5'
|
include ':instrumentation:grpc-1.5:auto'
|
||||||
|
include ':instrumentation:grpc-1.5:library'
|
||||||
|
include ':instrumentation:grpc-1.5:testing'
|
||||||
include ':instrumentation:guava-10.0'
|
include ':instrumentation:guava-10.0'
|
||||||
include ':instrumentation:hibernate:hibernate-3.3'
|
include ':instrumentation:hibernate:hibernate-3.3'
|
||||||
include ':instrumentation:hibernate:hibernate-4.0'
|
include ':instrumentation:hibernate:hibernate-4.0'
|
||||||
|
|
Loading…
Reference in New Issue