Skip to content

Commit 9820cb8

Browse files
chore: merge main into generate-libraries-main
2 parents 1e64107 + dea24db commit 9820cb8

File tree

3 files changed

+127
-75
lines changed

3 files changed

+127
-75
lines changed

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030

3131
package com.google.api.gax.tracing;
3232

33+
import com.google.api.client.util.Strings;
3334
import com.google.api.core.BetaApi;
3435
import com.google.api.core.InternalApi;
36+
import com.google.api.gax.rpc.LibraryMetadata;
3537
import com.google.common.annotations.VisibleForTesting;
3638
import io.opentelemetry.api.OpenTelemetry;
3739
import io.opentelemetry.api.trace.Tracer;
@@ -48,12 +50,12 @@
4850
@InternalApi
4951
public class SpanTracerFactory implements ApiTracerFactory {
5052
private final Tracer tracer;
51-
53+
private final OpenTelemetry openTelemetry;
5254
private final ApiTracerContext apiTracerContext;
5355

5456
/** Creates a SpanTracerFactory */
5557
public SpanTracerFactory(OpenTelemetry openTelemetry) {
56-
this(openTelemetry.getTracer("gax-java"), ApiTracerContext.empty());
58+
this(openTelemetry, null, ApiTracerContext.empty());
5759
}
5860

5961
/**
@@ -62,13 +64,18 @@ public SpanTracerFactory(OpenTelemetry openTelemetry) {
6264
* internally.
6365
*/
6466
@VisibleForTesting
65-
SpanTracerFactory(Tracer tracer, ApiTracerContext apiTracerContext) {
67+
SpanTracerFactory(OpenTelemetry openTelemetry, Tracer tracer, ApiTracerContext apiTracerContext) {
68+
this.openTelemetry = openTelemetry;
6669
this.tracer = tracer;
6770
this.apiTracerContext = apiTracerContext;
6871
}
6972

7073
@Override
7174
public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType) {
75+
if (tracer == null) {
76+
// Return a no-op tracer if withContext hasn't been called to initialize the tracer properly
77+
return new BaseApiTracer();
78+
}
7279
// TODO(diegomarquezp): this is a placeholder for span names and will be adjusted as the
7380
// feature is developed.
7481
String attemptSpanName = spanName.getClientName() + "/" + spanName.getMethodName() + "/attempt";
@@ -78,6 +85,10 @@ public ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType op
7885

7986
@Override
8087
public ApiTracer newTracer(ApiTracer parent, ApiTracerContext apiTracerContext) {
88+
if (tracer == null) {
89+
// Return a no-op tracer if withContext hasn't been called to initialize the tracer properly
90+
return new BaseApiTracer();
91+
}
8192
ApiTracerContext mergedContext = this.apiTracerContext.merge(apiTracerContext);
8293
return new SpanTracer(tracer, mergedContext);
8394
}
@@ -87,8 +98,21 @@ public ApiTracerContext getApiTracerContext() {
8798
return apiTracerContext;
8899
}
89100

101+
/**
102+
* Returns a new SpanTracerFactory with the provided context. The Tracer is re-initialized using
103+
* the artifact name and version from the library metadata.
104+
*/
90105
@Override
91106
public ApiTracerFactory withContext(ApiTracerContext context) {
92-
return new SpanTracerFactory(tracer, apiTracerContext.merge(context));
107+
if (context == null) {
108+
return new BaseApiTracerFactory();
109+
}
110+
LibraryMetadata metadata = context.libraryMetadata();
111+
if (metadata == null || metadata.isEmpty() || Strings.isNullOrEmpty(metadata.artifactName())) {
112+
return new BaseApiTracerFactory();
113+
}
114+
Tracer newTracer = openTelemetry.getTracer(metadata.artifactName(), metadata.version());
115+
ApiTracerContext mergedContext = this.apiTracerContext.merge(context);
116+
return new SpanTracerFactory(openTelemetry, newTracer, mergedContext);
93117
}
94118
}

sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/tracing/SpanTracerFactoryTest.java

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import static com.google.common.truth.Truth.assertThat;
3434
import static org.mockito.ArgumentMatchers.any;
3535
import static org.mockito.ArgumentMatchers.anyString;
36+
import static org.mockito.ArgumentMatchers.nullable;
3637
import static org.mockito.Mockito.atLeastOnce;
3738
import static org.mockito.Mockito.mock;
3839
import static org.mockito.Mockito.verify;
@@ -41,6 +42,7 @@
4142
import com.google.api.gax.rpc.LibraryMetadata;
4243
import com.google.api.gax.tracing.ApiTracerContext.Transport;
4344
import com.google.api.gax.tracing.ApiTracerFactory.OperationType;
45+
import io.opentelemetry.api.OpenTelemetry;
4446
import io.opentelemetry.api.common.AttributeKey;
4547
import io.opentelemetry.api.common.Attributes;
4648
import io.opentelemetry.api.trace.Span;
@@ -54,25 +56,36 @@
5456
import org.mockito.ArgumentCaptor;
5557

5658
class SpanTracerFactoryTest {
59+
private OpenTelemetry openTelemetry;
5760
private Tracer tracer;
5861
private SpanBuilder spanBuilder;
5962
private Span span;
6063

64+
private LibraryMetadata validMetadata;
65+
6166
@BeforeEach
6267
void setUp() {
68+
openTelemetry = mock(OpenTelemetry.class);
6369
tracer = mock(Tracer.class);
6470
spanBuilder = mock(SpanBuilder.class);
6571
span = mock(Span.class);
72+
when(openTelemetry.getTracer(nullable(String.class), nullable(String.class)))
73+
.thenReturn(tracer);
6674
when(tracer.spanBuilder(anyString())).thenReturn(spanBuilder);
6775
when(spanBuilder.setSpanKind(any())).thenReturn(spanBuilder);
6876
when(spanBuilder.setAllAttributes(any(Attributes.class))).thenReturn(spanBuilder);
6977
when(spanBuilder.startSpan()).thenReturn(span);
78+
79+
validMetadata = mock(LibraryMetadata.class);
80+
when(validMetadata.artifactName()).thenReturn("gax-java");
81+
when(validMetadata.version()).thenReturn("2.1.0");
7082
}
7183

7284
@ParameterizedTest
7385
@ValueSource(booleans = {false, true})
7486
void testNewTracer_createsSpanTracer(boolean useContext) {
75-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
87+
SpanTracerFactory factory =
88+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
7689
ApiTracer tracerInstance;
7790
if (useContext) {
7891
ApiTracerContext context =
@@ -92,11 +105,12 @@ void testNewTracer_createsSpanTracer(boolean useContext) {
92105
@ParameterizedTest
93106
@ValueSource(booleans = {false, true})
94107
void testNewTracer_addsAttributes(boolean useContext) {
95-
ApiTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
108+
ApiTracerFactory factory =
109+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
96110
factory =
97111
factory.withContext(
98112
ApiTracerContext.newBuilder()
99-
.setLibraryMetadata(LibraryMetadata.empty())
113+
.setLibraryMetadata(validMetadata)
100114
.setServerAddress("test-address")
101115
.build());
102116
ApiTracer tracerInstance;
@@ -105,7 +119,7 @@ void testNewTracer_addsAttributes(boolean useContext) {
105119
ApiTracerContext.newBuilder()
106120
.setFullMethodName("service/method")
107121
.setTransport(Transport.GRPC)
108-
.setLibraryMetadata(LibraryMetadata.empty())
122+
.setLibraryMetadata(validMetadata)
109123
.build();
110124
tracerInstance = factory.newTracer(null, context);
111125
} else {
@@ -128,11 +142,12 @@ void testNewTracer_addsAttributes(boolean useContext) {
128142
void testWithContext_addsInferredAttributes(boolean useContext) {
129143
ApiTracerContext context =
130144
ApiTracerContext.newBuilder()
131-
.setLibraryMetadata(LibraryMetadata.empty())
145+
.setLibraryMetadata(validMetadata)
132146
.setServerAddress("example.com")
133147
.build();
134148

135-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
149+
SpanTracerFactory factory =
150+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
136151
ApiTracerFactory factoryWithContext = factory.withContext(context);
137152

138153
ApiTracer tracerInstance;
@@ -141,7 +156,7 @@ void testWithContext_addsInferredAttributes(boolean useContext) {
141156
ApiTracerContext.newBuilder()
142157
.setFullMethodName("service/method")
143158
.setTransport(Transport.GRPC)
144-
.setLibraryMetadata(LibraryMetadata.empty())
159+
.setLibraryMetadata(validMetadata)
145160
.build();
146161
tracerInstance = factoryWithContext.newTracer(null, callContext);
147162
} else {
@@ -164,9 +179,11 @@ void testWithContext_addsInferredAttributes(boolean useContext) {
164179
@ParameterizedTest
165180
@ValueSource(booleans = {false, true})
166181
void testWithContext_noEndpointContext_doesNotAddServerAddressAttribute(boolean useContext) {
167-
ApiTracerContext context = ApiTracerContext.empty();
182+
ApiTracerContext context =
183+
ApiTracerContext.newBuilder().setLibraryMetadata(validMetadata).build();
168184

169-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
185+
SpanTracerFactory factory =
186+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
170187
ApiTracerFactory factoryWithContext = factory.withContext(context);
171188

172189
ApiTracer tracerInstance;
@@ -175,7 +192,7 @@ void testWithContext_noEndpointContext_doesNotAddServerAddressAttribute(boolean
175192
ApiTracerContext.newBuilder()
176193
.setFullMethodName("service/method")
177194
.setTransport(Transport.GRPC)
178-
.setLibraryMetadata(LibraryMetadata.empty())
195+
.setLibraryMetadata(validMetadata)
179196
.build();
180197
tracerInstance = factoryWithContext.newTracer(null, callContext);
181198
} else {
@@ -203,7 +220,8 @@ void testNewTracer_withContext_grpc_usesFullMethodName() {
203220
.setLibraryMetadata(LibraryMetadata.empty())
204221
.build();
205222

206-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
223+
SpanTracerFactory factory =
224+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
207225
ApiTracer tracerInstance = factory.newTracer(null, context);
208226

209227
tracerInstance.attemptStarted(null, 1);
@@ -229,7 +247,8 @@ void testNewTracer_withContext_http_usesHttpMethodAndPathTemplate(
229247
.setLibraryMetadata(LibraryMetadata.empty())
230248
.build();
231249

232-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
250+
SpanTracerFactory factory =
251+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
233252
ApiTracer tracerInstance = factory.newTracer(null, context);
234253

235254
tracerInstance.attemptStarted(null, 1);
@@ -246,7 +265,8 @@ void testNewTracer_withContext_http_noHttpMethodOrPathTemplate_usesFullMethodNam
246265
.setLibraryMetadata(LibraryMetadata.empty())
247266
.build();
248267

249-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
268+
SpanTracerFactory factory =
269+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
250270
ApiTracer tracerInstance = factory.newTracer(null, context);
251271

252272
tracerInstance.attemptStarted(null, 1);
@@ -256,7 +276,8 @@ void testNewTracer_withContext_http_noHttpMethodOrPathTemplate_usesFullMethodNam
256276

257277
@Test
258278
void testNewTracer_withSpanName_usesPlaceholder() {
259-
SpanTracerFactory factory = new SpanTracerFactory(tracer, ApiTracerContext.empty());
279+
SpanTracerFactory factory =
280+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
260281
ApiTracer tracerInstance =
261282
factory.newTracer(null, SpanName.of("Service", "Method"), OperationType.Unary);
262283

@@ -272,7 +293,7 @@ void testNewTracer_mergesFactoryContext() {
272293
.setServerAddress("factory-address")
273294
.setLibraryMetadata(LibraryMetadata.empty())
274295
.build();
275-
SpanTracerFactory factory = new SpanTracerFactory(tracer, apiTracerContext);
296+
SpanTracerFactory factory = new SpanTracerFactory(openTelemetry, tracer, apiTracerContext);
276297

277298
ApiTracerContext callContext =
278299
ApiTracerContext.newBuilder()
@@ -293,4 +314,51 @@ void testNewTracer_mergesFactoryContext() {
293314
assertThat(attributes.asMap())
294315
.containsEntry(AttributeKey.stringKey("rpc.method"), "Service/Method");
295316
}
317+
318+
@Test
319+
void testNoOpWhenTracerNull() {
320+
SpanTracerFactory factory =
321+
new SpanTracerFactory(openTelemetry, null, ApiTracerContext.empty());
322+
323+
ApiTracer tracerInstance =
324+
factory.newTracer(null, SpanName.of("Service", "Method"), OperationType.Unary);
325+
326+
assertThat(tracerInstance).isInstanceOf(BaseApiTracer.class);
327+
328+
ApiTracer tracerInstance2 = factory.newTracer(null, ApiTracerContext.empty());
329+
330+
assertThat(tracerInstance2).isInstanceOf(BaseApiTracer.class);
331+
}
332+
333+
@Test
334+
void testWithContext_nullContext_returnsBaseApiTracerFactory() {
335+
SpanTracerFactory factory =
336+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
337+
ApiTracerFactory factoryWithContext = factory.withContext(null);
338+
assertThat(factoryWithContext).isInstanceOf(BaseApiTracerFactory.class);
339+
}
340+
341+
@Test
342+
void testWithContext_nullMetadata_returnsBaseApiTracerFactory() {
343+
SpanTracerFactory factory =
344+
new SpanTracerFactory(openTelemetry, tracer, ApiTracerContext.empty());
345+
// Assuming ApiTracerContext.empty() has null libraryMetadata
346+
ApiTracerFactory factoryWithContext = factory.withContext(ApiTracerContext.empty());
347+
assertThat(factoryWithContext).isInstanceOf(BaseApiTracerFactory.class);
348+
}
349+
350+
@Test
351+
void testWithContext_nullTracer_returnsBaseApiTracerFactory() {
352+
OpenTelemetry mockOpenTelemetry = mock(OpenTelemetry.class);
353+
when(mockOpenTelemetry.getTracer(nullable(String.class), nullable(String.class)))
354+
.thenReturn(null);
355+
356+
SpanTracerFactory factory =
357+
new SpanTracerFactory(mockOpenTelemetry, tracer, ApiTracerContext.empty());
358+
ApiTracerContext context =
359+
ApiTracerContext.newBuilder().setLibraryMetadata(LibraryMetadata.empty()).build();
360+
361+
ApiTracerFactory factoryWithContext = factory.withContext(context);
362+
assertThat(factoryWithContext).isInstanceOf(BaseApiTracerFactory.class);
363+
}
296364
}

0 commit comments

Comments
 (0)