Skip to content
Prev Previous commit
Next Next commit
feat(opentelemetry): add request_tag to span attributes
  • Loading branch information
sinhasubham committed Nov 11, 2025
commit f3bf07401a8dbbebbd6b812cbea02b9f4951985b
25 changes: 19 additions & 6 deletions google/cloud/spanner_v1/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,16 @@
from opentelemetry.propagate import inject
from opentelemetry.propagators.textmap import Setter
from opentelemetry.semconv.resource import ResourceAttributes
from opentelemetry.resourcedetector import gcp_resource_detector
from opentelemetry.resourcedetector.gcp_resource_detector import (
GoogleCloudResourceDetector,
)

# Overwrite the requests timeout for the detector.
# This is necessary as the client will wait the full timeout if the
# code is not run in a GCP environment, with the location endpoints available.
gcp_resource_detector._TIMEOUT_SEC = 0.2

HAS_OPENTELEMETRY_INSTALLED = True
except ImportError:
HAS_OPENTELEMETRY_INSTALLED = False
Expand All @@ -65,6 +71,8 @@

log = logging.getLogger(__name__)

_cloud_region: str = None


if HAS_OPENTELEMETRY_INSTALLED:

Expand All @@ -90,25 +98,30 @@ def set(self, carrier: List[Tuple[str, str]], key: str, value: str) -> None:


def _get_cloud_region() -> str:
"""Get the location of the resource.
"""Get the location of the resource, caching the result.

Returns:
str: The location of the resource. If OpenTelemetry is not installed, returns a global region.
"""
if not HAS_OPENTELEMETRY_INSTALLED:
return GOOGLE_CLOUD_REGION_GLOBAL
global _cloud_region
if _cloud_region is not None:
return _cloud_region

try:
detector = GoogleCloudResourceDetector()
resources = detector.detect()

if ResourceAttributes.CLOUD_REGION in resources.attributes:
return resources.attributes[ResourceAttributes.CLOUD_REGION]
_cloud_region = resources.attributes[ResourceAttributes.CLOUD_REGION]
else:
_cloud_region = GOOGLE_CLOUD_REGION_GLOBAL
except Exception as e:
log.warning(
"Failed to detect GCP resource location for Spanner metrics, defaulting to 'global'. Error: %s",
e,
)
return GOOGLE_CLOUD_REGION_GLOBAL
_cloud_region = GOOGLE_CLOUD_REGION_GLOBAL

return _cloud_region


def _try_to_coerce_bytes(bytestring):
Expand Down
3 changes: 1 addition & 2 deletions google/cloud/spanner_v1/_opentelemetry_tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ def trace_call(
"enable_end_to_end_tracing", enable_end_to_end_tracing
)
db_name = observability_options.get("db_name", db_name)
cloud_region = observability_options.get("cloud_region", cloud_region)

cloud_region = _get_cloud_region()
tracer = get_tracer(tracer_provider)
Expand All @@ -125,7 +124,7 @@ def trace_call(
if "request_options" in attributes:
request_options = attributes.pop("request_options")
if request_options and request_options.request_tag:
attributes["spanner.request_tag"] = request_options.request_tag
attributes["request.tag"] = request_options.request_tag

if extended_tracing_globally_disabled:
enable_extended_tracing = False
Expand Down
3 changes: 2 additions & 1 deletion tests/system/test_session_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from google.cloud.spanner_admin_database_v1 import DatabaseDialect
from google.cloud._helpers import UTC

from google.cloud.spanner_v1._helpers import _get_cloud_region
from google.cloud.spanner_v1._helpers import AtomicCounter
from google.cloud.spanner_v1.data_types import JsonObject
from google.cloud.spanner_v1.database_sessions_manager import TransactionType
Expand Down Expand Up @@ -354,7 +355,7 @@ def _make_attributes(db_instance, **kwargs):
"db.url": "spanner.googleapis.com",
"net.host.name": "spanner.googleapis.com",
"db.instance": db_instance,
"cloud.region": "global",
"cloud.region": _get_cloud_region(),
"gcp.client.service": "spanner",
"gcp.client.version": ot_helpers.LIB_VERSION,
"gcp.client.repo": "googleapis/python-spanner",
Expand Down
5 changes: 4 additions & 1 deletion tests/unit/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from opentelemetry.semconv.resource import ResourceAttributes


from google.cloud.spanner_v1 import TransactionOptions
from google.cloud.spanner_v1 import TransactionOptions, _helpers


class Test_merge_query_options(unittest.TestCase):
Expand Down Expand Up @@ -94,6 +94,9 @@ def test_base_object_merge_dict(self):


class Test_get_cloud_region(unittest.TestCase):
def setUp(self):
_helpers._cloud_region = None

def _callFUT(self, *args, **kw):
from google.cloud.spanner_v1._helpers import _get_cloud_region

Expand Down
5 changes: 2 additions & 3 deletions tests/unit/test_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
TransactionOptions,
TransactionSelector,
)
from google.cloud.spanner_v1._helpers import _get_cloud_region
from google.cloud.spanner_v1.snapshot import _SnapshotBase
from tests._builders import (
build_precommit_token_pb,
Expand Down Expand Up @@ -1048,7 +1047,7 @@ def _execute_read(
x_goog_spanner_request_id=req_id,
)
if request_options and request_options.request_tag:
expected_attributes["spanner.request_tag"] = request_options.request_tag
expected_attributes["request.tag"] = request_options.request_tag
self.assertSpanAttributes(
"CloudSpanner._Derived.read", attributes=expected_attributes
)
Expand Down Expand Up @@ -1407,7 +1406,7 @@ def _execute_sql_helper(
},
)
if request_options and request_options.request_tag:
expected_attributes["spanner.request_tag"] = request_options.request_tag
expected_attributes["request.tag"] = request_options.request_tag

self.assertSpanAttributes(
"CloudSpanner._Derived.execute_sql",
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
TransactionOptions,
ResultSetMetadata,
)
from google.cloud.spanner_v1._helpers import _get_cloud_region
from google.cloud.spanner_v1._helpers import GOOGLE_CLOUD_REGION_GLOBAL
from google.cloud.spanner_v1 import DefaultTransactionOptions
from google.cloud.spanner_v1 import Type
Expand Down Expand Up @@ -841,7 +840,7 @@ def _execute_update_helper(
database, **{"db.statement": DML_QUERY_WITH_PARAM}
)
if request_options.request_tag:
expected_attributes["spanner.request_tag"] = request_options.request_tag
expected_attributes["request.tag"] = request_options.request_tag
self.assertSpanAttributes(
"CloudSpanner.Transaction.execute_update", attributes=expected_attributes
)
Expand Down