NeMo Guardrailsnemoguardrails 0.24.1 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
37 small wins to finish your pathNext lesson →

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.

Traces in Logfire · from The Complete AI Security Course In 8 Hours · 68:26 to 71:53

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.

bash
LOGFIRE_TOKEN=pylf_...

Syntax:

yaml
tracing:
  enabled: true
  adapters:
    - name: OpenTelemetry       # NeMo emits OpenTelemetry spans

Turning tracing on

yaml
tracing:
  enabled: true
  adapters:
    - name: OpenTelemetry

Pointing 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.

python
import logfire

logfire.configure(send_to_logfire=False, service_name="NeMo Guardrails Demo")
Project files used on this pageThis lesson builds on a project from earlier lessons. The code below imports this file. Click a file to see its code, or follow the link to the lesson that wrote it. To run the code yourself, keep it in the same folder.
View the code here
config.yml
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

ExampleAPI key
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"])

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.request for the whole turn, guardrails.rail and guardrails.action for 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
KeepsThe last turnEvery turn
WhereYour terminalA dashboard
NeedsNothingThe 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.
Watch out. Traces can hold user messages. The video's app notes that keys are never stored; treat trace content the same way, and read NeMo's content-capture settings before sending real users' messages to any backend.
Try it yourself
  • Set LOGFIRE_TOKEN, remove send_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.