Visitar URL original
feat: pass whole context to traced callables · googleapis/sdk-platform-java@e5b927a · GitHub
Skip to content
This repository was archived by the owner on Oct 29, 2026. It is now read-only.

Commit e5b927a

Browse files
committed
feat: pass whole context to traced callables
1 parent 105f644 commit e5b927a

14 files changed

Lines changed: 176 additions & 40 deletions

File tree

‎gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallableFactory.java‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.google.api.gax.rpc.Callables;
3737
import com.google.api.gax.rpc.ClientContext;
3838
import com.google.api.gax.rpc.ClientStreamingCallable;
39+
import com.google.api.gax.rpc.LibraryMetadata;
3940
import com.google.api.gax.rpc.LongRunningClient;
4041
import com.google.api.gax.rpc.OperationCallSettings;
4142
import com.google.api.gax.rpc.OperationCallable;
@@ -46,6 +47,7 @@
4647
import com.google.api.gax.rpc.StreamingCallSettings;
4748
import com.google.api.gax.rpc.UnaryCallSettings;
4849
import com.google.api.gax.rpc.UnaryCallable;
50+
import com.google.api.gax.tracing.ApiTracerContext;
4951
import com.google.api.gax.tracing.SpanName;
5052
import com.google.api.gax.tracing.TracedBatchingCallable;
5153
import com.google.api.gax.tracing.TracedBidiCallable;
@@ -66,7 +68,8 @@
6668
/** Class with utility methods to create grpc-based direct callables. */
6769
public class GrpcCallableFactory {
6870
// Used to extract service and method name from a grpc MethodDescriptor.
69-
private static final Pattern FULL_METHOD_NAME_REGEX = Pattern.compile("^.*?([^./]+)/([^./]+)$");
71+
private static final String FULL_METHOD_NAME_REGEX = "^.*?([^./]+)/([^./]+)$";
72+
private static final Pattern FULL_METHOD_NAME_PATTERN = Pattern.compile(FULL_METHOD_NAME_REGEX);
7073

7174
private GrpcCallableFactory() {}
7275

@@ -112,7 +115,7 @@ public static <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> createUna
112115
new TracedUnaryCallable<>(
113116
callable,
114117
clientContext.getTracerFactory(),
115-
getSpanName(grpcCallSettings.getMethodDescriptor()));
118+
getApiTracerContext(grpcCallSettings.getMethodDescriptor()));
116119

117120
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
118121
}
@@ -161,7 +164,7 @@ public static <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> createBat
161164
new TracedBatchingCallable<>(
162165
baseCallable,
163166
clientContext.getTracerFactory(),
164-
getSpanName(grpcCallSettings.getMethodDescriptor()),
167+
getApiTracerContext(grpcCallSettings.getMethodDescriptor()),
165168
batchingCallSettings.getBatchingDescriptor());
166169

167170
UnaryCallable<RequestT, ResponseT> batchingCallable =
@@ -200,7 +203,7 @@ OperationCallable<RequestT, ResponseT, MetadataT> createOperationCallable(
200203
// Create a sub-trace for the initial RPC that starts the operation.
201204
UnaryCallable<RequestT, OperationSnapshot> tracedInitialCallable =
202205
new TracedOperationInitialCallable<>(
203-
initialCallable, clientContext.getTracerFactory(), initialSpanName);
206+
initialCallable, clientContext.getTracerFactory(), getApiTracerContext(grpcCallSettings.getMethodDescriptor()));
204207

205208
LongRunningClient longRunningClient = new GrpcLongRunningClient(operationsStub);
206209
OperationCallable<RequestT, ResponseT, MetadataT> operationCallable =
@@ -209,7 +212,7 @@ OperationCallable<RequestT, ResponseT, MetadataT> createOperationCallable(
209212

210213
OperationCallable<RequestT, ResponseT, MetadataT> tracedOperationCallable =
211214
new TracedOperationCallable<>(
212-
operationCallable, clientContext.getTracerFactory(), operationSpanName);
215+
operationCallable, clientContext.getTracerFactory(), getApiTracerContext(grpcCallSettings.getMethodDescriptor()));
213216

