Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
bfb40b0
feat(core): add request hook to inject GCP resource and project attri…
chalmerlowe Sep 3, 2026
87ca9b8
feat(core): implement complete T4 gRPC telemetry capture and response…
chalmerlowe Sep 9, 2026
451e17b
test(core): add comprehensive unit tests for T4 gRPC telemetry and hooks
chalmerlowe Sep 9, 2026
29de72e
refactor(core): adopt explicit _grpc_* naming for request extraction …
chalmerlowe Sep 9, 2026
7f6519f
test(core): align test names and assertions with _grpc_* naming conve…
chalmerlowe Sep 9, 2026
b0de0a4
feat(core): add url.domain, error attributes, and streamline T4 hooks
chalmerlowe Sep 10, 2026
ac095c5
feat(core): normalize gRPC span names and eliminate duplicate rpc.sys…
chalmerlowe Sep 10, 2026
ef7d77d
refactor(core): remove deferred gcp.resource.destination.id attribute
chalmerlowe Sep 10, 2026
aa2bead
feat(core): record rpc.response.status_code on wire attempt spans
chalmerlowe Sep 10, 2026
894b380
refactor(core): remove duplicate error attribute extraction in favor …
chalmerlowe Sep 10, 2026
1c1b9af
fix(observability): resolve mypy union-attr error and support environ…
chalmerlowe Sep 10, 2026
81b686c
refactor(observability): simplify response hook to record OK on succe…
chalmerlowe Sep 10, 2026
324b866
test(observability): cover request hook span edge cases for 100% bran…
chalmerlowe Sep 10, 2026
abeaf04
fix(observability): safely handle invalid port in endpoint attributes
chalmerlowe Sep 11, 2026
99a4d3d
fix(observability): ensure response hook only records OK on successfu…
chalmerlowe Sep 11, 2026
4b82c9c
refactor(observability): address review feedback on method name, url …
chalmerlowe Sep 11, 2026
0fb354a
docs(observability): clarify sync vs async behavior and specify semco…
chalmerlowe Sep 14, 2026
acce308
feat(gapic): add OpenTelemetry channel tracing to generator templates
chalmerlowe Sep 11, 2026
d337933
fix(gapic): resolve CI import errors on unreleased ClientInterceptor …
chalmerlowe Sep 11, 2026
13f1218
fix(gapic): use AnonymousCredentials in test_grpc_transport_channel_i…
chalmerlowe Sep 11, 2026
11ccd0d
test(gapic): update bazel integration goldens for otel channel tracing
chalmerlowe Sep 11, 2026
a7dad4f
ci(gapic): add OpenTelemetry test dependencies to showcase nox sessions
chalmerlowe Sep 14, 2026
858ff52
test(gapic): support client_options and otel interceptor in system te…
chalmerlowe Sep 14, 2026
b1c66e4
test(gapic): add showcase system test suite for OpenTelemetry channel…
chalmerlowe Sep 14, 2026
b409ba6
feat(gapic): broaden transport subclass check and harden tracing tests
chalmerlowe Sep 14, 2026
2059f32
refactor(gapic): guard ClientInterceptor under TYPE_CHECKING in trans…
chalmerlowe Sep 15, 2026
66a6f0e
test(gapic): synchronize NO COVER pragma in golden gRPC transports
chalmerlowe Sep 15, 2026
7ebebfa
test(gapic): support flexible import of construct_client in system tr…
chalmerlowe Sep 15, 2026
a7956a5
feat(gapic): resolve OTel interceptor in GrpcTransport and pass clien…
chalmerlowe Sep 15, 2026
cd5299a
test(gapic): update bazel integration goldens for transport tracing u…
chalmerlowe Sep 15, 2026
8b540c8
fix(gapic): resolve showcase mypy error and ensure base transport wra…
chalmerlowe Sep 16, 2026
880f5b9
feat(observability): add fallback status code and exception mapping f…
chalmerlowe Sep 16, 2026
9bb3305
test(gapic): harmonize showcase system tracing tests with env gating …
chalmerlowe Sep 16, 2026
af22028
fix(observability): ensure 100% branch coverage in error attribute ex…
chalmerlowe Sep 16, 2026
d073f2b
perf(generator): cache wrap_method tracing check at module level
chalmerlowe Sep 16, 2026
715f58b
refactor(observability): guard none span in response hook and tag int…
chalmerlowe Sep 16, 2026
c13f97a
feat(gapic): harden otel interceptor deduplication and options checki…
chalmerlowe Sep 16, 2026
b1b7ce4
test(gapic): update bazel integration goldens for interceptor hardening
chalmerlowe Sep 16, 2026
ce65620
Merge remote-tracking branch 'origin/main' into feat/otel-tracing-gap…
chalmerlowe Sep 16, 2026
d53607b
fix(ci): synchronize goldens with bazel generator and align with main
chalmerlowe Sep 16, 2026
f7f3feb
feat(gapic): wire method_name for mixin methods in base transport
chalmerlowe Sep 16, 2026
2f522bd
test(gapic): clarify test handling of abstract base transport NotImpl…
chalmerlowe Sep 17, 2026
ee5f778
refactor(testing): tighten fixture usage and standardize span asserti…
chalmerlowe Sep 17, 2026
89675ea
feat(observability): populate status.message span attribute for cross…
chalmerlowe Sep 17, 2026
8abdbc6
feat(observability): implement universal 4-path OpenTelemetry tracing
chalmerlowe Sep 21, 2026
cba76f3
fix(observability): resolve 4-path transport tracing gaps and support…
chalmerlowe Sep 21, 2026
2772ee3
fix(observability): resolve mypy typing, matrix coverage, and update …
chalmerlowe Sep 21, 2026
09080aa
fix(generator): isolate goldens from pre-commit formatting and sync i…
chalmerlowe Sep 21, 2026
a933acb
fix(generator): sync Bazel integration goldens with raw generator out…
chalmerlowe Sep 21, 2026
78a1db7
test(tracing): achieve 100% coverage on google-api-core and showcase …
chalmerlowe Sep 21, 2026
0f6e078
refactor(tracing): centralize wrap_method introspection and simplify …
chalmerlowe Sep 22, 2026
2535c2d
refactor(gapic-generator): unify transport method wrapping and centra…
chalmerlowe Sep 22, 2026
1f54064
refactor(observability): add trace_http_request helper and simplify r…
chalmerlowe Sep 22, 2026
4c8984d
refactor(gapic-generator): unify transport wrap helper, clean compat …
chalmerlowe Sep 22, 2026
03e8dff
fix(core): route async channel interceptors by RPC type
chalmerlowe Sep 22, 2026
f63234f
refactor(observability): complete docstring typing, enforce transport…
chalmerlowe Sep 22, 2026
2862cce
fix(observability): document fail-open rationale and cover tracing in…
chalmerlowe Sep 23, 2026
b621fcd
feat(observability): align REST rpc.system.name, cache trace context …
chalmerlowe Sep 23, 2026
8382184
fix(generator): add coverage pragmas to _compat observability fallbac…
chalmerlowe Sep 23, 2026
c22f65b
test(core): cover apply_channel_interceptors fallback branches
chalmerlowe Sep 23, 2026
b50c26e
test(core): cover all non-appendable branches in apply_channel_interc…
chalmerlowe Sep 23, 2026
84ff4d9
test(generator): add semantic span contracts and 18-feature complianc…
chalmerlowe Sep 23, 2026
84a2128
refactor(generator): consolidate telemetry compliance scenarios and p…
chalmerlowe Sep 23, 2026
2f8d713
refactor(observability): address review comments on HTTP span context…
chalmerlowe Sep 24, 2026
c148624
refactor(observability): collapse _HttpSpanContext into class trace_h…
chalmerlowe Sep 24, 2026
4d2c361
style(generator): move TYPE_CHECKING import to bottom of imports in g…
chalmerlowe Sep 24, 2026
40b0db6
test(generator): remove pragma: NO COVER from base transport fallback…
chalmerlowe Sep 24, 2026
d535d6d
refactor(gapic-generator): inline _wrap helper directly into _wrap_me…
chalmerlowe Sep 24, 2026
86e2eed
docs(gapic-generator): add docstrings to transport method wrappers an…
chalmerlowe Sep 24, 2026
7934816
test(showcase): add F3 live retry hierarchy and aggregation complianc…
chalmerlowe Sep 24, 2026
bc39993
refactor(testing): drive telemetry compliance test suite from CSV fea…
chalmerlowe Sep 24, 2026
f2c08f9
feat(testing): add --dump-spans option to dump raw OpenTelemetry JSON…
chalmerlowe Sep 24, 2026
b2a97ed
refactor(testing): output telemetry compliance scorecard in clean CSV…
chalmerlowe Sep 24, 2026
f8ed46d
fix(observability): resolve mypy exit-return typing and sync bazel in…
chalmerlowe Sep 24, 2026
566e55d
fix(testing): simplify span_contract record and support local core in…
chalmerlowe Sep 25, 2026
a4dd85a
ci(generator): add showcase-system test workflow
chalmerlowe Sep 25, 2026
96e54eb
fix(generator): include sequence.proto in showcase library generation
chalmerlowe Sep 25, 2026
79b01ba
ci(generator): run full showcase system test suite in CI
chalmerlowe Sep 25, 2026
df0617e
ci(generator): enable verbose and uncaptured output for showcase syst…
chalmerlowe Sep 25, 2026
7599f5b
refactor(testing): clear legacy span_contract boilerplate for spec-dr…
chalmerlowe Sep 25, 2026
8b07759
docs(testing): update telemetry requirements matrix with concrete 1-t…
chalmerlowe Sep 25, 2026
4296316
feat(generator): implement clean-slate spec-driven telemetry complian…
chalmerlowe Sep 25, 2026
178686f
refactor(testing): remove deprecated span_contract references from te…
chalmerlowe Sep 25, 2026
6bc5406
refactor(testing): make matrix sole authority for sequence and retry …
chalmerlowe Sep 25, 2026
bc3a140
refactor(testing): use monkeypatch for tracing environment variable c…
chalmerlowe Sep 25, 2026
b6df0b7
refactor(testing): introduce construct_observability_client helper fo…
chalmerlowe Sep 25, 2026
02cb934
refactor(testing): remove unnecessary use_mtls plumbing from test run…
chalmerlowe Sep 25, 2026
38311d5
refactor(testing): inject clients into scenario runners and centraliz…
chalmerlowe Sep 25, 2026
fb3c3ff
refactor(testing): eliminate magic numbers and unify sequence executi…
chalmerlowe Sep 25, 2026
2bba42d
refactor(testing): decompose assert_span_matches_row into modular sub…
chalmerlowe Sep 25, 2026
0d3dcdf
docs(testing): enrich architectural docstrings and commentary across …
chalmerlowe Sep 25, 2026
89c6f86
refactor(testing): dry up span metadata assertions and simplify DSL d…
chalmerlowe Sep 25, 2026
92f9a2f
fix(core): remove unreachable branch in trace_http_request.__exit__ t…
chalmerlowe Sep 25, 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
47 changes: 40 additions & 7 deletions .github/workflows/gapic-generator-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
with:
python-version: "${{ matrix.python }}"
allow-prereleases: true
# Caches compiled wheels locally to prevent building heavy libraries
# Caches compiled wheels locally to prevent building heavy libraries
# such as grpcio, which we build from scratch on every run for Python 3.15+.
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
cache: 'pip'
Expand All @@ -94,6 +94,40 @@ jobs:
cd packages/gapic-generator
nox -s showcase_unit${{ matrix.variant }}-${MATRIX_PYTHON}

