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;
|
||||
|
||||
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.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
|
||||
public abstract class RpcServerTracer<REQUEST> extends BaseTracer {
|
||||
|
||||
protected RpcServerTracer() {}
|
||||
|
||||
protected RpcServerTracer(Tracer tracer) {
|
||||
super(tracer);
|
||||
}
|
||||
|
||||
protected abstract TextMapPropagator.Getter<REQUEST> getGetter();
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
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 java.util.Collections.singletonMap;
|
||||
|
@ -13,11 +13,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.opentelemetry.instrumentation.auto.api.ContextStore;
|
||||
import io.opentelemetry.instrumentation.auto.api.InstrumentationContext;
|
||||
import io.opentelemetry.instrumentation.grpc.v1_5.client.TracingClientInterceptor;
|
||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
@ -26,7 +23,7 @@ import net.bytebuddy.description.type.TypeDescription;
|
|||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(Instrumenter.class)
|
||||
public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcClientInstrumentation {
|
||||
public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcInstrumentation {
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
|
@ -45,7 +42,6 @@ public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcClientIns
|
|||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void addInterceptor(
|
||||
@Advice.This ManagedChannelBuilder thiz,
|
||||
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors) {
|
||||
boolean shouldRegister = true;
|
||||
for (ClientInterceptor interceptor : interceptors) {
|
||||
|
@ -55,10 +51,7 @@ public class GrpcClientBuilderBuildInstrumentation extends AbstractGrpcClientIns
|
|||
}
|
||||
}
|
||||
if (shouldRegister) {
|
||||
ContextStore<ManagedChannelBuilder, InetSocketAddress> contextStore =
|
||||
InstrumentationContext.get(ManagedChannelBuilder.class, InetSocketAddress.class);
|
||||
InetSocketAddress sockAddr = contextStore.get(thiz);
|
||||
interceptors.add(0, new TracingClientInterceptor(sockAddr));
|
||||
interceptors.add(0, TracingClientInterceptor.newInterceptor());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* 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 net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
|
@ -11,6 +11,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.opentelemetry.instrumentation.grpc.v1_5.server.TracingServerInterceptor;
|
||||
import io.opentelemetry.javaagent.tooling.Instrumenter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -20,29 +21,13 @@ import net.bytebuddy.description.type.TypeDescription;
|
|||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(Instrumenter.class)
|
||||
public class GrpcServerBuilderInstrumentation extends Instrumenter.Default {
|
||||
|
||||
public GrpcServerBuilderInstrumentation() {
|
||||
super("grpc", "grpc-server");
|
||||
}
|
||||
public class GrpcServerBuilderInstrumentation extends AbstractGrpcInstrumentation {
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
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
|
||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||
return singletonMap(
|
||||
|
@ -63,7 +48,7 @@ public class GrpcServerBuilderInstrumentation extends Instrumenter.Default {
|
|||
}
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.auto.grpc.client;
|
||||
package io.opentelemetry.instrumentation.grpc.v1_5.client;
|
||||
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT;
|
||||
|
||||
import io.grpc.Status;
|
||||
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.Builder;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||
|
||||
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) {
|
||||
Builder spanBuilder = tracer.spanBuilder(name).setSpanKind(CLIENT);
|
|
@ -3,14 +3,14 @@
|
|||
* 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.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
|
||||
public void set(Metadata carrier, String key, String value) {
|
|
@ -3,84 +3,106 @@
|
|||
* 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.instrumentation.auto.grpc.client.GrpcClientTracer.TRACER;
|
||||
import static io.opentelemetry.instrumentation.auto.grpc.client.GrpcInjectAdapter.SETTER;
|
||||
import static io.opentelemetry.trace.TracingContextUtils.getSpan;
|
||||
import static io.opentelemetry.instrumentation.grpc.v1_5.client.GrpcInjectAdapter.SETTER;
|
||||
import static io.opentelemetry.trace.TracingContextUtils.withSpan;
|
||||
|
||||
import io.grpc.CallOptions;
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ClientCall;
|
||||
import io.grpc.ClientCall.Listener;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.Context;
|
||||
import io.grpc.ForwardingClientCall;
|
||||
import io.grpc.ForwardingClientCallListener;
|
||||
import io.grpc.Grpc;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.MethodDescriptor;
|
||||
import io.grpc.Status;
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.common.Attributes;
|
||||
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.Tracer;
|
||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class TracingClientInterceptor implements ClientInterceptor {
|
||||
private final InetSocketAddress peerAddress;
|
||||
|
||||
public TracingClientInterceptor(InetSocketAddress peerAddress) {
|
||||
this.peerAddress = peerAddress;
|
||||
public static ClientInterceptor newInterceptor() {
|
||||
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
|
||||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
||||
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
||||
|
||||
String methodName = method.getFullMethodName();
|
||||
Span span = TRACER.startSpan(methodName);
|
||||
Span span = tracer.startSpan(methodName);
|
||||
GrpcHelper.prepareSpan(span, methodName);
|
||||
Context context = withSpan(span, Context.current());
|
||||
final ClientCall<ReqT, RespT> result;
|
||||
try (Scope ignored = withScopedContext(context)) {
|
||||
GrpcHelper.prepareSpan(span, methodName, peerAddress, false);
|
||||
|
||||
ClientCall<ReqT, RespT> result;
|
||||
try {
|
||||
// call other interceptors
|
||||
result = next.newCall(method, callOptions);
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, 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>
|
||||
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);
|
||||
this.span = span;
|
||||
this.context = context;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
try (Scope ignored = withScopedContext(context)) {
|
||||
super.start(new TracingClientCallListener<>(context, responseListener), headers);
|
||||
super.start(
|
||||
new TracingClientCallListener<>(responseListener, span, context, tracer), headers);
|
||||
} catch (Throwable e) {
|
||||
Span span = getSpan(context);
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -90,8 +112,7 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
|||
try (Scope ignored = withScopedContext(context)) {
|
||||
super.sendMessage(message);
|
||||
} catch (Throwable e) {
|
||||
Span span = getSpan(context);
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -99,17 +120,22 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
|||
|
||||
static final class TracingClientCallListener<RespT>
|
||||
extends ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT> {
|
||||
private final Span span;
|
||||
private final Context context;
|
||||
private final GrpcClientTracer tracer;
|
||||
|
||||
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);
|
||||
this.span = span;
|
||||
this.context = context;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(RespT message) {
|
||||
Span span = getSpan(context);
|
||||
Attributes attributes =
|
||||
Attributes.of(
|
||||
SemanticAttributes.GRPC_MESSAGE_TYPE,
|
||||
|
@ -119,19 +145,20 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
|||
span.addEvent("message", attributes);
|
||||
try (Scope ignored = withScopedContext(context)) {
|
||||
delegate().onMessage(message);
|
||||
} catch (Throwable e) {
|
||||
tracer.addThrowable(span, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Status status, Metadata trailers) {
|
||||
Span span = getSpan(context);
|
||||
try (Scope ignored = withScopedContext(context)) {
|
||||
delegate().onClose(status, trailers);
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
TRACER.endSpan(span, status);
|
||||
tracer.endSpan(span, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,8 +166,7 @@ public class TracingClientInterceptor implements ClientInterceptor {
|
|||
try (Scope ignored = withScopedContext(context)) {
|
||||
delegate().onReady();
|
||||
} catch (Throwable e) {
|
||||
Span span = getSpan(context);
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, 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
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.auto.grpc.server;
|
||||
package io.opentelemetry.instrumentation.grpc.v1_5.server;
|
||||
|
||||
import io.grpc.Metadata;
|
||||
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
|
||||
public String get(Metadata carrier, String key) {
|
|
@ -3,7 +3,7 @@
|
|||
* 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;
|
||||
|
||||
|
@ -11,13 +11,19 @@ import io.grpc.Metadata;
|
|||
import io.grpc.Status;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator.Getter;
|
||||
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.Builder;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||
|
||||
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) {
|
||||
Builder spanBuilder =
|
|
@ -3,9 +3,8 @@
|
|||
* 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 io.grpc.ForwardingServerCall;
|
||||
|
@ -13,13 +12,15 @@ import io.grpc.ForwardingServerCallListener;
|
|||
import io.grpc.Grpc;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.ServerCall;
|
||||
import io.grpc.ServerCall.Listener;
|
||||
import io.grpc.ServerCallHandler;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.Status;
|
||||
import io.opentelemetry.common.Attributes;
|
||||
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.Tracer;
|
||||
import io.opentelemetry.trace.attributes.SemanticAttributes;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
@ -27,20 +28,39 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
|
||||
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
|
||||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
|
||||
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
||||
|
||||
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);
|
||||
InetSocketAddress iAddr = addr instanceof InetSocketAddress ? (InetSocketAddress) addr : null;
|
||||
GrpcHelper.prepareSpan(span, methodName, iAddr, true);
|
||||
SocketAddress address = call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
|
||||
if (address instanceof InetSocketAddress) {
|
||||
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;
|
||||
try (Scope ignored = currentContextWith(span)) {
|
||||
|
@ -48,36 +68,39 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
|||
try {
|
||||
// Wrap the server call so that we can decorate the span
|
||||
// with the resulting status
|
||||
TracingServerCall<ReqT, RespT> tracingServerCall = new TracingServerCall<>(span, call);
|
||||
TracingServerCall<ReqT, RespT> tracingServerCall =
|
||||
new TracingServerCall<>(call, span, tracer);
|
||||
|
||||
// call other interceptors
|
||||
result = next.startCall(tracingServerCall, headers);
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// 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>
|
||||
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);
|
||||
this.span = span;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(Status status, Metadata trailers) {
|
||||
TRACER.setStatus(span, status);
|
||||
tracer.setStatus(span, status);
|
||||
try (Scope ignored = currentContextWith(span)) {
|
||||
delegate().close(status, trailers);
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -86,11 +109,14 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
|||
static final class TracingServerCallListener<ReqT>
|
||||
extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
|
||||
private final Span span;
|
||||
private final GrpcServerTracer tracer;
|
||||
|
||||
private final AtomicLong messageId = new AtomicLong();
|
||||
|
||||
TracingServerCallListener(Span span, ServerCall.Listener<ReqT> delegate) {
|
||||
TracingServerCallListener(Listener<ReqT> delegate, Span span, GrpcServerTracer tracer) {
|
||||
super(delegate);
|
||||
this.span = span;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,7 +138,7 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
|||
try (Scope ignored = currentContextWith(span)) {
|
||||
delegate().onHalfClose();
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -123,10 +149,10 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
|||
delegate().onCancel();
|
||||
span.setAttribute("canceled", true);
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
TRACER.end(span);
|
||||
tracer.end(span);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,10 +160,10 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
|||
try (Scope ignored = currentContextWith(span)) {
|
||||
delegate().onComplete();
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, e);
|
||||
throw e;
|
||||
}
|
||||
TRACER.end(span);
|
||||
tracer.end(span);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,7 +171,7 @@ public class TracingServerInterceptor implements ServerInterceptor {
|
|||
try (Scope ignored = currentContextWith(span)) {
|
||||
delegate().onReady();
|
||||
} catch (Throwable e) {
|
||||
TRACER.endExceptionally(span, e);
|
||||
tracer.endExceptionally(span, 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
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.auto.grpc.common
|
||||
package io.opentelemetry.instrumentation.grpc.v1_5.common
|
||||
|
||||
import io.grpc.Status
|
||||
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
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.grpc.v1_5
|
||||
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||
import static io.opentelemetry.trace.Span.Kind.SERVER
|
||||
|
||||
|
@ -14,16 +16,22 @@ import io.grpc.ManagedChannelBuilder
|
|||
import io.grpc.Server
|
||||
import io.grpc.ServerBuilder
|
||||
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.trace.attributes.SemanticAttributes
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.TimeUnit
|
||||
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:
|
||||
def msgCount = serverMessageCount
|
||||
def serverReceived = new CopyOnWriteArrayList<>()
|
||||
|
@ -58,8 +66,8 @@ class GrpcStreamingTest extends AgentTestRunner {
|
|||
}
|
||||
}
|
||||
def port = PortUtils.randomOpenPort()
|
||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
||||
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||
|
||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||
try {
|
||||
|
@ -94,12 +102,6 @@ class GrpcStreamingTest extends AgentTestRunner {
|
|||
observer.onCompleted()
|
||||
|
||||
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) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
|
@ -111,8 +113,6 @@ class GrpcStreamingTest extends AgentTestRunner {
|
|||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||
"${SemanticAttributes.RPC_METHOD.key()}" "Conversation"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" port
|
||||
}
|
||||
(1..(clientMessageCount * serverMessageCount)).each {
|
||||
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:
|
||||
channel?.shutdownNow()?.awaitTermination(10, TimeUnit.SECONDS)
|
|
@ -3,6 +3,8 @@
|
|||
* 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.runUnderTrace
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||
|
@ -18,15 +20,21 @@ import io.grpc.ServerBuilder
|
|||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
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.instrumentation.auto.grpc.common.GrpcHelper
|
||||
import io.opentelemetry.trace.StatusCanonicalCode
|
||||
import io.opentelemetry.trace.attributes.SemanticAttributes
|
||||
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:
|
||||
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
||||
@Override
|
||||
|
@ -38,8 +46,8 @@ class GrpcTest extends AgentTestRunner {
|
|||
}
|
||||
}
|
||||
def port = PortUtils.randomOpenPort()
|
||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
||||
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||
|
||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||
try {
|
||||
|
@ -77,8 +85,6 @@ class GrpcTest extends AgentTestRunner {
|
|||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" port
|
||||
}
|
||||
}
|
||||
span(2) {
|
||||
|
@ -112,7 +118,7 @@ class GrpcTest extends AgentTestRunner {
|
|||
paramName << ["some name", "some other name"]
|
||||
}
|
||||
|
||||
def "test error - #name"() {
|
||||
def "test error - #paramName"() {
|
||||
setup:
|
||||
def error = grpcStatus.asException()
|
||||
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
||||
|
@ -123,8 +129,8 @@ class GrpcTest extends AgentTestRunner {
|
|||
}
|
||||
}
|
||||
def port = PortUtils.randomOpenPort()
|
||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
||||
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||
|
||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||
try {
|
||||
|
@ -148,13 +154,11 @@ class GrpcTest extends AgentTestRunner {
|
|||
kind CLIENT
|
||||
hasNoParent()
|
||||
errored true
|
||||
status(GrpcHelper.statusFromGrpcStatus(grpcStatus))
|
||||
status(StatusCanonicalCode.ERROR)
|
||||
attributes {
|
||||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" port
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
|
@ -162,7 +166,7 @@ class GrpcTest extends AgentTestRunner {
|
|||
kind SERVER
|
||||
childOf span(0)
|
||||
errored true
|
||||
status(GrpcHelper.statusFromGrpcStatus(grpcStatus))
|
||||
status(StatusCanonicalCode.ERROR)
|
||||
event(0) {
|
||||
eventName "message"
|
||||
attributes {
|
||||
|
@ -198,7 +202,7 @@ class GrpcTest extends AgentTestRunner {
|
|||
"StatusRuntime - description" | Status.UNIMPLEMENTED.withDescription("some description")
|
||||
}
|
||||
|
||||
def "test error thrown - #name"() {
|
||||
def "test error thrown - #paramName"() {
|
||||
setup:
|
||||
def error = grpcStatus.asRuntimeException()
|
||||
BindableService greeter = new GreeterGrpc.GreeterImplBase() {
|
||||
|
@ -209,8 +213,8 @@ class GrpcTest extends AgentTestRunner {
|
|||
}
|
||||
}
|
||||
def port = PortUtils.randomOpenPort()
|
||||
Server server = ServerBuilder.forPort(port).addService(greeter).build().start()
|
||||
ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress("localhost", port)
|
||||
Server server = configureServer(ServerBuilder.forPort(port).addService(greeter)).build().start()
|
||||
ManagedChannelBuilder channelBuilder = configureClient(ManagedChannelBuilder.forAddress("localhost", port))
|
||||
|
||||
// Depending on the version of gRPC usePlainText may or may not take an argument.
|
||||
try {
|
||||
|
@ -240,8 +244,6 @@ class GrpcTest extends AgentTestRunner {
|
|||
"${SemanticAttributes.RPC_SYSTEM.key()}" "grpc"
|
||||
"${SemanticAttributes.RPC_SERVICE.key()}" "example.Greeter"
|
||||
"${SemanticAttributes.RPC_METHOD.key()}" "SayHello"
|
||||
"${SemanticAttributes.NET_PEER_NAME.key()}" "localhost"
|
||||
"${SemanticAttributes.NET_PEER_PORT.key()}" Long
|
||||
}
|
||||
}
|
||||
span(1) {
|
||||
|
@ -249,7 +251,7 @@ class GrpcTest extends AgentTestRunner {
|
|||
kind SERVER
|
||||
childOf span(0)
|
||||
errored true
|
||||
status(GrpcHelper.statusFromGrpcStatus(grpcStatus))
|
||||
status(StatusCanonicalCode.ERROR)
|
||||
event(0) {
|
||||
eventName "message"
|
||||
attributes {
|
|
@ -88,7 +88,9 @@ include ':instrumentation:geode-1.4'
|
|||
include ':instrumentation:google-http-client-1.19'
|
||||
include ':instrumentation:grizzly-2.0'
|
||||
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:hibernate:hibernate-3.3'
|
||||
include ':instrumentation:hibernate:hibernate-4.0'
|
||||
|
|
Loading…
Reference in New Issue