214217
return tracedOperationCallable.withDefaultCallContext(clientContext.getDefaultCallContext());
215218
}
@@ -237,7 +240,7 @@ BidiStreamingCallable<RequestT, ResponseT> createBidiStreamingCallable(
237240
new TracedBidiCallable<>(
238241
callable,
239242
clientContext.getTracerFactory(),
240-
getSpanName(grpcCallSettings.getMethodDescriptor()));
243+
getApiTracerContext(grpcCallSettings.getMethodDescriptor()));
241244

242245
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
243246
}
@@ -295,7 +298,7 @@ ServerStreamingCallable<RequestT, ResponseT> createServerStreamingCallable(
295298
new TracedServerStreamingCallable<>(
296299
callable,
297300
clientContext.getTracerFactory(),
298-
getSpanName(grpcCallSettings.getMethodDescriptor()));
301+
getApiTracerContext(grpcCallSettings.getMethodDescriptor()));
299302

300303
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
301304
}
@@ -323,16 +326,26 @@ ClientStreamingCallable<RequestT, ResponseT> createClientStreamingCallable(
323326
new TracedClientStreamingCallable<>(
324327
callable,
325328
clientContext.getTracerFactory(),
326-
getSpanName(grpcCallSettings.getMethodDescriptor()));
329+
getApiTracerContext(grpcCallSettings.getMethodDescriptor()));
327330

328331
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
329332
}
330333

331334
@InternalApi("Visible for testing")
332335
static SpanName getSpanName(@Nonnull MethodDescriptor<?, ?> methodDescriptor) {
333-
Matcher matcher = FULL_METHOD_NAME_REGEX.matcher(methodDescriptor.getFullMethodName());
336+
Matcher matcher = FULL_METHOD_NAME_PATTERN.matcher(methodDescriptor.getFullMethodName());
334337

335338
Preconditions.checkArgument(matcher.matches(), "Invalid fullMethodName");
336339
return SpanName.of(matcher.group(1), matcher.group(2));
337340
}
341+
342+
private static ApiTracerContext getApiTracerContext(
343+
@Nonnull MethodDescriptor<?, ?> methodDescriptor) {
344+
return ApiTracerContext.newBuilder()
345+
.setRpcSystemName("grpc")
346+
.setRpcMethod(methodDescriptor.getFullMethodName())
347+
.setFullMethodNameRegex(FULL_METHOD_NAME_REGEX)
348+
.setLibraryMetadata(LibraryMetadata.empty())
349+
.build();
350+
}
338351
}

‎gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallableFactory.java‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.google.api.gax.rpc.BatchingCallSettings;
3636
import com.google.api.gax.rpc.Callables;
3737
import com.google.api.gax.rpc.ClientContext;
38+
import com.google.api.gax.rpc.LibraryMetadata;
3839
import com.google.api.gax.rpc.LongRunningClient;
3940
import com.google.api.gax.rpc.OperationCallSettings;
4041
import com.google.api.gax.rpc.OperationCallable;
@@ -43,6 +44,7 @@
4344
import com.google.api.gax.rpc.ServerStreamingCallable;
4445
import com.google.api.gax.rpc.UnaryCallSettings;
4546
import com.google.api.gax.rpc.UnaryCallable;
47+
import com.google.api.gax.tracing.ApiTracerContext;
4648
import com.google.api.gax.tracing.SpanName;
4749
import com.google.api.gax.tracing.TracedUnaryCallable;
4850
import com.google.common.base.Preconditions;
@@ -55,7 +57,8 @@ public class HttpJsonCallableFactory {
5557
// Used to extract service and method name from a grpc MethodDescriptor.
5658
// fullMethodName has the format: service.resource.action
5759
// For example: compute.instances.addAccessConfig
58-
private static final Pattern FULL_METHOD_NAME_REGEX = Pattern.compile("^(.+)\\.(.+)$");
60+
private static final String FULL_METHOD_NAME_REGEX = "^(.+)\\.(.+)$";
61+
private static final Pattern FULL_METHOD_NAME_PATTERN = Pattern.compile(FULL_METHOD_NAME_REGEX);
5962

6063
private HttpJsonCallableFactory() {}
6164

@@ -88,7 +91,7 @@ static <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> createUnaryCalla
8891
new TracedUnaryCallable<>(
8992
callable,
9093
clientContext.getTracerFactory(),
91-
getSpanName(httpJsonCallSettings.getMethodDescriptor()));
94+
getApiTracerContext(httpJsonCallSettings.getMethodDescriptor()));
9295
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
9396
}
9497