showcase-system:
needs: python_config
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.10"
cache: 'pip'
cache-dependency-path: '**/requirements*.txt'
- name: Install System Deps & Protoc
run: |
sudo apt-get update && sudo apt-get install -y curl pandoc unzip
sudo mkdir -p /usr/src/protoc/ && sudo chown -R ${USER} /usr/src/
curl --location https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip --output /usr/src/protoc/protoc.zip
cd /usr/src/protoc/ && unzip protoc.zip
sudo ln -s /usr/src/protoc/bin/protoc /usr/local/bin/protoc
- name: Install & Run Showcase Daemon
run: |
sudo mkdir -p /usr/src/showcase && sudo chown -R ${USER} /usr/src/
curl --location https://github.com/googleapis/gapic-showcase/releases/download/v${SHOWCASE_VERSION}/gapic-showcase-${SHOWCASE_VERSION}-linux-amd64.tar.gz --output /usr/src/showcase/showcase.tar.gz
cd /usr/src/showcase/ && tar -xf showcase.tar.gz
./gapic-showcase run &
sleep 2
curl -s http://localhost:7469/ > /dev/null || true
- name: Run Showcase System Tests
run: |
pip install nox
cd packages/gapic-generator
nox -s showcase-3.10 -- -v -s tests/system

