The problem with most CAN logs
A CAN log is easy to create and easy to ruin. The common failure mode is not "we forgot to record." It is "we recorded something but cannot use it."
Bad logs usually miss one of these:
- bitrate
- channel name
- timestamp quality
- CAN FD mode
- DBC version
- vehicle or bench state
- event marker
- exact reproduction steps
- whether the log is raw, filtered, decoded, or replayed
When the log is reviewed later, nobody can tell whether the signal is wrong, the DBC is wrong, the bus segment is wrong, or the capture setup was wrong.
The goal is simple: record CAN traffic in a way that another engineer can replay, decode, and audit.
Start with a capture checklist
Before running candump, write down the capture context.
Project: Battery bench bring-up
Date: 2026-05-22
Interface: can0
Protocol: Classical CAN
Bitrate: 500000
Hardware: USB-CAN adapter name / serial number
DBC: battery_network_v14.dbc
Test state: ignition on, charger connected, pack contactors open
Purpose: check BMS voltage and temperature frames
This looks boring. It saves hours.
If a capture is meant to support a DBC change, also record:
Old DBC: battery_network_v13.dbc
New DBC: battery_network_v14.dbc
Change under review: added PackCurrentRaw, corrected Temperature byte order
That makes compare review meaningful.
Bring up the interface explicitly
For classical CAN:
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
ip -details link show can0
For CAN FD:
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
sudo ip link set can0 up
ip -details link show can0
Do not rely on the interface being "probably already configured." Put the setup command in your test notes or script.
Confirm traffic before logging
Run a short live view:
candump -t a can0
Check for:
- expected IDs
- non-zero payload changes
- no obvious error frames
- expected frame length
- stable timestamp cadence
If you expect ID 0x321 every 10 ms but it never appears, fix that before recording a long log.
Record a raw log
Use candump -l for a basic raw log:
candump -l can0
For timestamp visibility while recording:
candump -t a -l can0
For a focused capture around a known ID:
candump -t a -l can0,321:7FF
For several IDs:
candump -t a -l can0,321:7FF,322:7FF,400:7FF
The filter syntax matters. If you use a broad mask accidentally, your "small capture" may still include a full bus.
Add event markers without corrupting the raw log
The raw candump log should stay machine-readable. Put human event notes in a sidecar text file:
cat > capture-notes.txt <<'EOF'
00:00 start recording
00:15 ignition on
00:42 charger connected
01:10 current request changed from 0 A to 20 A
01:45 warning lamp appeared
02:05 stop recording
EOF
If you need precise event markers, use a separate signal or a controlled CAN frame from your test setup, but do not hand-edit the raw log unless you know every downstream parser can tolerate it.
Replay the log before sending it around
Replay catches bad captures early.
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
canplayer vcan0=can0 -I candump-2026-05-22_190501.log
In another terminal:
candump vcan0
If the replay works, you know the log is not just a pile of bytes. It can drive a decoder or a UI test again.
Decode against the exact DBC version
Install cantools:
python3 -m pip install cantools
Decode:
cat candump-2026-05-22_190501.log | python3 -m cantools decode battery_network_v14.dbc
If you are reviewing a DBC change, decode with both versions:
cat capture.log | python3 -m cantools decode battery_network_v13.dbc > decoded-v13.txt
cat capture.log | python3 -m cantools decode battery_network_v14.dbc > decoded-v14.txt
diff -u decoded-v13.txt decoded-v14.txt | less
That tells you whether the DBC change actually changes the interpreted engineering values.
Use Python when you need repeatable checks
For quick QA, write a tiny script that checks for expected message presence and signal ranges.
import cantools
import re
from pathlib import Path
db = cantools.database.load_file("battery_network_v14.dbc")
line_re = re.compile(r"\((?P<ts>[\d.]+)\)\s+\w+\s+(?P<id>[0-9A-Fa-f]+)#(?P<data>[0-9A-Fa-f]*)")
seen = set()
violations = []
for line in Path("capture.log").read_text().splitlines():
match = line_re.match(line)
if not match:
continue
frame_id = int(match.group("id"), 16)
data = bytes.fromhex(match.group("data"))
try:
message = db.get_message_by_frame_id(frame_id)
decoded = message.decode(data)
except KeyError:
continue
seen.add(message.name)
for signal_name, value in decoded.items():
signal = next((s for s in message.signals if s.name == signal_name), None)
if signal and isinstance(value, (int, float)):
if signal.minimum is not None and value < signal.minimum:
violations.append((message.name, signal_name, value, "below minimum"))
if signal.maximum is not None and value > signal.maximum:
violations.append((message.name, signal_name, value, "above maximum"))
print("Decoded messages:", sorted(seen))
print("Range violations:", violations)
This does not replace engineering judgment. It catches obvious drift before a review meeting.
Keep the capture package together
For a useful handoff, package:
capture.log
capture-notes.txt
vehicle_network.dbc
README.txt
The README should include:
Interface: can0
Bitrate: 500000
Protocol: Classical CAN
Adapter: USB-CAN serial 12345
DBC SHA or version: battery_network_v14.dbc
Capture command: candump -t a -l can0
Replay command: canplayer vcan0=can0 -I capture.log
If the log will be used for QA, do not send only a screenshot of a plot. Send the raw log and the exact DBC.
Where DBC Utility fits
Once a log shows suspicious values, open the DBC in DBC Utility and inspect:
- message ID and extended-frame status
- signal start bit
- signal length
- byte order
- signedness
- scale and offset
- unit and min/max
- multiplexer selector and muxed signals
- changes between old and new DBC versions
The command line tells you what happened on the bus. A DBC editor tells you whether the database explains it correctly.