Unit 10 · lesson
WPILib Logs and ROS 2 Logs: Read the Runtime Before You Merge the Story
Robot systems often contain more than one logging system.
A Java/WPILib application can record telemetry and events with WPILib data logs. A ROS 2 node can produce ROS log messages with logger names and severity levels. Both records can help explain a failure, but they are created by different runtimes and should not be merged into one story without evidence connecting them.
This lesson teaches you how to read both kinds of record.
WPILib data logs preserve robot-application telemetry
From the previous lesson, a WPILib Java application can start managed logging with:
DataLogManager.start();
and record a text event with:
DataLogManager.log(
"range update rejected"
+ " id=range-front"
+ " value=3.70 m"
);
It can also append typed numeric values through entries such as DoubleLogEntry.
WPILib data logs are built for robot telemetry. They can preserve timestamped records that are useful after a run.
A WPILib log entry answers questions about what the WPILib application chose to record.
It does not automatically tell you what a ROS 2 node logged.
ROS 2 has its own logging subsystem
ROS 2 Jazzy nodes use the ROS logging infrastructure.
The official ROS 2 logging documentation defines these severity levels, from least to most severe:
DEBUG
INFO
WARN
ERROR
FATAL
A logger processes messages at or above its configured severity threshold.
A ROS node has a logger associated with its node name and namespace. Logging output can be sent to targets including:
- the console;
- log files on disk;
- the
/rosouttopic on the ROS 2 network.
Those destinations are part of the ROS runtime, not WPILib's DataLogManager.
Severity communicates importance, not certainty
A message at ERROR severity is more severe than an INFO message. That does not make the statement inside the message automatically true.
For example:
[ERROR] [motor_guard]: motor response missing
is evidence that a logger produced an error-level message with that text.
You still need to inspect what condition caused the logger to emit it.
Severity helps operators filter and prioritize records. It does not replace technical verification.
What a ROS log message carries
ROS 2 exposes a log message definition through rcl_interfaces/msg/Log.
Important fields include:
- timestamp;
- severity level;
- logger name;
- message text;
- source file;
- source function;
- source line.
That combination can give a much richer record than a bare print statement.
A simplified log record might be presented as:
time=42.140
level=WARN
name=sensor_bridge
msg="range input outside declared interval"
The exact console formatting can vary. The semantic information is what matters.
Source identity matters
Compare these two messages:
range update rejected value=3.70 m
range update rejected value=3.70 m
The text is identical.
If the first came from a WPILib DataLogManager message and the second came from a ROS logger named sensor_bridge, they are still separate observations.
Do not assume one system copied the value from the other unless the architecture and runtime evidence show that data path.
A strong diagnosis records the source of every log line.
Compare the two logging systems
| Question | WPILib data log | ROS 2 log |
|---|---|---|
| Runtime | WPILib robot application | ROS 2 logging subsystem |
| Common Java entry point in this course | DataLogManager / typed log entries | not a WPILib Java API |
| Useful context | timestamp, entry name, typed value or message | timestamp, severity, logger name, message, source context |
| Typical use | robot telemetry and event recording | node/runtime diagnostic messages |
| Network-visible log path | not /rosout | /rosout may carry logs when enabled |
| Proves physical recovery? | no | no |
The systems can coexist in a larger robot architecture. The table prevents vocabulary from turning coexistence into false equivalence.
A log should let you ask the next question
Suppose WPILib records:
12.140 rawRangeMeters=3.70
12.141 message="range update rejected id=range-front"
12.141 sourceHealthy=false
The next question may be:
Where did the raw value come from?
Suppose a ROS log separately records:
12.138 WARN sensor_bridge "input queue delayed"
Now the timing is interesting. The ROS warning occurred shortly before the Java-side rejection.
But timing proximity is not enough to conclude:
The delayed ROS queue caused the Java value
3.70.
You would need evidence connecting the systems and the specific data item.
Logs help form hypotheses. They do not grant causation automatically.
Logger names make multi-node systems easier to inspect
Imagine a ROS system with:
sensor_bridge
motor_guard
navigation
A message from sensor_bridge and a message from motor_guard may refer to the same high-level incident but come from different responsibilities.
For example:
WARN sensor_bridge: range sample rejected
INFO motor_guard: movement inhibited
The logger names help separate observation from response.
A weak report might say:
ROS logged a sensor error and stopped the robot.
A stronger report keeps the records distinct:
sensor_bridgeemitted a warning about a rejected range sample.motor_guardseparately logged that its movement-inhibit state became active.
Physical stopping still requires physical or controller-response evidence.
Log level configuration changes what you can see
ROS loggers can filter messages by severity.
If the logger is configured to show INFO and above, DEBUG messages may not appear.
That means absence of a debug line does not necessarily prove the code path never executed. The message may have been filtered.
This is an important diagnostic lesson:
An observation can be missing because the event did not occur, or because your instrumentation did not record/show it.
Always understand the logging configuration before using absence as evidence.
WPILib logging has instrumentation choices too
A WPILib application only records the values and events its logging design actually captures.
If you never create a log entry for raw range input, the data log cannot later reconstruct the raw input history from nowhere.
A missing record may mean:
- the event did not happen;
- the code never reached the logging call;
- logging was not started;
- the data was never instrumented;
- a different logging source contains the evidence.
Good instrumentation is part of testable system design.
Do not log secrets or unnecessary personal data
Technical logs can become long-lived artifacts. They may be copied, uploaded, or shared during debugging.
Do not put credentials, tokens, passwords, student personal information, or unrelated private data into log messages.
For this course, appropriate context includes component IDs, controlled sensor values, units, thresholds, software states, logger names, and timestamps.
Worked cross-runtime review
You receive these records:
WPILib data log
42.120 /sensors/front/rawRangeMeters 3.70
42.121 messages "range update rejected id=range-front"
42.121 /sensors/front/healthy false
ROS 2 log
42.100 WARN sensor_bridge "range source timeout count=1"
ROS graph inspection
/sensor_bridge
/motor_guard
What can you defend?
You can say the WPILib application recorded a raw 3.70 value, a rejection event, and an unhealthy modeled state. You can say a ROS logger named sensor_bridge produced the supplied warning. You can say two node names were visible in the inspected graph state.
What remains unproven?
You cannot yet prove that the ROS timeout produced the WPILib raw value, that the two applications are directly connected, or that a physical sensor failed.
That is the discipline you will use in the lab.
Your turn
Classify each record by its evidence source:
DataLogManager.log("movement inhibited")
WARN motor_guard "movement inhibited"
ros2 node list -> /motor_guard
wheel encoder measured 0 rpm
For each one, write:
- source/runtime;
- strongest supported claim;
- one stronger claim it does not establish by itself.
In the final lesson, you will combine exception, test, log, and runtime records into an evidence timeline without allowing the timeline to turn correlation into a made-up cause.