showcase-mypy:
needs: python_config
runs-on: ubuntu-latest
Expand Down Expand Up @@ -159,7 +193,7 @@ jobs:
with:
python-version: ${{ needs.python_config.outputs.prerelease_python }}
allow-prereleases: true
# Caches compiled wheels locally to prevent building heavy libraries
# Caches compiled wheels locally to prevent building heavy libraries
# such as grpcio, which we build from scratch on every run for Python 3.15+.
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
cache: 'pip'
Expand Down Expand Up @@ -189,7 +223,7 @@ jobs:
with:
python-version: ${{ matrix.python }}
allow-prereleases: true
# Caches compiled wheels locally to prevent building heavy libraries
# Caches compiled wheels locally to prevent building heavy libraries
# such as grpcio, which we build from scratch on every run for Python 3.15+.
# Follow https://github.com/grpc/grpc/issues/41010 for updates.
cache: 'pip'
Expand Down Expand Up @@ -234,16 +268,16 @@ jobs:

- name: Run Bazel Integration Tests
run: |
# We need to move into the package directory if the
# We need to move into the package directory if the
# WORKSPACE file is located there.
cd packages/gapic-generator
bazelisk test //tests/integration/... --test_output=errors

# Final job to simplify branch protection rules.
# This job will be reported as 'Success' if all its dependencies either
# This job will be reported as 'Success' if all its dependencies either
# pass or are skipped due to path filtering.
status:
needs: [check_changes, python_config, showcase-unit, showcase-mypy, goldens, goldens-prerelease, fragment-snippet, integration]
needs: [check_changes, python_config, showcase-unit, showcase-system, showcase-mypy, goldens, goldens-prerelease, fragment-snippet, integration]
if: always()
runs-on: ubuntu-latest
steps:
Expand All @@ -261,4 +295,3 @@ jobs:
exit 1
fi
echo "All checks passed or were successfully skipped."

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ venv/
# Test logs
coverage.xml
*sponge_log.xml
raw_spans_output*.json

