Skip to content

Commit 47ffdfc

Browse files
committed
General touch-ups for every better fine-grained spans and events
1 parent 51d3e91 commit 47ffdfc

File tree

11 files changed

+269
-139
lines changed

11 files changed

+269
-139
lines changed

google/cloud/spanner_v1/_opentelemetry_tracing.py

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ def get_tracer(tracer_provider=None):
5454
return tracer_provider.get_tracer(TRACER_NAME, TRACER_VERSION)
5555

5656

57-
def trace_end_explicitly(
58-
name, session=None, extra_attributes=None, observability_options=None
57+
def _make_tracer_and_span_attributes(
58+
session=None, extra_attributes=None, observability_options=None
5959
):
6060
if not HAS_OPENTELEMETRY_INSTALLED:
61-
return None
61+
return None, None
6262

6363
tracer_provider = None
6464

@@ -68,7 +68,7 @@ def trace_end_explicitly(
6868
enable_extended_tracing = True
6969

7070
db_name = ""
71-
if session and session._database:
71+
if session and getattr(session, "_database", None):
7272
db_name = session._database.name
7373

7474
if isinstance(observability_options, dict): # Avoid false positives with mock.Mock
@@ -99,13 +99,45 @@ def trace_end_explicitly(
9999
if not enable_extended_tracing:
100100
attributes.pop("db.statement", False)
101101

102-
return tracer.start_span(name, kind=trace.SpanKind.CLIENT, attributes=attributes)
102+
return tracer, attributes
103+
104+
105+
def trace_call_end_lazily(
106+
name, session=None, extra_attributes=None, observability_options=None
107+
):
108+
"""
109+
 trace_call_end_lazily is used in situations where you won't have a context manager
110+
 and need to end a span explicitly when a specific condition happens. If you need a
111+
 context manager, please invoke `trace_call` with which you can invoke
112+
 `with trace_call(...) as span:`
113+
 It is the caller's responsibility to explicitly invoke span.end()
114+
"""
115+
tracer, span_attributes = _make_tracer_and_span_attributes(
116+
session, extra_attributes, observability_options
117+
)
118+
if not tracer:
119+
return None
120+
return tracer.start_span(
121+
name, kind=trace.SpanKind.CLIENT, attributes=span_attributes
122+
)
103123

104124

105125
@contextmanager
106126
def trace_call(name, session=None, extra_attributes=None, observability_options=None):
107-
with trace_end_explicitly(
108-
name, session, extra_attributes, observability_options
127+
"""
128+
 trace_call is used in situations where you need to end a span with a context manager
129+
 or after a scope is exited. If you need to keep a span alive and lazily end it, please
130+
 invoke `trace_call_end_lazily`.
131+
"""
132+
tracer, span_attributes = _make_tracer_and_span_attributes(
133+
session, extra_attributes, observability_options
134+
)
135+
if not tracer:
136+
yield None
137+
return
138+
139+
with tracer.start_as_current_span(
140+
name, kind=trace.SpanKind.CLIENT, attributes=span_attributes
109141
) as span:
110142
try:
111143
yield span
@@ -115,3 +147,25 @@ def trace_call(name, session=None, extra_attributes=None, observability_options=
115147
raise
116148
else:
117149
span.set_status(Status(StatusCode.OK))
150+
151+
152+
def set_span_status_error(span, error):
153+
if span:
154+
span.set_status(Status(StatusCode.ERROR, str(error)))
155+
156+
157+
def set_span_status_ok(span):
158+
if span:
159+
span.set_status(Status(StatusCode.OK))
160+
161+
162+
def get_current_span():
163+
if not HAS_OPENTELEMETRY_INSTALLED:
164+
return None
165+
return trace.get_current_span()
166+
167+
168+
def add_event_on_current_span(self, event_name, attributes=None):
169+
current_span = get_current_span()
170+
if current_span:
171+
current_span.add_event(event_commentary, attributes)

google/cloud/spanner_v1/batch.py

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@
2727
_metadata_with_leader_aware_routing,
2828
)
2929
from google.cloud.spanner_v1._opentelemetry_tracing import (
30+
add_event_on_current_span,
3031
trace_call,
31-
trace_end_explicitly,
32+
trace_call_end_lazily,
3233
)
3334
from google.cloud.spanner_v1 import RequestOptions
3435
from google.cloud.spanner_v1._helpers import _retry
@@ -50,9 +51,9 @@ def __init__(self, session):
5051
super(_BatchBase, self).__init__(session)
5152
self._mutations = []
5253
observability_options = getattr(
53-
self._session.database, "observability_options", None
54+
self._session._database, "observability_options", None
5455
)
55-
self.__span = trace_end_explicitly(
56+
self.__span = trace_call_end_lazily(
5657
"CloudSpannerX." + type(self).__name__,
5758
self._session,
5859
observability_options=observability_options,
@@ -80,10 +81,9 @@ def insert(self, table, columns, values):
8081
:type values: list of lists
8182
:param values: Values to be modified.
8283
"""
83-
if self.__span:
84-
self.__span.add_event(
85-
"insert mutations inserted", dict(table=table, columns=columns)
86-
)
84+
add_event_on_span(
85+
self.__span, "insert mutations added", dict(table=table, columns=columns)
86+
)
8787
self._mutations.append(Mutation(insert=_make_write_pb(table, columns, values)))
8888

8989
def update(self, table, columns, values):
@@ -98,11 +98,10 @@ def update(self, table, columns, values):
9898
:type values: list of lists
9999
:param values: Values to be modified.
100100
"""
101-
if self.__span:
102-
self.__span.add_event(
103-
"update mutations inserted", dict(table=table, columns=columns)
104-
)
105101
self._mutations.append(Mutation(update=_make_write_pb(table, columns, values)))
102+
add_event_on_span(
103+
self.__span, "update mutations added", dict(table=table, columns=columns)
104+
)
106105

107106
def insert_or_update(self, table, columns, values):
108107
"""Insert/update one or more table rows.
@@ -116,14 +115,14 @@ def insert_or_update(self, table, columns, values):
116115
:type values: list of lists
117116
:param values: Values to be modified.
118117
"""
119-
if self.__span:
120-
self.__span.add_event(
121-
"insert_or_update mutations inserted",
122-
dict(table=table, columns=columns),
123-
)
124118
self._mutations.append(
125119
Mutation(insert_or_update=_make_write_pb(table, columns, values))
126120
)
121+
add_event_on_span(
122+
self.__span,
123+
"insert_or_update mutations added",
124+
dict(table=table, columns=columns),
125+
)
127126

128127
def replace(self, table, columns, values):
129128
"""Replace one or more table rows.
@@ -137,11 +136,10 @@ def replace(self, table, columns, values):
137136
:type values: list of lists
138137
:param values: Values to be modified.
139138
"""
140-
if self.__span:
141-
self.__span.add_event(
142-
"replace mutations inserted", dict(table=table, columns=columns)
143-
)
144139
self._mutations.append(Mutation(replace=_make_write_pb(table, columns, values)))
140+
add_event_on_span(
141+
self.__span, "replace mutations added", dict(table=table, columns=columns)
142+
)
145143

146144
def delete(self, table, keyset):
147145
"""Delete one or more table rows.
@@ -154,10 +152,7 @@ def delete(self, table, keyset):
154152
"""
155153
delete = Mutation.Delete(table=table, key_set=keyset._to_pb())
156154
self._mutations.append(Mutation(delete=delete))
157-
if self.__span:
158-
self.__span.add_event(
159-
"delete mutations inserted", dict(table=table, columns=columns)
160-
)
155+
add_event_on_span(self.__span, "delete mutations added", dict(table=table))
161156

162157

163158
class Batch(_BatchBase):
@@ -261,9 +256,9 @@ def __enter__(self):
261256
"""Begin ``with`` block."""
262257
self._check_state()
263258
observability_options = getattr(
264-
self._session.database, "observability_options", None
259+
self._session._database, "observability_options", None
265260
)
266-
self.__span = trace_end_explicitly(
261+
self.__span = trace_call_end_lazily(
267262
"CloudSpanner.Batch",
268263
self._session,
269264
observability_options=observability_options,

0 commit comments

Comments
 (0)