11"""Telemetry: spans, adapters, and the ambient current span.
22
3+ Experimental: not part of the stable API, may change or be removed.
4+
35:class:`Span` is a record of work done by the application. It carries
46start, end, parent, and typed data.
57
68Same API is used to instrument the framework and define custom spans::
79
8- async with ai.telemetry .span("retrieval", query=q) as sp:
10+ async with ai.experimental_telemetry .span("retrieval", query=q) as sp:
911 docs = await search(q)
1012 sp.set(count=len(docs))
1113
@@ -19,7 +21,7 @@ async def on_span_start(self, span): ...
1921 async def on_span_end(self, span): ...
2022 async def on_span_event(self, span, event): ...
2123
22- ai.telemetry .register(MyAdapter())
24+ ai.experimental_telemetry .register(MyAdapter())
2325
2426Adapters dispatch on the type of ``span.data``. An adapter that crashes
2527is logged and skipped, it never kills the run.
@@ -97,13 +99,13 @@ def use_clock(now_ns: Callable[[], int]) -> Iterator[None]:
9799 used to plug an approved clock function in durable execution
98100 settings::
99101
100- with ai.telemetry .use_clock(workflow.time_ns):
102+ with ai.experimental_telemetry .use_clock(workflow.time_ns):
101103 ... # spans opened here read time from workflow.time_ns
102104
103105 This can also be used as a decorator on both sync and async
104106 functions::
105107
106- @ai.telemetry .use_clock(clock.time_ns)
108+ @ai.experimental_telemetry .use_clock(clock.time_ns)
107109 async def run(...):
108110 ...
109111 """
@@ -131,7 +133,8 @@ class RetrievalSpanData:
131133
132134 span_name: ClassVar[str] = "retrieval"
133135
134- async with ai.telemetry.span(RetrievalSpanData(query=q)) as sp:
136+ data = RetrievalSpanData(query=q)
137+ async with ai.experimental_telemetry.span(data) as sp:
135138 docs = await search(q)
136139 sp.data.count = len(docs) # typed
137140
@@ -289,12 +292,12 @@ class SpanRef(pydantic.BaseModel):
289292 (``model_dump`` / ``model_validate``); restore by opening a span
290293 with ``parent=ref`` on the other side::
291294
292- ref = ai.telemetry .current_ref()
295+ ref = ai.experimental_telemetry .current_ref()
293296 job = {"task": task, "telemetry": ref.model_dump()}
294297
295298 # elsewhere:
296- ref = ai.telemetry .SpanRef.model_validate(job["telemetry"])
297- async with ai.telemetry .span("pickup", parent=ref):
299+ ref = ai.experimental_telemetry .SpanRef.model_validate(job["telemetry"])
300+ async with ai.experimental_telemetry .span("pickup", parent=ref):
298301 ... # everything inside continues the original trace
299302
300303 ``sampled`` is carried so refs round-trip sampling decisions
@@ -685,7 +688,7 @@ async def vendor(span):
685688 v.log_event(ev.name, timestamp=ev.time_ns)
686689 v.update(output=span.data) # span end
687690
688- ai.telemetry .register(vendor)
691+ ai.experimental_telemetry .register(vendor)
689692
690693 - A span that ends with an error is thrown into the generator at
691694 the ``yield``, so the vendor context manager sees the failure.
0 commit comments