# System test environment variables.
**/system_tests/local_test_setup
Expand All @@ -72,3 +73,6 @@ bazel-bin
bazel-gapic-generator
bazel-out
bazel-testlogs

# Telemetry raw spans dump
raw_spans_output-*.json
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: '^packages/gapic-generator/tests/integration/goldens/'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
Expand Down
10 changes: 10 additions & 0 deletions packages/gapic-generator/gapic/schema/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,60 @@
"DeleteOperation",
request_type="operations_pb2.DeleteOperationRequest",
response_type="None",
rpc_name="google.longrunning.Operations/DeleteOperation",
),
"WaitOperation": wrappers.MixinMethod(
"WaitOperation",
request_type="operations_pb2.WaitOperationRequest",
response_type="operations_pb2.Operation",
rpc_name="google.longrunning.Operations/WaitOperation",
),
"ListOperations": wrappers.MixinMethod(
"ListOperations",
request_type="operations_pb2.ListOperationsRequest",
response_type="operations_pb2.ListOperationsResponse",
rpc_name="google.longrunning.Operations/ListOperations",
),
"CancelOperation": wrappers.MixinMethod(
"CancelOperation",
request_type="operations_pb2.CancelOperationRequest",
response_type="None",
rpc_name="google.longrunning.Operations/CancelOperation",
),
"GetOperation": wrappers.MixinMethod(
"GetOperation",
request_type="operations_pb2.GetOperationRequest",
response_type="operations_pb2.Operation",
rpc_name="google.longrunning.Operations/GetOperation",
),
"TestIamPermissions": wrappers.MixinMethod(
"TestIamPermissions",
request_type="iam_policy_pb2.TestIamPermissionsRequest",
response_type="iam_policy_pb2.TestIamPermissionsResponse",
rpc_name="google.iam.v1.IAMPolicy/TestIamPermissions",
),
"GetIamPolicy": wrappers.MixinMethod(
"GetIamPolicy",
request_type="iam_policy_pb2.GetIamPolicyRequest",
response_type="policy_pb2.Policy",
rpc_name="google.iam.v1.IAMPolicy/GetIamPolicy",
),
"SetIamPolicy": wrappers.MixinMethod(
"SetIamPolicy",
request_type="iam_policy_pb2.SetIamPolicyRequest",
response_type="policy_pb2.Policy",
rpc_name="google.iam.v1.IAMPolicy/SetIamPolicy",
),
"ListLocations": wrappers.MixinMethod(
"ListLocations",
request_type="locations_pb2.ListLocationsRequest",
response_type="locations_pb2.ListLocationsResponse",
rpc_name="google.cloud.location.Locations/ListLocations",
),
"GetLocation": wrappers.MixinMethod(
"GetLocation",
request_type="locations_pb2.GetLocationRequest",
response_type="locations_pb2.Location",
rpc_name="google.cloud.location.Locations/GetLocation",
),
}
2 changes: 2 additions & 0 deletions packages/gapic-generator/gapic/schema/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,8 @@ class MixinMethod:
name: str
request_type: str
response_type: str
rpc_name: str = ""



