Skip to content

Commit 00686f6

Browse files
committed
feat(gax): implement actionable errors logging in ApiTracer framework
1 parent 5d6bc5f commit 00686f6

File tree

5 files changed

+476
-0
lines changed

5 files changed

+476
-0
lines changed

gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ public static ClientContext create(StubSettings settings) throws IOException {
281281
if (apiTracerFactory instanceof SpanTracerFactory) {
282282
apiTracerFactory = apiTracerFactory.withContext(apiTracerContext);
283283
}
284+
if (com.google.api.gax.logging.LoggingUtils.isLoggingV2Enabled()) {
285+
com.google.api.gax.tracing.ApiTracerFactory loggingTracerFactory =
286+
new com.google.api.gax.tracing.LoggingTracerFactory().withContext(apiTracerContext);
287+
apiTracerFactory =
288+
new com.google.api.gax.tracing.CompositeTracerFactory(
289+
apiTracerFactory, loggingTracerFactory);
290+
}
284291

285292
return newBuilder()
286293
.setBackgroundResources(backgroundResources.build())
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
* * Neither the name of Google LLC nor the names of its
15+
* contributors may be used to endorse or promote products derived from
16+
* this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
package com.google.api.gax.tracing;
32+
33+
import com.google.api.core.BetaApi;
34+
import com.google.api.core.InternalApi;
35+
import java.util.List;
36+
37+
/** A composite {@link ApiTracer} that delegates to a list of {@link ApiTracer}s. */
38+
@BetaApi
39+
@InternalApi
40+
public class CompositeTracer implements ApiTracer {
41+
private final List<ApiTracer> tracers;
42+
43+
public CompositeTracer(List<ApiTracer> tracers) {
44+
this.tracers = tracers;
45+
}
46+
47+
@Override
48+
public Scope inScope() {
49+
// Returning a scope that closes all sub-scopes
50+
final Scope[] scopes = new Scope[tracers.size()];
51+
for (int i = 0; i < tracers.size(); i++) {
52+
scopes[i] = tracers.get(i).inScope();
53+
}
54+
return () -> {
55+
for (Scope scope : scopes) {
56+
if (scope != null) {
57+
scope.close();
58+
}
59+
}
60+
};
61+
}
62+
63+
@Override
64+
public void operationSucceeded() {
65+
for (ApiTracer tracer : tracers) {
66+
tracer.operationSucceeded();
67+
}
68+
}
69+
70+
@Override
71+
public void operationCancelled() {
72+
for (ApiTracer tracer : tracers) {
73+
tracer.operationCancelled();
74+
}
75+
}
76+
77+
@Override
78+
public void operationFailed(Throwable error) {
79+
for (ApiTracer tracer : tracers) {
80+
tracer.operationFailed(error);
81+
}
82+
}
83+
84+
@Override
85+
public void connectionSelected(String id) {
86+
for (ApiTracer tracer : tracers) {
87+
tracer.connectionSelected(id);
88+
}
89+
}
90+
91+
@Override
92+
@SuppressWarnings("deprecation")
93+
public void attemptStarted(int attemptNumber) {
94+
for (ApiTracer tracer : tracers) {
95+
tracer.attemptStarted(attemptNumber);
96+
}
97+
}
98+
99+
@Override
100+
public void attemptStarted(Object request, int attemptNumber) {
101+
for (ApiTracer tracer : tracers) {
102+
tracer.attemptStarted(request, attemptNumber);
103+
}
104+
}
105+
106+
@Override
107+
public void attemptSucceeded() {
108+
for (ApiTracer tracer : tracers) {
109+
tracer.attemptSucceeded();
110+
}
111+
}
112+
113+
@Override
114+
public void attemptCancelled() {
115+
for (ApiTracer tracer : tracers) {
116+
tracer.attemptCancelled();
117+
}
118+
}
119+
120+
@Override
121+
@SuppressWarnings("deprecation")
122+
public void attemptFailed(Throwable error, org.threeten.bp.Duration delay) {
123+
for (ApiTracer tracer : tracers) {
124+
tracer.attemptFailed(error, delay);
125+
}
126+
}
127+
128+
@Override
129+
public void attemptFailedDuration(Throwable error, java.time.Duration delay) {
130+
for (ApiTracer tracer : tracers) {
131+
tracer.attemptFailedDuration(error, delay);
132+
}
133+
}
134+
135+
@Override
136+
public void attemptFailedRetriesExhausted(Throwable error) {
137+
for (ApiTracer tracer : tracers) {
138+
tracer.attemptFailedRetriesExhausted(error);
139+
}
140+
}
141+
142+
@Override
143+
public void attemptPermanentFailure(Throwable error) {
144+
for (ApiTracer tracer : tracers) {
145+
tracer.attemptPermanentFailure(error);
146+
}
147+
}
148+
149+
@Override
150+
public void lroStartFailed(Throwable error) {
151+
for (ApiTracer tracer : tracers) {
152+
tracer.lroStartFailed(error);
153+
}
154+
}
155+
156+
@Override
157+
public void lroStartSucceeded() {
158+
for (ApiTracer tracer : tracers) {
159+
tracer.lroStartSucceeded();
160+
}
161+
}
162+
163+
@Override
164+
public void responseReceived() {
165+
for (ApiTracer tracer : tracers) {
166+
tracer.responseReceived();
167+
}
168+
}
169+
170+
@Override
171+
public void requestSent() {
172+
for (ApiTracer tracer : tracers) {
173+
tracer.requestSent();
174+
}
175+
}
176+
177+
@Override
178+
public void batchRequestSent(long elementCount, long requestSize) {
179+
for (ApiTracer tracer : tracers) {
180+
tracer.batchRequestSent(elementCount, requestSize);
181+
}
182+
}
183+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
* * Neither the name of Google LLC nor the names of its
15+
* contributors may be used to endorse or promote products derived from
16+
* this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
package com.google.api.gax.tracing;
32+
33+
import com.google.api.core.BetaApi;
34+
import com.google.api.core.InternalApi;
35+
import java.util.ArrayList;
36+
import java.util.Arrays;
37+
import java.util.List;
38+
39+
/**
40+
* A composite {@link ApiTracerFactory} that creates a {@link CompositeTracer} containing multiple
41+
* {@link ApiTracer} instances.
42+
*/
43+
@BetaApi
44+
@InternalApi
45+
public class CompositeTracerFactory implements ApiTracerFactory {
46+
private final List<ApiTracerFactory> factories;
47+
private final ApiTracerContext apiTracerContext;
48+
49+
public CompositeTracerFactory(ApiTracerFactory... factories) {
50+
this(Arrays.asList(factories), ApiTracerContext.empty());
51+
}
52+
53+
public CompositeTracerFactory(List<ApiTracerFactory> factories) {
54+
this(factories, ApiTracerContext.empty());
55+
}
56+
57+
private CompositeTracerFactory(
58+
List<ApiTracerFactory> factories, ApiTracerContext apiTracerContext) {
59+
this.factories = factories;
60+
this.apiTracerContext = apiTracerContext;
61+
}
62+
63+
@Override
64+
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
65+
List<ApiTracer> tracers = new ArrayList<>(factories.size());
66+
for (ApiTracerFactory factory : factories) {
67+
tracers.add(factory.newTracer(parent, spanName, operationType));
68+
}
69+
return new CompositeTracer(tracers);
70+
}
71+
72+
@Override
73+
public ApiTracer newTracer(ApiTracer parent, ApiTracerContext context) {
74+
List<ApiTracer> tracers = new ArrayList<>(factories.size());
75+
for (ApiTracerFactory factory : factories) {
76+
tracers.add(factory.newTracer(parent, context));
77+
}
78+
return new CompositeTracer(tracers);
79+
}
80+
81+
@Override
82+
public ApiTracerContext getApiTracerContext() {
83+
return apiTracerContext;
84+
}
85+
86+
@Override
87+
public ApiTracerFactory withContext(ApiTracerContext context) {
88+
List<ApiTracerFactory> updatedFactories = new ArrayList<>(factories.size());
89+
for (ApiTracerFactory factory : factories) {
90+
updatedFactories.add(factory.withContext(context));
91+
}
92+
return new CompositeTracerFactory(updatedFactories, apiTracerContext.merge(context));
93+
}
94+
}

0 commit comments

Comments
 (0)