Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@

package io.opentelemetry.javaagent.instrumentation.armeria.grpc.v1_14;

import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableRpcSemconv;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;

import com.linecorp.armeria.client.grpc.GrpcClientBuilder;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry;
import io.opentelemetry.instrumentation.grpc.v1_6.internal.Internal;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.net.URI;
import javax.annotation.Nullable;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
Expand All @@ -34,8 +38,14 @@ public void transform(TypeTransformer transformer) {
public static class BuildAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void onEnter(@Advice.This GrpcClientBuilder builder) {
builder.intercept(GrpcTelemetry.create(GlobalOpenTelemetry.get()).createClientInterceptor());
public static void onEnter(
@Advice.This GrpcClientBuilder builder, @Advice.FieldValue("uri") @Nullable URI uri) {
String target = null;
if (emitStableRpcSemconv() && uri != null) {
target = uri.getAuthority();
}
GrpcTelemetry telemetry = GrpcTelemetry.create(GlobalOpenTelemetry.get());
builder.intercept(Internal.createClientInterceptor(telemetry, target));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.javaagent.instrumentation.grpc.v1_6;

import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableRpcSemconv;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.instrumentation.grpc.v1_6.GrpcSingletons.MANAGED_CHANNEL_BUILDER_INSTRUMENTED;
Expand All @@ -30,7 +31,8 @@ public ElementMatcher<ClassLoader> classLoaderOptimization() {
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return extendsClass(named("io.grpc.ManagedChannelBuilder"))
.and(declaresField(named("interceptors")));
.and(declaresField(named("interceptors")))
.and(declaresField(named("target")));
}

@Override
Expand All @@ -44,9 +46,14 @@ public static class AddInterceptorAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void addInterceptor(
@Advice.This ManagedChannelBuilder<?> builder,
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors) {
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors,
@Advice.FieldValue("target") String target) {
if (!Boolean.TRUE.equals(MANAGED_CHANNEL_BUILDER_INSTRUMENTED.get(builder))) {
interceptors.add(0, clientInterceptor());
ClientInterceptor interceptor =
emitStableRpcSemconv()
? GrpcSingletons.createClientInterceptor(target)
: clientInterceptor();
interceptors.add(0, interceptor);
MANAGED_CHANNEL_BUILDER_INSTRUMENTED.set(builder, true);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.opentelemetry.instrumentation.api.util.VirtualField;
import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry;
import io.opentelemetry.instrumentation.grpc.v1_6.internal.ContextStorageBridge;
import io.opentelemetry.instrumentation.grpc.v1_6.internal.Internal;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
Expand All @@ -32,6 +33,8 @@ public class GrpcSingletons {
public static final VirtualField<ServerBuilder<?>, Boolean> SERVER_BUILDER_INSTRUMENTED =
VirtualField.find(ServerBuilder.class, Boolean.class);

private static final GrpcTelemetry telemetry;

private static final ClientInterceptor clientInterceptor;

private static final ServerInterceptor serverInterceptor;
Expand All @@ -57,16 +60,17 @@ public class GrpcSingletons {
.get("server")
.getScalarList("request", String.class, emptyList());

GrpcTelemetry telemetry =
GrpcTelemetry configuredTelemetry =
GrpcTelemetry.builder(GlobalOpenTelemetry.get())
.setEmitMessageEvents(emitMessageEvents)
.setCaptureExperimentalSpanAttributes(experimentalSpanAttributes)
.setCapturedClientRequestMetadata(clientRequestMetadata)
.setCapturedServerRequestMetadata(serverRequestMetadata)
.build();

clientInterceptor = telemetry.createClientInterceptor();
serverInterceptor = telemetry.createServerInterceptor();
telemetry = configuredTelemetry;
clientInterceptor = Internal.createClientInterceptor(configuredTelemetry, null);
serverInterceptor = configuredTelemetry.createServerInterceptor();
}

public static ClientInterceptor clientInterceptor() {
Expand All @@ -82,6 +86,10 @@ public static Context.Storage storage() {
return storageReference.get();
}

public static ClientInterceptor createClientInterceptor(@Nullable String target) {
return Internal.createClientInterceptor(telemetry, target);
}

public static Context.Storage setStorage(Context.Storage storage) {
storageReference.compareAndSet(null, new ContextStorageBridge(storage));
return storage();
Expand Down
2 changes: 1 addition & 1 deletion instrumentation/grpc-1.6/library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The instrumentation library provides the implementation of `ClientInterceptor` a
// For client-side, attach the interceptor to your channel builder.
void configureClientInterceptor(OpenTelemetry openTelemetry, NettyChannelBuilder nettyChannelBuilder) {
GrpcTelemetry grpcTelemetry = GrpcTelemetry.create(openTelemetry);
nettyChannelBuilder.intercept(grpcTelemetry.createClientInterceptor());
grpcTelemetry.addClientInterceptor(nettyChannelBuilder);
}

// For server-side, attatch the interceptor to your service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.opentelemetry.instrumentation.grpc.v1_6.internal.GrpcTargetParser;
import io.opentelemetry.instrumentation.grpc.v1_6.internal.ParsedTarget;
import java.net.SocketAddress;
import javax.annotation.Nullable;

Expand All @@ -15,40 +17,67 @@ public final class GrpcRequest {
private final MethodDescriptor<?, ?> method;

@Nullable private volatile Metadata metadata;

@Nullable private volatile String logicalHost;
private volatile int logicalPort = -1;
@Nullable private final String serverAddress;
@Nullable private final Integer serverPort;
@Nullable private volatile SocketAddress peerSocketAddress;

@Nullable private volatile Long requestSize;
@Nullable private volatile Long responseSize;

GrpcRequest(
/**
* Creates a client-side gRPC request.
*
* @param method the gRPC method descriptor
* @param authority the channel authority (host:port)
* @param parsedTarget the pre-parsed gRPC target (from {@link
* io.opentelemetry.instrumentation.grpc.v1_6.internal.GrpcTargetParser#parse}), or {@code
* null} if unavailable
*/
static GrpcRequest createClientRequest(
MethodDescriptor<?, ?> method,
@Nullable String authority,
@Nullable ParsedTarget parsedTarget) {
ParsedTarget effective =
parsedTarget != null ? parsedTarget : GrpcTargetParser.parseAuthority(authority);
if (effective == null) {
return new GrpcRequest(method, null, null, null, null);
}
return new GrpcRequest(method, null, null, effective.getAddress(), effective.getPort());
}

/**
* Creates a server-side gRPC request.
*
* @param method the gRPC method descriptor
* @param metadata the request metadata
* @param peerSocketAddress the peer socket address
* @param authority the request authority
*/
static GrpcRequest createServerRequest(
MethodDescriptor<?, ?> method,
@Nullable Metadata metadata,
@Nullable SocketAddress peerSocketAddress,
@Nullable String authority) {
ParsedTarget parsed = GrpcTargetParser.parseAuthority(authority);
return new GrpcRequest(
method,
metadata,
peerSocketAddress,
parsed != null ? parsed.getAddress() : null,
parsed != null ? parsed.getPort() : null);
}

private GrpcRequest(
MethodDescriptor<?, ?> method,
@Nullable Metadata metadata,
@Nullable SocketAddress peerSocketAddress,
@Nullable String serverAddress,
@Nullable Integer serverPort) {
this.method = method;
this.metadata = metadata;
this.peerSocketAddress = peerSocketAddress;
setLogicalAddress(authority);
}

private void setLogicalAddress(@Nullable String authority) {
if (authority == null) {
return;
}
int index = authority.indexOf(':');
if (index == -1) {
logicalHost = authority;
} else {
logicalHost = authority.substring(0, index);
try {
logicalPort = Integer.parseInt(authority.substring(index + 1));
} catch (NumberFormatException e) {
// ignore
}
}
this.serverAddress = serverAddress;
this.serverPort = serverPort;
}

public MethodDescriptor<?, ?> getMethod() {
Expand All @@ -64,13 +93,45 @@ void setMetadata(Metadata metadata) {
this.metadata = metadata;
}

/**
* Returns the server address.
*
* <p>When a target string is available (from gRPC channel configuration), the server address is
* extracted per the <a href="https://grpc.github.io/grpc/core/md_doc_naming.html">gRPC Name
* Resolution spec</a>. Otherwise, falls back to the authority (host portion).
*/
@Nullable
public String getServerAddress() {
return serverAddress;
}

/**
* Returns the server port.
*
* <p>When a target string is available (from gRPC channel configuration), the server port is
* extracted per the <a href="https://grpc.github.io/grpc/core/md_doc_naming.html">gRPC Name
* Resolution spec</a>. Otherwise, falls back to the authority (port portion).
*/
@Nullable
public Integer getServerPort() {
return serverPort;
}

/**
* @deprecated Use {@link #getServerAddress()} instead.
*/
@Deprecated
@Nullable
public String getLogicalHost() {
return logicalHost;
return serverAddress;
}

/**
* @deprecated Use {@link #getServerPort()} instead.
*/
@Deprecated
public int getLogicalPort() {
return logicalPort;
return serverPort != null ? serverPort : -1;
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ final class GrpcServerNetworkAttributesGetter
@Nullable
@Override
public String getServerAddress(GrpcRequest grpcRequest) {
return grpcRequest.getLogicalHost();
return grpcRequest.getServerAddress();
}

@Override
@Nullable
public Integer getServerPort(GrpcRequest grpcRequest) {
int port = grpcRequest.getLogicalPort();
return port == -1 ? null : port;
return grpcRequest.getServerPort();
}

@Nullable
Expand Down
Loading
Loading