Skip to main content

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

main.py
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:

main.py
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:

main.py
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:

main.py
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:

main.py
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:

  1. Find a trace by robot ID or operation name
  2. See all log entries in chronological order within that trace
  3. 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 than fields={"soc": 78.5}
  • Log at decision points — not inside tight loops
  • Always use log_exception for caught exceptions — it captures the full traceback
  • Keep log messages concise — the structured fields carry the context

Next steps