Skip to content

Commit f198a7c

Browse files
authored
Correctly trace OTLP spans (#457)
This PR fixes an issue where `DBOS.span` does not return the current active span. Instead, it always returned the span created by DBOS. This would cause incorrect span tree structure. For example: ```python @DBOS.workflow() def test_workflow() -> None: with my_tracer.start_as_current_span("manual_span"): test_step() ``` Without this PR, the span tree is wrong: ``` test_workflow |- manual_span |- test_step ``` With this PR, `test_step` will correctly show as the child of `manual_span`: ``` test_workflow |- manual_span |- test_step ```
1 parent 32f3312 commit f198a7c

File tree

8 files changed

+194
-45
lines changed

8 files changed

+194
-45
lines changed

dbos/_context.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,18 @@ def start_handler(self, attributes: TracedAttributes) -> None:
215215
def end_handler(self, exc_value: Optional[BaseException]) -> None:
216216
self._end_span(exc_value)
217217

218-
def get_current_span(self) -> Optional[Span]:
218+
""" Return the current DBOS span if any. It must be a span created by DBOS."""
219+
220+
def get_current_dbos_span(self) -> Optional[Span]:
219221
if len(self.context_spans) > 0:
220222
return self.context_spans[-1].span
221223
return None
222224

225+
""" Return the current active span if any. It might not be a DBOS span."""
226+
227+
def get_current_active_span(self) -> Optional[Span]:
228+
return dbos_tracer.get_current_span()
229+
223230
def _start_span(self, attributes: TracedAttributes) -> None:
224231
if dbos_tracer.disable_otlp:
225232
return
@@ -235,7 +242,7 @@ def _start_span(self, attributes: TracedAttributes) -> None:
235242
attributes["authenticatedUserAssumedRole"] = self.assumed_role
236243
span = dbos_tracer.start_span(
237244
attributes,
238-
parent=self.context_spans[-1].span if len(self.context_spans) > 0 else None,
245+
parent=None, # It'll use the current active span as the parent
239246
)
240247
# Activate the current span
241248
cm = use_span(

dbos/_core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ def invoke_tx(*args: Any, **kwargs: Any) -> Any:
971971
dbapi_error
972972
) or dbos._app_db._is_serialization_error(dbapi_error):
973973
# Retry on serialization failure
974-
span = ctx.get_current_span()
974+
span = ctx.get_current_dbos_span()
975975
if span:
976976
span.add_event(
977977
"Transaction Failure",
@@ -1090,7 +1090,7 @@ def on_exception(attempt: int, error: BaseException) -> float:
10901090
exc_info=error,
10911091
)
10921092
ctx = assert_current_dbos_context()
1093-
span = ctx.get_current_span()
1093+
span = ctx.get_current_dbos_span()
10941094
if span:
10951095
span.add_event(
10961096
f"Step attempt {attempt} failed",

dbos/_dbos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,7 @@ def parent_workflow_id(cls) -> str:
12971297
def span(cls) -> Span:
12981298
"""Return the tracing `Span` associated with the current context."""
12991299
ctx = assert_current_dbos_context()
1300-
span = ctx.get_current_span()
1300+
span = ctx.get_current_active_span()
13011301
assert span
13021302
return span
13031303

dbos/_logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def filter(self, record: Any) -> bool:
3939
if ctx:
4040
if ctx.is_within_workflow():
4141
record.operationUUID = ctx.workflow_id
42-
span = ctx.get_current_span()
42+
span = ctx.get_current_active_span()
4343
if span:
4444
trace_id = format_trace_id(span.get_span_context().trace_id)
4545
record.traceId = trace_id

dbos/_tracer.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,12 @@ def start_span(
7777
def end_span(self, span: Span) -> None:
7878
span.end()
7979

80+
def get_current_span(self) -> Optional[Span]:
81+
# Return the current active span if any. It might not be a DBOS span.
82+
span = trace.get_current_span()
83+
if span.get_span_context().is_valid:
84+
return span
85+
return None
86+
8087

8188
dbos_tracer = DBOSTracer()

pdm.lock

Lines changed: 45 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,5 @@ dev = [
8585
"pyright>=1.1.398",
8686
"types-docker>=7.1.0.20241229",
8787
"pytest-timeout>=2.3.1",
88+
"inline-snapshot>=0.28.0",
8889
]

0 commit comments

Comments
 (0)