Skip to content

Commit c45ee61

Browse files
committed
Retrieve gRPC server.address/server.port from target
1 parent f27845a commit c45ee61

18 files changed

Lines changed: 556 additions & 72 deletions

File tree

instrumentation/armeria/armeria-grpc-1.14/javaagent/build.gradle.kts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ tasks.test {
6363
systemProperty("collectMetadata", findProperty("collectMetadata")?.toString() ?: "false")
6464
}
6565

66+
tasks {
67+
val testStableSemconv by registering(Test::class) {
68+
testClassesDirs = sourceSets.test.get().output.classesDirs
69+
classpath = sourceSets.test.get().runtimeClasspath
70+
71+
jvmArgs("-Dotel.semconv-stability.opt-in=rpc")
72+
systemProperty("metadataConfig", "otel.semconv-stability.opt-in=rpc")
73+
}
74+
75+
check {
76+
dependsOn(testStableSemconv)
77+
}
78+
}
79+
6680
if (findProperty("denyUnsafe") as Boolean) {
6781
tasks.withType<Test>().configureEach {
6882
enabled = false

instrumentation/armeria/armeria-grpc-1.14/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/armeria/grpc/v1_14/ArmeriaGrpcClientBuilderInstrumentation.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111

1212
import com.linecorp.armeria.client.grpc.GrpcClientBuilder;
1313
import io.opentelemetry.api.GlobalOpenTelemetry;
14+
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
1415
import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry;
16+
import io.opentelemetry.instrumentation.grpc.v1_6.internal.Internal;
1517
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
1618
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
19+
import java.net.URI;
20+
import javax.annotation.Nullable;
1721
import net.bytebuddy.asm.Advice;
1822
import net.bytebuddy.description.type.TypeDescription;
1923
import net.bytebuddy.matcher.ElementMatcher;
@@ -36,8 +40,14 @@ public void transform(TypeTransformer transformer) {
3640
public static class BuildAdvice {
3741

3842
@Advice.OnMethodEnter
39-
public static void onEnter(@Advice.This GrpcClientBuilder builder) {
40-
builder.intercept(GrpcTelemetry.create(GlobalOpenTelemetry.get()).createClientInterceptor());
43+
public static void onEnter(
44+
@Advice.This GrpcClientBuilder builder, @Advice.FieldValue("uri") @Nullable URI uri) {
45+
String target = null;
46+
if (SemconvStability.emitStableRpcSemconv() && uri != null) {
47+
target = uri.getAuthority();
48+
}
49+
GrpcTelemetry telemetry = GrpcTelemetry.create(GlobalOpenTelemetry.get());
50+
builder.intercept(Internal.createClientInterceptor(telemetry, target));
4151
}
4252
}
4353
}

instrumentation/grpc-1.6/javaagent/build.gradle.kts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ dependencies {
3131
val collectMetadata = findProperty("collectMetadata")?.toString() ?: "false"
3232

3333
tasks {
34-
test {
34+
withType<Test>().configureEach {
3535
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
3636
// The agent context debug mechanism isn't compatible with the bridge approach which may add a
3737
// gRPC context to the root.
@@ -56,26 +56,20 @@ tasks {
5656
testClassesDirs = sourceSets.test.get().output.classesDirs
5757
classpath = sourceSets.test.get().runtimeClasspath
5858

59-
// replicated base config from standard test task
60-
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
61-
jvmArgs("-Dotel.javaagent.experimental.thread-propagation-debugger.enabled=false")
62-
jvmArgs("-Dotel.instrumentation.grpc.capture-metadata.client.request=some-client-key")
63-
jvmArgs("-Dotel.instrumentation.grpc.capture-metadata.server.request=some-server-key")
64-
jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true")
65-
66-
// exclude our grpc library instrumentation, the ContextStorageOverride contained within it
67-
// breaks the tests
68-
classpath = classpath.filter {
69-
!it.absolutePath.contains("opentelemetry-grpc-1.6")
70-
}
71-
72-
systemProperty("collectMetadata", collectMetadata)
7359
systemProperty("metadataConfig", "otel.instrumentation.grpc.experimental-span-attributes=true")
7460
jvmArgs("-Dotel.instrumentation.grpc.experimental-span-attributes=true")
7561
}
7662

63+
val testStableSemconv by registering(Test::class) {
64+
testClassesDirs = sourceSets.test.get().output.classesDirs
65+
classpath = sourceSets.test.get().runtimeClasspath
66+
67+
jvmArgs("-Dotel.semconv-stability.opt-in=rpc")
68+
systemProperty("metadataConfig", "otel.semconv-stability.opt-in=rpc")
69+
}
70+
7771
check {
78-
dependsOn(testExperimental)
72+
dependsOn(testExperimental, testStableSemconv)
7973
}
8074
}
8175

instrumentation/grpc-1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grpc/v1_6/GrpcClientBuilderBuildInstrumentation.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import io.grpc.ClientInterceptor;
1616
import io.grpc.ManagedChannelBuilder;
17+
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
1718
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
1819
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
1920
import java.util.List;
@@ -30,7 +31,8 @@ public ElementMatcher<ClassLoader> classLoaderOptimization() {
3031
@Override
3132
public ElementMatcher<TypeDescription> typeMatcher() {
3233
return extendsClass(named("io.grpc.ManagedChannelBuilder"))
33-
.and(declaresField(named("interceptors")));
34+
.and(declaresField(named("interceptors")))
35+
.and(declaresField(named("target")));
3436
}
3537

3638
@Override
@@ -46,9 +48,11 @@ public static class AddInterceptorAdvice {
4648
@Advice.OnMethodEnter(suppress = Throwable.class)
4749
public static void addInterceptor(
4850
@Advice.This ManagedChannelBuilder<?> builder,
49-
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors) {
51+
@Advice.FieldValue("interceptors") List<ClientInterceptor> interceptors,
52+
@Advice.FieldValue("target") String target) {
5053
if (!Boolean.TRUE.equals(MANAGED_CHANNEL_BUILDER_INSTRUMENTED.get(builder))) {
51-
interceptors.add(0, GrpcSingletons.CLIENT_INTERCEPTOR);
54+
String effectiveTarget = SemconvStability.emitStableRpcSemconv() ? target : null;
55+
interceptors.add(0, GrpcSingletons.createClientInterceptor(effectiveTarget));
5256
MANAGED_CHANNEL_BUILDER_INSTRUMENTED.set(builder, true);
5357
}
5458
}

instrumentation/grpc-1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/grpc/v1_6/GrpcSingletons.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import io.opentelemetry.instrumentation.api.util.VirtualField;
1919
import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry;
2020
import io.opentelemetry.instrumentation.grpc.v1_6.internal.ContextStorageBridge;
21+
import io.opentelemetry.instrumentation.grpc.v1_6.internal.Internal;
2122
import java.util.List;
2223
import java.util.concurrent.atomic.AtomicReference;
24+
import javax.annotation.Nullable;
2325

2426
// Holds singleton references.
2527
public final class GrpcSingletons {
@@ -31,7 +33,7 @@ public final class GrpcSingletons {
3133
public static final VirtualField<ServerBuilder<?>, Boolean> SERVER_BUILDER_INSTRUMENTED =
3234
VirtualField.find(ServerBuilder.class, Boolean.class);
3335

34-
public static final ClientInterceptor CLIENT_INTERCEPTOR;
36+
private static final GrpcTelemetry TELEMETRY;
3537

3638
public static final ServerInterceptor SERVER_INTERCEPTOR;
3739

@@ -64,10 +66,14 @@ public final class GrpcSingletons {
6466
.setCapturedServerRequestMetadata(serverRequestMetadata)
6567
.build();
6668

67-
CLIENT_INTERCEPTOR = telemetry.createClientInterceptor();
69+
TELEMETRY = telemetry;
6870
SERVER_INTERCEPTOR = telemetry.createServerInterceptor();
6971
}
7072

73+
public static ClientInterceptor createClientInterceptor(@Nullable String target) {
74+
return Internal.createClientInterceptor(TELEMETRY, target);
75+
}
76+
7177
public static Context.Storage getStorage() {
7278
return STORAGE_REFERENCE.get();
7379
}

instrumentation/grpc-1.6/library/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ The instrumentation library provides the implementation of `ClientInterceptor` a
3434
// For client-side, attach the interceptor to your channel builder.
3535
void configureClientInterceptor(OpenTelemetry openTelemetry, NettyChannelBuilder nettyChannelBuilder) {
3636
GrpcTelemetry grpcTelemetry = GrpcTelemetry.create(openTelemetry);
37-
nettyChannelBuilder.intercept(grpcTelemetry.createClientInterceptor());
37+
grpcTelemetry.addClientInterceptor(nettyChannelBuilder);
3838
}
3939

4040
// For server-side, attatch the interceptor to your service.

instrumentation/grpc-1.6/library/src/main/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcNetworkServerAttributesGetter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ final class GrpcNetworkServerAttributesGetter
1818
@Nullable
1919
@Override
2020
public String getServerAddress(GrpcRequest grpcRequest) {
21-
return grpcRequest.getLogicalHost();
21+
return grpcRequest.getServerAddress();
2222
}
2323

2424
@Override
2525
public Integer getServerPort(GrpcRequest grpcRequest) {
26-
return grpcRequest.getLogicalPort();
26+
return grpcRequest.getServerPort();
2727
}
2828

2929
@Nullable

instrumentation/grpc-1.6/library/src/main/java/io/opentelemetry/instrumentation/grpc/v1_6/GrpcRequest.java

Lines changed: 110 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import io.grpc.Metadata;
99
import io.grpc.MethodDescriptor;
10+
import io.opentelemetry.instrumentation.grpc.v1_6.internal.ParsedTarget;
1011
import java.net.SocketAddress;
1112
import javax.annotation.Nullable;
1213

@@ -15,40 +16,65 @@ public final class GrpcRequest {
1516
private final MethodDescriptor<?, ?> method;
1617

1718
@Nullable private volatile Metadata metadata;
18-
19-
@Nullable private volatile String logicalHost;
20-
private volatile int logicalPort = -1;
19+
@Nullable private final String serverAddress;
20+
@Nullable private final Integer serverPort;
2121
@Nullable private volatile SocketAddress peerSocketAddress;
2222

2323
private Long requestSize;
2424
private Long responseSize;
2525

26-
GrpcRequest(
26+
/**
27+
* Creates a client-side gRPC request.
28+
*
29+
* @param method the gRPC method descriptor
30+
* @param authority the channel authority (host:port)
31+
* @param parsedTarget the pre-parsed gRPC target (from {@link
32+
* io.opentelemetry.instrumentation.grpc.v1_6.internal.GrpcTargetParser#parse}), or {@code
33+
* null} if unavailable
34+
*/
35+
public static GrpcRequest createClientRequest(
36+
MethodDescriptor<?, ?> method,
37+
@Nullable String authority,
38+
@Nullable ParsedTarget parsedTarget) {
39+
if (parsedTarget != null) {
40+
return new GrpcRequest(method, null, null, parsedTarget.getAddress(), parsedTarget.getPort());
41+
}
42+
return new GrpcRequest(
43+
method, null, null, hostFromAuthority(authority), portFromAuthority(authority));
44+
}
45+
46+
/**
47+
* Creates a server-side gRPC request.
48+
*
49+
* @param method the gRPC method descriptor
50+
* @param metadata the request metadata
51+
* @param peerSocketAddress the peer socket address
52+
* @param authority the request authority
53+
*/
54+
public static GrpcRequest createServerRequest(
2755
MethodDescriptor<?, ?> method,
2856
@Nullable Metadata metadata,
2957
@Nullable SocketAddress peerSocketAddress,
3058
@Nullable String authority) {
59+
return new GrpcRequest(
60+
method,
61+
metadata,
62+
peerSocketAddress,
63+
hostFromAuthority(authority),
64+
portFromAuthority(authority));
65+
}
66+
67+
private GrpcRequest(
68+
MethodDescriptor<?, ?> method,
69+
@Nullable Metadata metadata,
70+
@Nullable SocketAddress peerSocketAddress,
71+
@Nullable String serverAddress,
72+
@Nullable Integer serverPort) {
3173
this.method = method;
3274
this.metadata = metadata;
3375
this.peerSocketAddress = peerSocketAddress;
34-
setLogicalAddress(authority);
35-
}
36-
37-
private void setLogicalAddress(@Nullable String authority) {
38-
if (authority == null) {
39-
return;
40-
}
41-
int index = authority.indexOf(':');
42-
if (index == -1) {
43-
logicalHost = authority;
44-
} else {
45-
logicalHost = authority.substring(0, index);
46-
try {
47-
logicalPort = Integer.parseInt(authority.substring(index + 1));
48-
} catch (NumberFormatException e) {
49-
// ignore
50-
}
51-
}
76+
this.serverAddress = serverAddress;
77+
this.serverPort = serverPort;
5278
}
5379

5480
public MethodDescriptor<?, ?> getMethod() {
@@ -64,13 +90,45 @@ void setMetadata(Metadata metadata) {
6490
this.metadata = metadata;
6591
}
6692

93+
/**
94+
* Returns the server address.
95+
*
96+
* <p>When a target string is available (from gRPC channel configuration), the server address is
97+
* extracted per the <a href="https://grpc.github.io/grpc/core/md_doc_naming.html">gRPC Name
98+
* Resolution spec</a>. Otherwise, falls back to the authority (host portion).
99+
*/
100+
@Nullable
101+
public String getServerAddress() {
102+
return serverAddress;
103+
}
104+
105+
/**
106+
* Returns the server port.
107+
*
108+
* <p>When a target string is available (from gRPC channel configuration), the server port is
109+
* extracted per the <a href="https://grpc.github.io/grpc/core/md_doc_naming.html">gRPC Name
110+
* Resolution spec</a>. Otherwise, falls back to the authority (port portion).
111+
*/
112+
@Nullable
113+
public Integer getServerPort() {
114+
return serverPort;
115+
}
116+
117+
/**
118+
* @deprecated Use {@link #getServerAddress()} instead.
119+
*/
120+
@Deprecated
67121
@Nullable
68122
public String getLogicalHost() {
69-
return logicalHost;
123+
return serverAddress;
70124
}
71125

126+
/**
127+
* @deprecated Use {@link #getServerPort()} instead.
128+
*/
129+
@Deprecated
72130
public int getLogicalPort() {
73-
return logicalPort;
131+
return serverPort != null ? serverPort : -1;
74132
}
75133

76134
@Nullable
@@ -97,4 +155,32 @@ public Long getResponseSize() {
97155
public void setResponseSize(Long responseSize) {
98156
this.responseSize = responseSize;
99157
}
158+
159+
@Nullable
160+
private static String hostFromAuthority(@Nullable String authority) {
161+
if (authority == null) {
162+
return null;
163+
}
164+
int index = authority.indexOf(':');
165+
if (index == -1) {
166+
return authority;
167+
}
168+
return authority.substring(0, index);
169+
}
170+
171+
@Nullable
172+
private static Integer portFromAuthority(@Nullable String authority) {
173+
if (authority == null) {
174+
return null;
175+
}
176+
int index = authority.indexOf(':');
177+
if (index == -1) {
178+
return null;
179+
}
180+
try {
181+
return Integer.parseInt(authority.substring(index + 1));
182+
} catch (NumberFormatException e) {
183+
return null;
184+
}
185+
}
100186
}

0 commit comments

Comments
 (0)