Prism OpenTelemetry for Python
OpenTelemetry spans for Prism generations, using the GenAI semantic conventions
and the OpenInference keys that Phoenix and Arize read. The Python port of
particle-academy/prism-opentelemetry.
Zero runtime dependencies. Python 3.10+.
pip install prism-ai-opentelemetry
from prism_opentelemetry import GenerationContext, PendingTool, TelemetrySubscriber, Usage
telemetry = TelemetrySubscriber(my_tracer)
context = GenerationContext(
trace_id="run-42", operation="text", provider="anthropic", model="claude-opus-5"
)
telemetry.on_generation_started(context, prompt)
telemetry.on_tool_invoked("run-42", PendingTool(name="search", call_id="call_1", step_index=0))
telemetry.on_step_completed(
"run-42", 0, "claude-opus-5", "anthropic", Usage(prompt_tokens=812, completion_tokens=64)
)
telemetry.on_generation_completed("run-42", finish_reason="stop", output=response_text)
my_tracer is anything with start_span(name, start_time_nanos=None, parent=None)
returning a span with set_attribute, set_status, record_exception and
end. Wrap your OpenTelemetry SDK tracer in that method; the package imports no
OpenTelemetry code.
Spans
- One root span per generation, with the operation, provider, model and,
when given,
session.idanduser.id. - A child span per step, with token usage and, when given, cost.
- A child span per tool call (
execute_tool <name>), attached to the step it belongs to. - A failed generation ends its root span with an error status.
Children are parented off the root stored in SpanStore under the trace id,
never off the ambient context. Prism's tool loop is recursive, and ambient
context does not survive it.
Content is off by default
Prompts, completions and tool arguments are user content, and a span export
leaves the application. They are recorded only with capture_content=True.
- Captured content is cut at
max_content_lengthcharacters (65,536 by default) and marked…[truncated]. - Even with capture on, media bytes (images, audio, video, documents) are
replaced by their size unless you also pass
capture_media=True.without_media_bytes()is the function that does it. - The model, provider, token counts and rate limits are not content and are always recorded.
record_exceptionsis on by default and puts the exception's message on the root span. Turn it off if your errors can carry user content.
Rate limits
Pass the provider's quota buckets as RateLimit(name, limit, remaining, resets_at) to on_generation_completed or on the error given to
on_generation_failed. They are written as prism.rate_limit.<name>.*
attributes, on success as well as on failure.
Parity
prism-parity's opentelemetry-media-content corpus pins the media-byte rule,
and all three languages agree on it.
Its opentelemetry-span-attributes corpus does not agree yet. Rate-limit
attributes are identical in PHP, TypeScript and Python. These still differ:
- the operation name and span name, which the PHP reference maps onto the GenAI vocabulary and the ports pass through;
- the span kind for image and stream operations;
- the status of a successful span, unset in PHP and
okin the ports; gen_ai.response.finish_reasons;- captured content, which Python encodes with spaces after separators and escaped non-ASCII;
- where truncation cuts a long value.
Spans from a PHP application and a Python agent in the same trace show those differences.
License
MIT. See LICENSE.
Metadata
Release files for prism-ai-opentelemetry 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| prism_ai_opentelemetry-0.3.1.tar.gz | 17.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prism_ai_opentelemetry-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.0 kB
Release files / prism_ai_opentelemetry-0.3.1.tar.gz
| Download URL | prism_ai_opentelemetry-0.3.1.tar.gz |
|---|---|
| Size | 17.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
594fb52312a463fc74e942a5e24f0477f0bd35ef8c21c6f1482b360eb991b0b9
|
|
BLAKE2b-256 checksum How to use checksums |
15c2fed89b83953819af337eba6258b24e0155c74c61d4497109db4ea8c6f883
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency logRelease files / prism_ai_opentelemetry-0.3.1-py3-none-any.whl
| Download URL | prism_ai_opentelemetry-0.3.1-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fc8bf030e3d6bd46f1c086bb22484c7936d7f1f7f6306f51d86a1d1c9006b944
|
|
BLAKE2b-256 checksum How to use checksums |
ad03b3565c0b54e6410ddaad84f339cc1a8e4abf29c60df50e35e7b7ac2a1c4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency log