BB.Diagnostic (bb v0.15.0)
View SourceDiagnostic reporting for monitoring and awareness.
Diagnostics are separate from control errors - they provide observability into system health without affecting control flow. Following the ROS2 model, diagnostics use four levels that indicate component health status.
Diagnostic Levels
:ok- Component operating normally:warn- Unusual condition, but operation continues:error- Component has failed or is degraded:stale- No recent updates from component (timeout/disconnect)
Usage
Publish diagnostics via telemetry:
BB.Diagnostic.publish(
component: [:robot, :arm, :elbow],
level: :warn,
message: "Motor temperature elevated",
values: %{temperature: 65.2, threshold: 70.0}
)Subscribe to diagnostics in your application:
:telemetry.attach(
"my-diagnostic-handler",
[:bb, :diagnostic],
&MyApp.handle_diagnostic/4,
nil
)Integration with bb_liveview
The bb_liveview package provides a diagnostic dashboard that aggregates
and displays diagnostics from all robot components. It subscribes to the
[:bb, :diagnostic] telemetry event automatically.
Separation from Control Errors
Diagnostics are for awareness - they inform operators about system state
but don't halt operations. Control errors (BB.Error.*) are for control
flow - they're returned from functions and affect program execution.
| Concern | Mechanism | Purpose |
|---|---|---|
| Diagnostics | Telemetry events | Monitoring dashboards |
| Control errors | Return values | Program control flow |
A component may publish a :warn diagnostic while continuing to operate,
or publish an :error diagnostic when it has failed. The safety system
(BB.Safety) handles critical failures independently.
Summary
Functions
Convenience function to publish an :error diagnostic.
Creates a new diagnostic struct.
Convenience function to publish an :ok diagnostic.
Publishes a diagnostic event via telemetry.
Convenience function to publish a :stale diagnostic.
Convenience function to publish a :warn diagnostic.
Types
@type level() :: :ok | :warn | :error | :stale
@type t() :: %BB.Diagnostic{ component: [atom()], level: level(), message: String.t(), timestamp: DateTime.t(), values: map() }
Functions
Convenience function to publish an :error diagnostic.
Examples
BB.Diagnostic.error([:my_robot, :sensor], "Sensor disconnected",
values: %{last_reading: ~U[2025-01-15 10:30:00Z]}
)
Creates a new diagnostic struct.
Options
:component(required) - Path to the component, e.g.[:robot, :arm, :elbow]:level(required) - One of:ok,:warn,:error,:stale:message(required) - Human-readable description:values- Map of diagnostic values (default:%{}):timestamp- When the diagnostic was generated (default:DateTime.utc_now/0)
Examples
BB.Diagnostic.new(
component: [:my_robot, :gripper],
level: :ok,
message: "Gripper operating normally"
)
BB.Diagnostic.new(
component: [:my_robot, :arm, :shoulder],
level: :warn,
message: "Motor temperature elevated",
values: %{temperature: 65.2, threshold: 70.0}
)
Convenience function to publish an :ok diagnostic.
Examples
BB.Diagnostic.ok([:my_robot, :arm], "Arm calibrated successfully")
BB.Diagnostic.ok([:my_robot, :gripper], "Gripper ready",
values: %{grip_force: 10.5}
)
Publishes a diagnostic event via telemetry.
This is the primary way to emit diagnostics. The event is published to
[:bb, :diagnostic] with the diagnostic struct as metadata.
Accepts either a BB.Diagnostic struct or keyword options (which are
passed to new/1).
Examples
# With keyword options
BB.Diagnostic.publish(
component: [:my_robot, :battery],
level: :warn,
message: "Battery low",
values: %{percentage: 15, threshold: 20}
)
# With struct
diagnostic = BB.Diagnostic.new(component: [:my_robot], level: :ok, message: "OK")
BB.Diagnostic.publish(diagnostic)
Convenience function to publish a :stale diagnostic.
Used when a component hasn't reported recently, indicating potential disconnect or hang.
Examples
BB.Diagnostic.stale([:my_robot, :camera], "No frames received",
values: %{last_frame: ~U[2025-01-15 10:25:00Z], timeout_ms: 5000}
)
Convenience function to publish a :warn diagnostic.
Examples
BB.Diagnostic.warn([:my_robot, :motor], "Temperature elevated",
values: %{temperature: 65.0, threshold: 70.0}
)