Skip to content

Commit 3389806

Browse files
committed
tracing: update OpenTelemetry dependencies from 2021 to 2024
This change non-invasively introduces dependencies of opentelemetry bringing in the latest dependencies and modernizing them. While here also brought in modern span attributes: * otel.scope.name * otel.scope.version Also added a modernized example and updated the docs. Updates googleapis#1170 Fixes googleapis#1173 Built from PR googleapis#1172
1 parent a941adb commit 3389806

File tree

6 files changed

+96
-16
lines changed

6 files changed

+96
-16
lines changed

docs/opentelemetry-tracing.rst

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,69 @@ To take advantage of these traces, we first need to install OpenTelemetry:
99
.. code-block:: sh
1010
1111
pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation
12-
13-
# [Optional] Installs the cloud monitoring exporter, however you can use any exporter of your choice
14-
pip install opentelemetry-exporter-google-cloud
12+
pip install opentelemetry-exporter-gcp-trace
1513
1614
We also need to tell OpenTelemetry which exporter to use. To export Spanner traces to `Cloud Tracing <https://cloud.google.com/trace>`_, add the following lines to your application:
1715

1816
.. code:: python
1917
2018
from opentelemetry import trace
2119
from opentelemetry.sdk.trace import TracerProvider
22-
from opentelemetry.trace.sampling import ProbabilitySampler
20+
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
2321
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
24-
# BatchExportSpanProcessor exports spans to Cloud Trace
22+
# BatchSpanProcessor exports spans to Cloud Trace
2523
# in a seperate thread to not block on the main thread
26-
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
24+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
2725
2826
# Create and export one trace every 1000 requests
29-
sampler = ProbabilitySampler(1/1000)
27+
sampler = TraceIdRatioBased(1/1000)
3028
# Use the default tracer provider
3129
trace.set_tracer_provider(TracerProvider(sampler=sampler))
3230
trace.get_tracer_provider().add_span_processor(
3331
# Initialize the cloud tracing exporter
34-
BatchExportSpanProcessor(CloudTraceSpanExporter())
32+
BatchSpanProcessor(CloudTraceSpanExporter())
33+
)
34+
35+
36+
Alternatively you can pass in a tracer provider into the Cloud Spanner
37+
initialization, otherwise the global tracer will be used:
38+
39+
.. code:: python
40+
41+
from opentelemetry.sdk.trace import TracerProvider
42+
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
43+
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
44+
45+
# Create and export one trace every 1000 requests
46+
sampler = TraceIdRatioBased(1/1000)
47+
tracerProvider = TracerProvider(sampler=sampler)
48+
tracerProvider.add_span_processor(
49+
# Initialize the cloud tracing exporter
50+
BatchSpanProcessor(CloudTraceSpanExporter())
3551
)
3652
53+
options = dict(tracer_provider=tracerProvider)
54+
# Pass the tracer provider while creating the Spanner client.
55+
spanner_client = spanner.Client(observability_options=options)
56+
instance = spanner_client.instance(instance_id)
57+
database = instance.database(database_id)
58+
59+
60+
To get more fine-grained traces from gRPC, you can enable the gRPC instrumentation by the following
61+
62+
.. code-block:: sh
63+
64+
pip install opentelemetry-instrumentation-grpc
65+
66+
and then in your Python code, please add the following lines:
67+
68+
.. code:: python
69+
70+
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
71+
grpc_client_instrumentor = GrpcInstrumentorClient()
72+
grpc_client_instrumentor.instrument()
73+
74+
3775
Generated spanner traces should now be available on `Cloud Trace <https://console.cloud.google.com/traces>`_.
3876

3977
Tracing is most effective when many libraries are instrumented to provide insight over the entire lifespan of a request.

google/cloud/spanner_v1/_opentelemetry_tracing.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,40 @@
1818

1919
from google.api_core.exceptions import GoogleAPICallError
2020
from google.cloud.spanner_v1 import SpannerClient
21+
from google.cloud.spanner_v1 import gapic_version
2122

2223
try:
2324
from opentelemetry import trace
2425
from opentelemetry.trace.status import Status, StatusCode
26+
from opentelemetry.semconv.attributes.otel_attributes import (
27+
OTEL_SCOPE_NAME,
28+
OTEL_SCOPE_VERSION,
29+
)
2530

2631
HAS_OPENTELEMETRY_INSTALLED = True
2732
except ImportError:
2833
HAS_OPENTELEMETRY_INSTALLED = False
2934

35+
LIB_VERSION = gapic_version.__version__
36+
LIB_FQNAME = 'cloud.google.com/python/spanner'
37+
TRACER_NAME = LIB_FQNAME
38+
TRACER_VERSION = LIB_VERSION
39+
40+
41+
def get_tracer(tracer_provider=None):
42+
"""
43+
get_tracer is a utility to unify and simplify retrieval of the tracer, without
44+
leaking implementation details given that retrieving a tracer requires providing
45+
the full qualified library name and version.
46+
When the tracer_provider is set, it'll retrieve the tracer from it, otherwise
47+
it'll fall back to the global tracer provider and use this library's specific semantics.
48+
"""
49+
if not tracer_provider:
50+
# Acquire the global tracer provider.
51+
tracer_provider = trace.get_tracer_provider()
52+
53+
return tracer_provider.get_tracer(TRACER_NAME, TRACER_VERSION)
54+
3055

