Tracing with Logfire
Tracing in NeMo Guardrails records each turn as OpenTelemetry spans: the rails that ran, the actions and the model calls, with timings; Pydantic Logfire is one place to send and view them.
Last updated: 30 Sep, 2026 · NeMo Guardrails 0.24.1
The video's demo app logs every guardrail call to Logfire: the message received, the rails applied and the response sent. It calls this observability. explain() shows one turn in your terminal; tracing keeps every turn, for everyone, in a dashboard.
In the clip, a Logfire key is pasted into the app, a query is fired, and the interaction appears on the live dashboard. One log line is a span, a whole request is a trace, and the view of spans in time order is the waterfall. The clip also shows a trace from an older project where a request was blocked by the guard.
Installing Logfire
pip install "logfire==5.1.1"A Logfire tokenOptional
Only needed to send traces to the dashboard. Sign in at logfire.pydantic.dev with GitHub or Google, create a project, and create a write token for it; the free plan covers a course's traffic. The video adds that the free plan allows two projects, and that the universal key at the bottom of the API keys page worked when the project key did not.
LOGFIRE_TOKEN=pylf_...Syntax:
tracing:
enabled: true
adapters:
- name: OpenTelemetry # NeMo emits OpenTelemetry spansTurning tracing on
tracing:
enabled: true
adapters:
- name: OpenTelemetryPointing OpenTelemetry at Logfire
logfire.configure() sets up OpenTelemetry for the process, so NeMo's spans go wherever Logfire sends them. With send_to_logfire=False they are printed in the terminal and no token is needed. With a token in LOGFIRE_TOKEN, leave the argument out and they go to your dashboard.
import logfire
logfire.configure(send_to_logfire=False, service_name="NeMo Guardrails Demo")View the code here
models:
- type: main
engine: openai
model: openai/gpt-oss-120b
api_key_env_var: GROQ_API_KEY
parameters:
base_url: https://api.groq.com/openai/v1
temperature: 0
instructions:
- type: general
content: |
You are an Enterprise IT Assistant specialising in Kubernetes,
Intel hardware, and enterprise networking.
Only answer questions about these topics.
Answer in one or two short sentences.
tracing:
enabled: true
adapters:
- name: OpenTelemetry
One traced turn
import logfire
from nemoguardrails import LLMRails, RailsConfig
logfire.configure(send_to_logfire=False, service_name="NeMo Guardrails Demo")
rails = LLMRails(RailsConfig.from_path("."))
result = rails.generate(messages=[{"role": "user", "content": "What is a VLAN?"}])
print(result.response[0]["content"])00:45:54.475 guardrails.request 00:45:54.475 guardrails.rail 00:45:54.475 guardrails.action 00:45:54.476 general openai/gpt-oss-120b A VLAN (Virtual Local Area Network) logically segments a physical network into separate broadcast domains, allowing devices to be grouped together regardless of their physical location. This improves security, reduces broadcast traffic, and simplifies network management.
With tracing on, generate returns a GenerationResponse, as it does with options, so the reply is read from result.response.
What the spans show
- One line per span, with its start time:
guardrails.requestfor the whole turn,guardrails.railandguardrails.actionfor the step that ran, and a span named after the task and the model,general openai/gpt-oss-120b, for the model call. - The same spans go to the dashboard with a token, where they draw the waterfall from the clip.
The video's logging vs NeMo's tracing
The video's app calls logfire.span and logfire.info itself around each call, with names such as response_sent. This page turns on NeMo's own tracing instead, so the spans come from inside the runtime and name each rail and model call, with no logging code in the app.
| explain() | Tracing to Logfire | |
|---|---|---|
| Keeps | The last turn | Every turn |
| Where | Your terminal | A dashboard |
| Needs | Nothing | The logfire package, a token for the dashboard |
Where you trace
- Any guarded assistant with real users: which rail fires most, and how long each check takes.
- Debugging a refusal a user reported, from its trace.
Related
- Previous: Generation options
- Next: Groq or Gemini
- Reference: OpenTelemetry integration
- See also: Logfire documentation
- Set
LOGFIRE_TOKEN, removesend_to_logfire=False, and find the trace on your dashboard. - Send a message the input rail refuses and compare its spans with an answered one.
Little by little, you're building something great.