@@ -228,9 +231,19 @@ ServerStreamingCallable<RequestT, ResponseT> createServerStreamingCallable(
228231

229232
@InternalApi("Visible for testing")
230233
static SpanName getSpanName(@Nonnull ApiMethodDescriptor<?, ?> methodDescriptor) {
231-
Matcher matcher = FULL_METHOD_NAME_REGEX.matcher(methodDescriptor.getFullMethodName());
234+
Matcher matcher = FULL_METHOD_NAME_PATTERN.matcher(methodDescriptor.getFullMethodName());
232235

233236
Preconditions.checkArgument(matcher.matches(), "Invalid fullMethodName");
234237
return SpanName.of(matcher.group(1), matcher.group(2));
235238
}
239+
240+
private static ApiTracerContext getApiTracerContext(
241+
@Nonnull ApiMethodDescriptor<?, ?> methodDescriptor) {
242+
return ApiTracerContext.newBuilder()
243+
.setRpcSystemName("http")
244+
.setRpcMethod(methodDescriptor.getFullMethodName())
245+
.setFullMethodNameRegex(FULL_METHOD_NAME_REGEX)
246+
.setLibraryMetadata(LibraryMetadata.empty())
247+
.build();
248+
}
236249
}

‎gax-java/gax/src/main/java/com/google/api/gax/rpc/LibraryMetadata.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public static LibraryMetadata empty() {
5555
return newBuilder().build();
5656
}
5757

58+
public boolean isEmpty() {
59+
return repository() == null && artifactName() == null;
60+
}
61+
5862
public static LibraryMetadata.Builder newBuilder() {
5963
return new AutoValue_LibraryMetadata.Builder();
6064
}

‎gax-java/gax/src/main/java/com/google/api/gax/tracing/ApiTracerContext.java‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@
3333
import com.google.api.core.InternalApi;
3434
import com.google.api.gax.rpc.LibraryMetadata;
3535
import com.google.auto.value.AutoValue;
36+
import com.google.common.base.Preconditions;
3637
import java.util.HashMap;
3738
import java.util.Map;
39+
import java.util.regex.Matcher;
40+
import java.util.regex.Pattern;
3841
import javax.annotation.Nullable;
3942

4043
/**
@@ -51,6 +54,15 @@ public abstract class ApiTracerContext {
5154

5255
public abstract LibraryMetadata libraryMetadata();
5356

57+
@Nullable
58+
public abstract String rpcSystemName();
59+
60+
@Nullable
61+
public abstract String rpcMethod();
62+
63+
@Nullable
64+
public abstract String fullMethodNameRegex();
65+
5466
/**
5567
* @return a map of attributes to be included in attempt-level spans
5668
*/
@@ -59,6 +71,12 @@ public Map<String, String> getAttemptAttributes() {
5971
if (serverAddress() != null) {
6072
attributes.put(ObservabilityAttributes.SERVER_ADDRESS_ATTRIBUTE, serverAddress());
6173
}
74+
if (rpcMethod() != null) {
75+
attributes.put(ObservabilityAttributes.RPC_METHOD_ATTRIBUTE, rpcMethod());
76+
}
77+
if (rpcSystemName() != null) {
78+
attributes.put(ObservabilityAttributes.RPC_SYSTEM_NAME_ATTRIBUTE, rpcSystemName());
79+
}
6280
if (libraryMetadata().repository() != null) {
6381
attributes.put(ObservabilityAttributes.REPO_ATTRIBUTE, libraryMetadata().repository());
6482
}
@@ -68,6 +86,47 @@ public Map<String, String> getAttemptAttributes() {
6886
return attributes;
6987
}
7088

89+
/**
90+
* @return a {@link SpanName} object constructed from the rpcMethod and fullMethodNameRegex
91+
*/
92+
public SpanName getSpanName() {
93+
Preconditions.checkState(rpcMethod() != null, "rpcMethod must be set to get SpanName");
94+
Preconditions.checkState(
95+
fullMethodNameRegex() != null, "fullMethodNameRegex must be set to get SpanName");
96+
97+
Pattern pattern = Pattern.compile(fullMethodNameRegex());
98+
Matcher matcher = pattern.matcher(rpcMethod());
99+
100+
Preconditions.checkArgument(matcher.matches(), "Invalid rpcMethod: " + rpcMethod());
101+
return SpanName.of(matcher.group(1), matcher.group(2));
102+
}
103+
104+
/**
105+
* Merges this context with another context. The values in the other context take precedence.
106+
*
107+
* @param other the other context to merge with
108+
* @return a new {@link ApiTracerContext} with merged values
109+
*/
110+
public ApiTracerContext merge(ApiTracerContext other) {
111+
Builder builder = toBuilder();
112+
if (other.serverAddress() != null) {
113+
builder.setServerAddress(other.serverAddress());
114+
}
115+
if (!other.libraryMetadata().isEmpty()) {
116+
builder.setLibraryMetadata(other.libraryMetadata());
117+
}
118+
if (other.rpcSystemName() != null) {
119+
builder.setRpcSystemName(other.rpcSystemName());
120+
}
121+
if (other.rpcMethod() != null) {
122+
builder.setRpcMethod(other.rpcMethod());
123+
}
124+
if (other.fullMethodNameRegex() != null) {
125+
builder.setFullMethodNameRegex(other.fullMethodNameRegex());
126+
}
127+
return builder.build();
128+
}
129+
71130
public static ApiTracerContext empty() {
72131
return newBuilder().setLibraryMetadata(LibraryMetadata.empty()).build();
73132
}
@@ -76,12 +135,20 @@ public static Builder newBuilder() {
76135
return new AutoValue_ApiTracerContext.Builder();
77136
}
78137

138+
public abstract Builder toBuilder();
139+
79140
@AutoValue.Builder
80141
public abstract static class Builder {
81142
public abstract Builder setServerAddress(@Nullable String serverAddress);
82143

83144
public abstract Builder setLibraryMetadata(LibraryMetadata gapicProperties);
84145

146+
public abstract Builder setRpcSystemName(@Nullable String rpcSystemName);
147+
148+
public abstract Builder setRpcMethod(@Nullable String rpcMethod);
149+
150+
public abstract Builder setFullMethodNameRegex(@Nullable String fullMethodNameRegex);
151+
85152
public abstract ApiTracerContext build();
86153
}
87154
}