3156
@contextmanager
3257
def trace_call(name, session, extra_attributes=None):
@@ -35,14 +60,16 @@ def trace_call(name, session, extra_attributes=None):
3560
yield None
3661
return
3762

38-
tracer = trace.get_tracer(__name__)
63+
tracer = get_tracer()
3964

4065
# Set base attributes that we know for every trace created
4166
attributes = {
4267
"db.type": "spanner",
4368
"db.url": SpannerClient.DEFAULT_ENDPOINT,
4469
"db.instance": session._database.name,
4570
"net.host.name": SpannerClient.DEFAULT_ENDPOINT,
71+
OTEL_SCOPE_NAME: LIB_FQNAME,
72+
OTEL_SCOPE_VERSION: LIB_VERSION,
4673
}
4774

4875
if extra_attributes:

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@
4747
]
4848
extras = {
4949
"tracing": [
50-
"opentelemetry-api >= 1.1.0",
51-
"opentelemetry-sdk >= 1.1.0",
52-
"opentelemetry-instrumentation >= 0.20b0, < 0.23dev",
50+
"opentelemetry-api >= 1.24.0",
51+
"opentelemetry-sdk >= 1.24.0",
52+
"opentelemetry-instrumentation >= 0.46b0",
53+
"opentelemetry-semantic-conventions >= 0.46b0",
5354
],
5455
"libcst": "libcst >= 0.2.5",
5556
}

testing/constraints-3.7.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ grpc-google-iam-v1==0.12.4
1010
libcst==0.2.5
1111
proto-plus==1.22.0
1212
sqlparse==0.4.4
13-
opentelemetry-api==1.1.0
14-
opentelemetry-sdk==1.1.0
15-
opentelemetry-instrumentation==0.20b0
13+
opentelemetry-api>=1.24.0
14+
opentelemetry-sdk>=1.24.0
15+
opentelemetry-instrumentation==0.46b0
16+
opentelemetry-semantic-conventions==0.46b0
1617
protobuf==3.20.2
1718
deprecated==1.2.14
1819
grpc-interceptor==0.15.4

tests/_helpers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@
99
InMemorySpanExporter,
1010
)
1111
from opentelemetry.trace.status import StatusCode
12+
from opentelemetry.semconv.attributes import (
13+
OTEL_SCOPE_NAME,
14+
OTEL_SCOPE_VERSION,
15+
)
1216

1317
trace.set_tracer_provider(TracerProvider())
1418

1519
HAS_OPENTELEMETRY_INSTALLED = True
1620
except ImportError:
1721
HAS_OPENTELEMETRY_INSTALLED = False
22+
OTEL_SCOPE_NAME = "otel.scope.name"
1823

1924
StatusCode = mock.Mock()
2025

tests/unit/test__opentelemetry_tracing.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
from google.api_core.exceptions import GoogleAPICallError
1313
from google.cloud.spanner_v1 import _opentelemetry_tracing
1414

15-
from tests._helpers import OpenTelemetryBase, HAS_OPENTELEMETRY_INSTALLED
15+
from tests._helpers import (
16+
OpenTelemetryBase,
17+
HAS_OPENTELEMETRY_INSTALLED,
18+
OTEL_SCOPE_NAME,
19+
)
1620

1721

1822
def _make_rpc_error(error_cls, trailing_metadata=None):
@@ -59,6 +63,7 @@ def test_trace_call(self):
5963
"db.type": "spanner",
6064
"db.url": "spanner.googleapis.com",
6165
"net.host.name": "spanner.googleapis.com",
66+
OTEL_SCOPE_NAME: "cloud.google.com/python/spanner",
6267
}
6368
expected_attributes.update(extra_attributes)
6469

@@ -84,6 +89,7 @@ def test_trace_error(self):
8489
"db.type": "spanner",
8590
"db.url": "spanner.googleapis.com",
8691
"net.host.name": "spanner.googleapis.com",
92+
OTEL_SCOPE_NAME: "cloud.google.com/python/spanner",
8793
}
8894
expected_attributes.update(extra_attributes)
8995

@@ -110,6 +116,7 @@ def test_trace_grpc_error(self):
110116
"db.type": "spanner",
111117
"db.url": "spanner.googleapis.com:443",
112118
"net.host.name": "spanner.googleapis.com:443",
119+
OTEL_SCOPE_NAME: "cloud.google.com/python/spanner",
113120
}
114121
expected_attributes.update(extra_attributes)
115122

@@ -133,6 +140,7 @@ def test_trace_codeless_error(self):
133140
"db.type": "spanner",
134141
"db.url": "spanner.googleapis.com:443",
135142
"net.host.name": "spanner.googleapis.com:443",
143+
OTEL_SCOPE_NAME: "cloud.google.com/python/spanner",
136144
}
137145
expected_attributes.update(extra_attributes)
138146

0 commit comments

Comments
 (0)