Logfire and other OTLP backends
A Pyrula runtime emits OpenTelemetry spans for every turn, model call, tool call and durable
step (Observability). configure() sends them to any backend that
accepts OTLP over HTTP. configure_langfuse, configure_langsmith and configure_datadog are
shortcuts that fill in the endpoint and authentication for those three; for any other backend,
Logfire included, you give configure() the endpoint and headers yourself.
There is no Logfire shortcut. Take the OTLP endpoint and the write token from Logfire’s own documentation; this page does not carry them, and none of its snippets has been sent to Logfire.
Install the extra: pip install "pyrula[agents,otel]". Call configure() once, before the worker
starts.
An OTLP backend by endpoint and header
Section titled “An OTLP backend by endpoint and header”from pyrula.agents.observability import configure
configure( service_name="invoice-agent", endpoint="https://otlp.example.com", # the OTLP/HTTP base URL; /v1/traces is appended headers={"Authorization": "write-token-from-your-backend"}, metrics=False, # leave True if the backend also takes metrics capture_content=False, # True records prompts and completions on spans)The same through the standard variables, with no arguments in code:
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.example.comexport OTEL_EXPORTER_OTLP_HEADERS="authorization=write-token-from-your-backend"- OTLP over HTTP only. The exporter is the
http/protobufone. A backend that offers only gRPC cannot be reached this way; put an OpenTelemetry Collector between them. - Content is off unless you turn it on. Prompts, completions and tool arguments reach the
backend only with
capture_content=TrueorOTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT. What is captured is secret-redacted and cut at 32 KB first (Prompt and completion content). - Metrics are on by default (
gen_ai.client.token.usage,gen_ai.client.operation.duration). Passmetrics=Falsefor a backend that ingests traces only.
When the app already sets up OpenTelemetry
Section titled “When the app already sets up OpenTelemetry”If your application registers a tracer provider before Pyrula starts, do not call configure():
Pyrula’s spans go through the global provider and arrive wherever it exports
(Setup). Logfire’s SDK is built on OpenTelemetry; if
logfire.configure() registers the global provider in your version (confirm in its documentation),
an app that uses Logfire makes that call and none from Pyrula.
import logfire
logfire.configure() # Logfire's own setup; Pyrula's spans use the provider it registers# no pyrula.agents.observability.configure() callWhich of the two you want depends on who owns the provider. A Pyrula worker started with
configure() owns it; an app that already has one keeps it.
Next to the shortcuts
Section titled “Next to the shortcuts”| Backend | Call |
|---|---|
| Langfuse | configure_langfuse() reads LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_HOST; content on, metrics off |
| LangSmith | configure_langsmith() reads LANGSMITH_API_KEY and LANGSMITH_PROJECT |
| Datadog | configure_datadog() exports to the local Agent’s OTLP intake |
| Logfire or any other OTLP/HTTP backend | configure(endpoint=..., headers=...) or the OTEL variables |
| Your own spans on the console | configure(console=True) |
Not Pyrula Cloud
Section titled “Not Pyrula Cloud”Pointing this exporter at Pyrula Cloud’s intake is possible and is usually wrong for a Pyrula runtime: the runtime already reports its runs to Cloud through its connector, and importing the same work as traces would count each run twice. Traces carrying a Pyrula run id are skipped for that reason. The Cloud intake is for apps that have OpenTelemetry and no Pyrula runtime; see Observe-only frameworks.