Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7082247
feat: introduce minimal implementation of OTel tracing
diegomarquezp Feb 4, 2026
bfe6a6d
chore: avoid new public methods
diegomarquezp Feb 5, 2026
ea6cb18
feat: add api tracer context
diegomarquezp Feb 5, 2026
97bec08
Merge remote-tracking branch 'origin/main' into observability/initial…
diegomarquezp Feb 5, 2026
097f701
chore: concise comment
diegomarquezp Feb 5, 2026
f547e5a
fix: use internal span kind for operations
diegomarquezp Feb 5, 2026
b7b9e31
chore: remove unnecessary inScope implementation
diegomarquezp Feb 5, 2026
556c84c
Revert "chore: remove unnecessary inScope implementation"
diegomarquezp Feb 5, 2026
0359b7d
test: add test for inScope()
diegomarquezp Feb 5, 2026
402cb89
Merge remote-tracking branch 'origin/main' into observability/initial…
diegomarquezp Feb 5, 2026
420278b
chore: use suggested server address resolution impl
diegomarquezp Feb 5, 2026
6de9fb6
fix: use concurrent hash map
diegomarquezp Feb 5, 2026
a61dacf
chore: remove default impl for startSpan with parent
diegomarquezp Feb 5, 2026
b000d52
chore: add opentelemery-context to tests
diegomarquezp Feb 5, 2026
9ce0c34
test: increase coverage for TracingTracerTest
diegomarquezp Feb 5, 2026
9c6c737
deps: include opentelemetry context in gax
diegomarquezp Feb 5, 2026
e77de58
chore: simplify and remove error handling
diegomarquezp Feb 9, 2026
8f07f61
chore: review refactor
diegomarquezp Feb 10, 2026
2cfcd68
chore: make TracingTracerFactory(recorder, opAtts, atAtts) package pr…
diegomarquezp Feb 10, 2026
2415c6b
chore: remove unnecessary inScope
diegomarquezp Feb 10, 2026
0f5e9b5
chore: rename startSpan to createSpan
diegomarquezp Feb 10, 2026
0c3bd22
chore: use server address instead of endpoint context
diegomarquezp Feb 10, 2026
bdeb291
chore: rename classes
diegomarquezp Feb 10, 2026
5c07a3c
chore: add javadoc for tracer
diegomarquezp Feb 10, 2026
ff1d45d
chore: rename to TraceSpan, improve javadocs
diegomarquezp Feb 10, 2026
043ce62
chore: format
diegomarquezp Feb 10, 2026
dbc5f41
Update gax-java/gax/src/main/java/com/google/api/gax/tracing/AppCentr…
diegomarquezp Feb 10, 2026
b4bce0d
chore: handle ipv6 in endpoint context
diegomarquezp Feb 10, 2026
6e95cf4
Merge branch 'observability/initial-tracing-impl' of https://github.c…
diegomarquezp Feb 10, 2026
e873904
chore: add language tests
diegomarquezp Feb 10, 2026
68943b0
chore: AppCentricTracer to implement interface
diegomarquezp Feb 11, 2026
cd4d4d0
chore: revert operation implementation
diegomarquezp Feb 12, 2026
5b76e40
chore: extract common span attributes to separate class
diegomarquezp Feb 12, 2026
c783d68
chore: remove unused var
diegomarquezp Feb 12, 2026
3e06b39
chore: restore context dep
diegomarquezp Feb 12, 2026
40a97a5
chore: process attributes in context and tracer classes
diegomarquezp Feb 13, 2026
5b43fa5
chore: rename to GaxSpan
diegomarquezp Feb 13, 2026
ed4af8e
chore: use fq name for otel tracer
diegomarquezp Feb 13, 2026
3bfd1ce
chore: add otel context to maven deps
diegomarquezp Feb 13, 2026
5382d78
chore: rename TraceRecorder to TraceManager and GaxSpan to Span
diegomarquezp Feb 13, 2026
4ece157
chore: remove attrs from factory
diegomarquezp Feb 13, 2026
fb57471
chore: adjust javadoc in TraceManager
diegomarquezp Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gax-java/dependencies.properties
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ maven.com_google_api_grpc_grpc_google_common_protos=com.google.api.grpc:grpc-goo
maven.com_google_auth_google_auth_library_oauth2_http=com.google.auth:google-auth-library-oauth2-http:1.42.1
maven.com_google_auth_google_auth_library_credentials=com.google.auth:google-auth-library-credentials:1.42.1
maven.io_opentelemetry_opentelemetry_api=io.opentelemetry:opentelemetry-api:1.47.0
maven.io_opentelemetry_opentelemetry_context=io.opentelemetry:opentelemetry-context:1.47.0
maven.io_opencensus_opencensus_api=io.opencensus:opencensus-api:0.31.1
maven.io_opencensus_opencensus_contrib_grpc_metrics=io.opencensus:opencensus-contrib-grpc-metrics:0.31.1
maven.io_opencensus_opencensus_contrib_http_util=io.opencensus:opencensus-contrib-http-util:0.31.1
Expand Down
1 change: 1 addition & 0 deletions gax-java/gax/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ _COMPILE_DEPS = [
"@com_google_errorprone_error_prone_annotations//jar",
"@com_google_guava_guava//jar",
"@io_opentelemetry_opentelemetry_api//jar",
"@io_opentelemetry_opentelemetry_context//jar",
"@io_opencensus_opencensus_api//jar",
"@io_opencensus_opencensus_contrib_http_util//jar",
"@io_grpc_grpc_java//context:context",
Expand Down
5 changes: 5 additions & 0 deletions gax-java/gax/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@
<artifactId>opentelemetry-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-context</artifactId>
<optional>true</optional>
</dependency>
<!-- Logging dependency -->
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.google.api.gax.core.ExecutorAsBackgroundResource;
import com.google.api.gax.core.ExecutorProvider;
import com.google.api.gax.rpc.internal.QuotaProjectIdHidingCredentials;
import com.google.api.gax.tracing.ApiTracerContext;
import com.google.api.gax.tracing.ApiTracerFactory;
import com.google.api.gax.tracing.BaseApiTracerFactory;
import com.google.auth.ApiKeyCredentials;
Expand Down Expand Up @@ -269,6 +270,11 @@ public static ClientContext create(StubSettings settings) throws IOException {
if (watchdogProvider != null && watchdogProvider.shouldAutoClose()) {
backgroundResources.add(watchdog);
}
ApiTracerContext apiTracerContext =
ApiTracerContext.newBuilder()
.setServerAddress(endpointContext.resolvedServerAddress())
.build();
ApiTracerFactory apiTracerFactory = settings.getTracerFactory().withContext(apiTracerContext);

return newBuilder()
.setBackgroundResources(backgroundResources.build())
Expand All @@ -284,7 +290,7 @@ public static ClientContext create(StubSettings settings) throws IOException {
.setQuotaProjectId(settings.getQuotaProjectId())
.setStreamWatchdog(watchdog)
.setStreamWatchdogCheckIntervalDuration(settings.getStreamWatchdogCheckIntervalDuration())
.setTracerFactory(settings.getTracerFactory())
.setTracerFactory(apiTracerFactory)
.setEndpointContext(endpointContext)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.net.HostAndPort;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -133,6 +134,8 @@ public static EndpointContext getDefaultInstance() {

public abstract String resolvedEndpoint();

public abstract String resolvedServerAddress();

public abstract Builder toBuilder();

public static Builder newBuilder() {
Expand Down Expand Up @@ -228,6 +231,8 @@ public abstract static class Builder {

public abstract Builder setResolvedEndpoint(String resolvedEndpoint);

public abstract Builder setResolvedServerAddress(String serverAddress);

public abstract Builder setResolvedUniverseDomain(String resolvedUniverseDomain);

abstract Builder setUseS2A(boolean useS2A);
Expand Down Expand Up @@ -382,6 +387,23 @@ boolean shouldUseS2A() {
return mtlsEndpoint().contains(Credentials.GOOGLE_DEFAULT_UNIVERSE);
}

private String parseServerAddress(String endpoint) {
if (Strings.isNullOrEmpty(endpoint)) {
return endpoint;
}
String hostPort = endpoint;
if (hostPort.contains("://")) {
// Strip the scheme if present. HostAndPort doesn't support schemes.
hostPort = hostPort.substring(hostPort.indexOf("://") + 3);
}
try {
return HostAndPort.fromString(hostPort).getHost();
} catch (IllegalArgumentException e) {
// Fallback for cases HostAndPort can't handle.
return hostPort;
}
}

// Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint
private String buildEndpointTemplate(String serviceName, String resolvedUniverseDomain) {
return serviceName + "." + resolvedUniverseDomain + ":443";
Expand Down Expand Up @@ -416,7 +438,9 @@ String mtlsEndpointResolver(
public EndpointContext build() throws IOException {
// The Universe Domain is used to resolve the Endpoint. It should be resolved first
setResolvedUniverseDomain(determineUniverseDomain());
setResolvedEndpoint(determineEndpoint());
String endpoint = determineEndpoint();
setResolvedEndpoint(endpoint);
setResolvedServerAddress(parseServerAddress(endpoint));
setUseS2A(shouldUseS2A());
return autoBuild();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2026 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.api.gax.tracing;

import com.google.api.core.InternalApi;
import com.google.auto.value.AutoValue;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

/**
* A context object that contains information used to infer attributes that are common for all
* {@link ApiTracer}s.
*
* <p>For internal use only.
*/
@InternalApi
@AutoValue
public abstract class ApiTracerContext {

/**
* @return a map of attributes to be included in attempt-level spans
*/
public Map<String, String> getAttemptAttributes() {
Map<String, String> attributes = new HashMap<>();
if (getServerAddress() != null) {
attributes.put(AppCentricAttributes.SERVER_ADDRESS_ATTRIBUTE, getServerAddress());
}
return attributes;
}

@Nullable
public abstract String getServerAddress();

public static Builder newBuilder() {
return new AutoValue_ApiTracerContext.Builder();
}

@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setServerAddress(String serverAddress);

public abstract ApiTracerContext build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,15 @@ enum OperationType {
* @param operationType the type of operation that the tracer will trace
*/
ApiTracer newTracer(ApiTracer parent, SpanName spanName, OperationType operationType);

/**
* Returns a new {@link ApiTracerFactory} that will use the provided context to infer attributes
* for all tracers created by the factory.
*
* @param context an {@link ApiTracerContext} object containing information to construct
* attributes
*/
default ApiTracerFactory withContext(ApiTracerContext context) {
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2026 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.api.gax.tracing;

import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;

/**
* Utility class with common attribute names in app-centric observability.
*
* <p>For internal use only.
*/
@InternalApi
@BetaApi
public class AppCentricAttributes {
/** The address of the server being called (e.g., "pubsub.googleapis.com"). */
public static final String SERVER_ADDRESS_ATTRIBUTE = "server.address";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2026 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.api.gax.tracing;

import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import java.util.HashMap;
import java.util.Map;

/**
* An implementation of {@link ApiTracer} that uses a {@link TraceManager} to record traces. This
* implementation is agnostic to the specific {@link TraceManager} in order to allow extensions that
* interact with other backends.
*/
@BetaApi
@InternalApi
public class AppCentricTracer implements ApiTracer {
public static final String LANGUAGE_ATTRIBUTE = "gcp.client.language";

public static final String DEFAULT_LANGUAGE = "Java";

private final TraceManager traceManager;
private final Map<String, String> attemptAttributes;
private final String attemptSpanName;
private final ApiTracerContext apiTracerContext;
private TraceManager.Span attemptHandle;

/**
* Creates a new instance of {@code AppCentricTracer}.
*
* @param traceManager the {@link TraceManager} to use for recording spans
* @param attemptSpanName the name of the individual attempt spans
*/
public AppCentricTracer(
TraceManager traceManager, ApiTracerContext apiTracerContext, String attemptSpanName) {
this.traceManager = traceManager;
this.attemptSpanName = attemptSpanName;
this.apiTracerContext = apiTracerContext;
this.attemptAttributes = new HashMap<>();
buildAttributes();
}

private void buildAttributes() {
this.attemptAttributes.put(LANGUAGE_ATTRIBUTE, DEFAULT_LANGUAGE);
this.attemptAttributes.putAll(this.apiTracerContext.getAttemptAttributes());
}

@Override
public void attemptStarted(Object request, int attemptNumber) {
Map<String, String> attemptAttributes = new HashMap<>(this.attemptAttributes);
// Start the specific attempt span with the operation span as parent
this.attemptHandle = traceManager.createSpan(attemptSpanName, attemptAttributes);
}

@Override
public void attemptSucceeded() {
endAttempt();
}

private void endAttempt() {
if (attemptHandle != null) {
attemptHandle.end();
attemptHandle = null;
}
}
}
Loading
Loading