Unit 10 · lesson
WPILib Data Logs: Leave a Record You Can Inspect Later
A print statement disappears as soon as the terminal scrolls away unless something else captures it. Robot debugging often needs a record that survives long enough to compare values, events, and timing after a run.
WPILib provides data logging tools for that job.
The stable WPILib documentation describes DataLogManager as a centralized manager for robot data logs. The log contains timestamped records and can store text messages as well as typed numeric or boolean entries.
This lesson does not require a physical robot. You are learning what a good runtime record should contain and how WPILib represents it.
Start the managed data log
In a WPILib Java robot project, logging can be started with:
import edu.wpi.first.wpilibj.DataLogManager;
DataLogManager.start();
A real robot project would normally place that startup call in an appropriate initialization location such as the robot constructor or initialization path.
Starting the log does not mean every value in your program is automatically meaningful. It gives the application a place to record telemetry and messages.
Log a text event
DataLogManager provides a convenience method for text messages:
DataLogManager.log(
"range update rejected id=range-front value=3.70 m"
);
WPILib records these text messages in its managed data log and also prints them to standard output.
This is already stronger than:
System.out.println("error");
because the message itself carries component and value context.
A better event record might include the rule too:
DataLogManager.log(
"range update rejected"
+ " id=range-front"
+ " value=3.70 m"
+ " allowed=0.10..2.00 m"
);
Now another person can read the event without searching the source code just to discover what 3.70 means.
Logs should answer useful questions
For a failure event, aim to preserve enough information to answer:
- what happened;
- which component was involved;
- which value triggered the event;
- which unit the value uses;
- which rule was violated;
- when the record occurred or where it belongs in the event sequence.
The logging framework can provide timing information. Your message still needs domain context.
A timestamp attached to the word error is not enough.
Record numeric telemetry as data, not only prose
Text messages are useful for discrete events. Repeated measurements are often easier to analyze when stored as typed numeric entries.
WPILib provides log-entry classes such as DoubleLogEntry.
A simplified Java setup looks like:
import edu.wpi.first.util.datalog.DataLog;
import edu.wpi.first.util.datalog.DoubleLogEntry;
import edu.wpi.first.wpilibj.DataLogManager;
DataLogManager.start();
DataLog log = DataLogManager.getLog();
DoubleLogEntry frontRangeLog =
new DoubleLogEntry(
log,
"/sensors/front/rangeMeters"
);
Then a value can be appended:
frontRangeLog.append(0.42);
and later:
frontRangeLog.append(0.38);
The entry name itself carries structure:
/sensors/front/rangeMeters
A reader can tell that the values belong to a front sensor range expressed in meters.
Compare that with:
/value
The second name forces the reader to guess.
Data records and event records solve different problems
Suppose the sensor receives:
0.42 m
0.38 m
3.70 m
0.35 m
You may want a numeric record of accepted readings and a text event for the rejection.
For example:
try {
sensor.updateRange(value);
frontRangeLog.append(value);
} catch (IllegalArgumentException error) {
DataLogManager.log(
"range update rejected"
+ " id=" + sensor.getId()
+ " value=" + value + " m"
+ " reason=" + error.getMessage()
);
}
Now the data log can preserve two different kinds of evidence:
- typed range values that were accepted;
- an event message explaining why one request was rejected.
Do not quietly write the invalid 3.70 into the accepted-range series unless your logging design explicitly uses a separate raw-input entry.
If preserving raw input matters, create a clearly named raw-data entry rather than mixing raw and accepted values into one ambiguous stream.
Raw input and accepted state are not the same thing
A stronger logging design may contain both:
/sensors/front/rawRangeMeters
/sensors/front/acceptedRangeMeters
Then an invalid input can still be preserved without pretending the component accepted it.
Conceptually:
rawRangeLog.append(value);
try {
sensor.updateRange(value);
acceptedRangeLog.append(
sensor.getRangeMeters()
);
} catch (IllegalArgumentException error) {
DataLogManager.log(...);
}
For the input 3.70:
- the raw stream can preserve
3.70; - the accepted state can remain
0.38or whatever the previous valid value was; - the event record can explain the rejection.
That separation makes later diagnosis much easier.
Timestamps create a chronology
WPILib data logs store timestamped records.
That means an analysis can ask questions such as:
Did the range value change before or after the warning event?
or:
Did several rejected updates occur close together?
Timing can reveal relationships that a single final value cannot.
But timing alone does not prove causation.
If event A appears before event B, you know their recorded order. You do not automatically know that A caused B.
Do not log every value just because you can
Logging has a purpose: make the system inspectable.
A weak strategy records thousands of poorly named values with no plan for how they will be used.
Another weak strategy records almost nothing and leaves every diagnosis dependent on memory.
Choose logs that answer likely engineering questions.
For the range component, useful records might include:
raw range
accepted range
component ID
rejection event
caution threshold
source health state
The exact set depends on the robot architecture.
Low-level append calls are your responsibility
WPILib's data-log entry APIs record appended values. Your code decides when an append is useful.
If this loop executes many times:
frontRangeLog.append(0.42);
then repeated calls can create repeated records even when the value did not change.
Sometimes that sampling history is exactly what you want. Sometimes it is noise.
Logging policy should match the question you expect the data to answer.
Logging a decision can be more useful than logging only the input
Suppose the robot rule is:
stop when range < 0.50 m
Recording only:
range=0.42
forces a later reader to find the threshold elsewhere.
You may also preserve:
cautionDistanceMeters=0.50
stopDecision=true
Now the record can reconstruct the decision inputs and result.
This is particularly useful when configuration values can change.
A log record is not proof of physical behavior
If the log contains:
stopDecision=true
you can claim that the software recorded a stop decision.
You cannot automatically claim:
motor voltage became zero
wheels stopped rotating
robot stopped moving
Those are different observations.
A useful diagnostic chain may eventually include controller output, encoder response, Driver Station information, or physical measurement.
The log should make the next question easier, not pretend the question has already been answered.
Worked logging design
For one front range source, define these records:
/sensors/front/rawRangeMeters
/sensors/front/acceptedRangeMeters
/guard/cautionDistanceMeters
/guard/stopDecision
messages: rejection events
For input 0.42 m with threshold 0.50 m:
rawRangeMeters 0.42
acceptedRangeMeters 0.42
cautionDistance 0.50
stopDecision true
For the next input 3.70 m:
rawRangeMeters 3.70
acceptedRangeMeters remains at previous valid state
message range update rejected id=range-front value=3.70 m ...
That record preserves both the failure and the last accepted state.
Your turn
Design a logging plan for a battery monitor with:
battery percent
warning threshold
needsCharge decision
invalid percentage rejection
Create names for at least four log entries or event fields.
Then answer:
Which value would you preserve as raw input, which value represents accepted component state, and what text context should appear when an invalid percentage such as
140.0is rejected?
In the next lesson, you will use logs and exceptions to separate three jobs that are often confused: detecting a failure, diagnosing its cause, and deciding how the system should recover.