‎gax-java/gax/src/main/java/com/google/api/gax/tracing/ObservabilityAttributes.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,10 @@ public class ObservabilityAttributes {
4949

5050
/** The artifact name of the client library (e.g., "google-cloud-vision"). */
5151
public static final String ARTIFACT_ATTRIBUTE = "gcp.client.artifact";
52+
53+
/** The artifact name of the client library (e.g., "google-cloud-vision"). */
54+
public static final String RPC_METHOD_ATTRIBUTE = "rpc.method";
55+
56+
/** The artifact name of the client library (e.g., "google-cloud-vision"). */
57+
public static final String RPC_SYSTEM_NAME_ATTRIBUTE = "rpc.system.name";
5258
}

‎gax-java/gax/src/main/java/com/google/api/gax/tracing/SpanTracerFactory.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,6 @@ public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType op
7777

7878
@Override
7979
public ApiTracerFactory withContext(ApiTracerContext context) {
80-
return new SpanTracerFactory(traceManager, context);
80+
return new SpanTracerFactory(traceManager, apiTracerContext.merge(context));
8181
}
8282
}

‎gax-java/gax/src/main/java/com/google/api/gax/tracing/TracedBatchingCallable.java‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,17 @@
4949
public class TracedBatchingCallable<RequestT, ResponseT>
5050
extends UnaryCallable<RequestT, ResponseT> {
5151
private final ApiTracerFactory tracerFactory;
52-
private final SpanName spanName;
52+
private final ApiTracerContext apiTracerContext;
5353
private final BatchingDescriptor<RequestT, ResponseT> batchingDescriptor;
5454
private final UnaryCallable<RequestT, ResponseT> innerCallable;
5555

5656
public TracedBatchingCallable(
5757
UnaryCallable<RequestT, ResponseT> innerCallable,
5858
ApiTracerFactory tracerFactory,
59-
SpanName spanName,
59+
ApiTracerContext apiTracerContext,
6060
BatchingDescriptor<RequestT, ResponseT> batchingDescriptor) {
6161
this.tracerFactory = tracerFactory;
62-
this.spanName = spanName;
62+
this.apiTracerContext = apiTracerContext;
6363
this.batchingDescriptor = batchingDescriptor;
6464
this.innerCallable = innerCallable;
6565
}
@@ -69,7 +69,8 @@ public ApiFuture<ResponseT> futureCall(RequestT request, ApiCallContext context)
6969
// NOTE: This will be invoked asynchronously outside of the original caller's thread.
7070
// So this start a top level tracer.
7171
ApiTracer tracer =
72-
tracerFactory.newTracer(context.getTracer(), spanName, OperationType.Batching);
72+
tracerFactory.newTracer(
73+
context.getTracer(), apiTracerContext.getSpanName(), OperationType.Batching);
7374
TraceFinisher<ResponseT> finisher = new TraceFinisher<>(tracer);
7475

7576
try {

‎gax-java/gax/src/main/java/com/google/api/gax/tracing/TracedBidiCallable.java‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,16 @@ public class TracedBidiCallable<RequestT, ResponseT>
5353
extends BidiStreamingCallable<RequestT, ResponseT> {
5454

5555
@Nonnull private final ApiTracerFactory tracerFactory;
56-
@Nonnull private final SpanName spanName;
56+
@Nonnull private final ApiTracerContext apiTracerContext;
5757
@Nonnull private final BidiStreamingCallable<RequestT, ResponseT> innerCallable;
5858

5959
public TracedBidiCallable(
6060
@Nonnull BidiStreamingCallable<RequestT, ResponseT> innerCallable,
6161
@Nonnull ApiTracerFactory tracerFactory,
62-
@Nonnull SpanName spanName) {
62+
@Nonnull ApiTracerContext apiTracerContext) {
6363
this.tracerFactory = Preconditions.checkNotNull(tracerFactory, "tracerFactory can't be null");
64-
this.spanName = Preconditions.checkNotNull(spanName, "spanName can't be null");
64+
this.apiTracerContext =
65+
Preconditions.checkNotNull(apiTracerContext, "apiTracerContext can't be null");
6566
this.innerCallable = Preconditions.checkNotNull(innerCallable, "innerCallable can't be null");
6667
}
6768

@@ -72,7 +73,8 @@ public ClientStream<RequestT> internalCall(
7273
ApiCallContext context) {
7374

7475
ApiTracer tracer =
75-
tracerFactory.newTracer(context.getTracer(), spanName, OperationType.BidiStreaming);
76+
tracerFactory.newTracer(
77+
context.getTracer(), apiTracerContext.getSpanName(), OperationType.BidiStreaming);
7678
context = context.withTracer(tracer);
7779

7880
AtomicBoolean wasCancelled = new AtomicBoolean();

‎gax-java/gax/src/main/java/com/google/api/gax/tracing/TracedClientStreamingCallable.java‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ public class TracedClientStreamingCallable<RequestT, ResponseT>
5454
extends ClientStreamingCallable<RequestT, ResponseT> {
5555
private final ClientStreamingCallable<RequestT, ResponseT> innerCallable;
5656
private final ApiTracerFactory tracerFactory;
57-
private final SpanName spanName;
57+
private final ApiTracerContext apiTracerContext;
5858

5959
public TracedClientStreamingCallable(
6060
@Nonnull ClientStreamingCallable<RequestT, ResponseT> innerCallable,
6161
@Nonnull ApiTracerFactory tracerFactory,
62-
@Nonnull SpanName spanName) {
62+
@Nonnull ApiTracerContext apiTracerContext) {
6363
this.tracerFactory = Preconditions.checkNotNull(tracerFactory, "tracerFactory can't be null");
64-
this.spanName = Preconditions.checkNotNull(spanName, "spanName can't be null");
64+
this.apiTracerContext =
65+
Preconditions.checkNotNull(apiTracerContext, "apiTracerContext can't be null");
6566
this.innerCallable = Preconditions.checkNotNull(innerCallable, "innerCallable can't be null");
6667
}
6768

@@ -70,7 +71,8 @@ public ApiStreamObserver<RequestT> clientStreamingCall(
7071
ApiStreamObserver<ResponseT> responseObserver, ApiCallContext context) {
7172

7273
ApiTracer tracer =
73-
tracerFactory.newTracer(context.getTracer(), spanName, OperationType.ClientStreaming);
74+
tracerFactory.newTracer(
75+
context.getTracer(), apiTracerContext.getSpanName(), OperationType.ClientStreaming);
7476
context = context.withTracer(tracer);
7577

7678
// Shared state that allows the response observer to know that the error it received was

0 commit comments

Comments
 (0)