@dataclasses.dataclass(frozen=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
"""A compatibility module for older versions of google-api-core."""
{% set has_auto_populated_fields = api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|select|list %}
{# TODO(https://github.com/googleapis/google-cloud-python/issues/17813):
Clean up this file/functions when the minimum supported version of
Clean up this file/functions when the minimum supported version of
google-api-core has the functions in `_compat.py.j2`. #}
{# TODO(https://github.com/googleapis/google-cloud-python/issues/17884):
Add conditional logic to check if static code exists in google-api-core and use it from there,
{# TODO(https://github.com/googleapis/google-cloud-python/issues/17884):
Add conditional logic to check if static code exists in google-api-core and use it from there,
falling back to the local implementation if not present. #}
{# TODO(https://github.com/googleapis/google-cloud-python/issues/17883):
{# TODO(https://github.com/googleapis/google-cloud-python/issues/17883):
Backfill compatibility functions being removed from the client layer. #}

import contextlib
import os
import json
{% if has_auto_populated_fields %}
Expand All @@ -23,9 +24,6 @@ import google.protobuf.message
from typing import Any, Dict, List, Optional, Tuple
{% if has_auto_populated_fields %}
from typing import TYPE_CHECKING, Union

if TYPE_CHECKING: # pragma: NO COVER
import proto # type: ignore[import-untyped]
{% endif %}

from google.api_core import path_template
Expand All @@ -34,9 +32,37 @@ from google.auth.exceptions import MutualTLSChannelError
from google.protobuf import json_format
from urllib.parse import urlparse, urlunparse

{% if has_auto_populated_fields %}
if TYPE_CHECKING: # pragma: NO COVER
import proto # type: ignore[import-untyped]
{% endif %}

# The _observability module was introduced in google-api-core 2.36.0+.
# On older versions of google-api-core or when type-checking against them,
# mypy may flag attr-defined or assignment errors when fallback to None occurs.
try:
from google.api_core import _observability # type: ignore[attr-defined]
except ImportError: # pragma: NO COVER
_observability = None # type: ignore[assignment]

if _observability is not None and hasattr(_observability, "trace_http_request"):
trace_http_request = _observability.trace_http_request
else: # pragma: NO COVER
# Fallback for older versions of google-api-core without HTTP tracing.
@contextlib.contextmanager
def trace_http_request(*args: Any, **kwargs: Any):
yield None

if _observability is not None and hasattr(_observability, "record_http_response"):
record_http_response = _observability.record_http_response
else: # pragma: NO COVER
# Fallback for older versions of google-api-core without HTTP tracing.
def record_http_response(span: Any, response: Any) -> None:
pass

try:
# note: `#type: ignore` is added because the return type for `should_use_client_cert`
# is different than that of the fallback implementation below. This will be removed once
# is different than that of the fallback implementation below. This will be removed once
# we bump the minimum supported version of google-auth.
from google.auth.transport.mtls import should_use_client_cert # type: ignore
except ImportError: # pragma: NO COVER
Expand Down
Loading
Loading