Logs
Bot Pulse provides structured logging that automatically correlates with your traces. Every log entry within a trace gets linked to the active span, so you can jump from a log message straight to the full trace.
Basic logging
import botpulse
pulse = botpulse.init(
service_name="navigation-node",
robot_id="robot-01",
)
with pulse.trace("navigate_to_waypoint") as span:
pulse.log("Starting navigation")
# ... do work ...
pulse.log("Waypoint reached")
Log levels
Use standard log levels to indicate severity:
import botpulse
pulse = botpulse.init(service_name="motor-driver", robot_id="robot-01")
with pulse.trace("set_motor_speed") as span:
pulse.log("Received speed command", level="info")
pulse.log("Motor temperature is high", level="warning")
pulse.log("Motor stalled", level="error")
pulse.log("Debugging motor state", level="debug")
Available levels: debug, info, warning, error, critical.
Structured data
Attach structured fields to log entries for searchable context:
import botpulse
pulse = botpulse.init(service_name="battery-monitor", robot_id="robot-01")
with pulse.trace("check_battery") as span:
pulse.log(
"Battery status update",
level="info",
fields={
"voltage": 22.4,
"current": 3.2,
"temperature": 35.1,
"soc_percent": 78.5,
},
)
These fields appear in your log viewer and can be filtered and searched.
Logging outside of traces
You can emit logs without an active trace:
import botpulse
pulse = botpulse.init(service_name="system-watchdog", robot_id="robot-01")
# No trace active — log is sent independently
pulse.log("System startup complete", level="info")
pulse.log("Connected to fleet manager", level="info")
Logging exceptions
Use pulse.log_exception() to capture full tracebacks:
import botpulse
pulse = botpulse.init(service_name="navigation-node", robot_id="robot-01")
with pulse.trace("navigate_to_waypoint") as span:
try:
path = plan_path(start, goal)
except PathPlanningError as e:
pulse.log_exception(e, message="Path planning failed")
span.set_status("error", "Path planning failed")
Correlating logs with traces
When a log is emitted inside a trace() or child_span() block, it is automatically linked to the current span. In the dashboard you can:
- Find a trace by robot ID or operation name
- See all log entries in chronological order within that trace
- Click a log entry to jump to the exact span where it was emitted
This makes it easy to answer questions like "What happened on robot-07 during navigation at 14:32?"
Best practices
- Use structured fields over string formatting —
"Battery at {soc}%"is harder to search thanfields={"soc": 78.5} - Log at decision points — not inside tight loops
- Always use
log_exceptionfor caught exceptions — it captures the full traceback - Keep log messages concise — the structured fields carry the context
Next steps
- Metrics — Emit numeric measurements
- ROS2 Integration — Use Bot Pulse with ROS2 nodes