ulog
USB serial port logger with automatic session management for Linux.
Features
- Logs serial data from USB devices with syslog-style timestamps
- Multi-device support - single service handles multiple USB devices
- Session tracking - each session gets a unique ID (format:
MMDD-HHMM-xxxx) - USB device identity - tracks vendor:product:serial to detect device swaps
- Export tool - list and export sessions by device, session ID, or USB identity
- Automatic daily log rotation (new folder per day)
- New log file on service restart
- Auto-start on device hotplug
- Config file changes auto-applied (no manual reload needed)
- Security hardened (dedicated user, systemd sandboxing, input validation)
Supported Systems
Linux distributions with systemd:
| Distribution | Package |
|---|---|
| Arch Linux / Manjaro | AUR |
| Debian 11+ / Ubuntu 20.04+ | .deb |
| Fedora / RHEL / CentOS | Manual |
| Other systemd-based | Manual |
Requirements: Linux kernel 4.x+, systemd, bash 4.4+
Not supported: macOS, Windows, BSD, non-systemd Linux (OpenRC, runit, etc.)
Installation
Arch Linux (AUR)
Or manually:
git clone https://github.com/matterizelabs/ulog.git
cd ulog/packaging/arch
makepkg -siDebian/Ubuntu
Download from releases:
sudo dpkg -i ulog_1.1.1_all.deb
Manual (root-only systems)
git clone https://github.com/matterizelabs/ulog.git
cd ulog
./install.shConfiguration
Single Device (Simple)
Edit /etc/ulog.conf:
DEVICE=/dev/ttyUSB0 BAUD=115200 LOG_DIR=/var/log/ulog/ttyUSB0
Multiple Devices
Create a config file per device in /etc/ulog.d/:
# /etc/ulog.d/sensor1.conf DEVICE=/dev/ttyUSB0 BAUD=115200 # /etc/ulog.d/sensor2.conf DEVICE=/dev/ttyUSB1 BAUD=9600 # /etc/ulog.d/gps.conf DEVICE=/dev/ttyACM0 BAUD=38400
Each device gets its own log directory: /var/log/ulog/<device_name>/
Changes are auto-applied when config files are saved.
Usage
Enable and start:
systemctl enable --now ulog.service ulog-rollover.timer ulog-genconfig.pathView logs:
# Single device tail -f /var/log/ulog/ttyUSB0/$(date +%Y-%m-%d)/*.log # All devices tail -f /var/log/ulog/*/$(date +%Y-%m-%d)/*.log
Check status:
systemctl status ulog.service journalctl -u ulog.service -f
Session Management
Each logging session is assigned a unique ID in the format MMDD-HHMM-xxxx (e.g., 0120-1830-a1b2). Sessions are tracked in a session.index file per device with start/end times and USB device identity.
USB Device Identity
ulog tracks the USB vendor ID, product ID, and serial number for each device. This allows:
- Detecting when a different physical device is connected to the same port
- Filtering exports by specific hardware (useful with multiple identical adapters)
Identity format: vendor:product:serial (e.g., 10c4:ea60:0001a2b3)
List Sessions
# List all sessions for a device ulog-export --list --device ttyUSB0 # List sessions from all devices ulog-export --list --all
Output:
SESSION START END IDENTITY FILES
====================================================================================================
0120-1830-a1b2 2026-01-20 18:30:00 2026-01-20 19:45:00 10c4:ea60:0001a2b3 2 file(s)
0120-2000-c3d4 2026-01-20 20:00:00 ongoing 10c4:ea60:0001a2b3 1 file(s)
Export Sessions
# Export specific session ulog-export --session 0120-1830-a1b2 --device ttyUSB0 --output session.log # Export latest/current session ulog-export --device ttyUSB0 --output latest.log # Export multiple sessions combined ulog-export --session 0120-1830-a1b2,0120-2000-c3d4 --device ttyUSB0 --output combined.log
Filter by USB Identity
# Export all sessions from Silicon Labs adapters (vendor 10c4) ulog-export --vendor 10c4 --output silabs.log # Export from specific vendor and product (CP210x) ulog-export --vendor 10c4 --product ea60 --output cp210x.log # Export from specific physical device (by serial, prefix match) ulog-export --vendor 10c4 --product ea60 --serial 0001a2b3 --output device1.log
Add a new device:
cat > /etc/ulog.d/mydevice.conf << EOF DEVICE=/dev/ttyUSB2 BAUD=115200 EOF chown root:ulog /etc/ulog.d/mydevice.conf chmod 0640 /etc/ulog.d/mydevice.conf # Service auto-restarts to pick up new device
Log Format
Logs use syslog-style timestamps:
Jan 18 14:30:00 sensor reading: 42.5
Jan 18 14:30:01 sensor reading: 43.1
Log Directory Structure
/var/log/ulog/
ttyUSB0/
session.index # Session tracking database
2026-01-18/
2026-01-18_14-30-00.log
2026-01-19/
2026-01-19_00-00-01.log
ttyUSB1/
session.index
2026-01-18/
2026-01-18_14-30-00.log
ttyACM0/
...
/var/lib/ulog/
sessions/ # Runtime state
ttyUSB0.session # Current session ID
ttyUSB0.identity # Last known USB identity
Configuration Reference
| Key | Description | Default |
|---|---|---|
DEVICE |
Serial device path | /dev/ttyUSB0 |
BAUD |
Baud rate (300-921600) | 115200 |
LOG_DIR |
Log directory (must be under /var/log/) | /var/log/ulog/<device> |
Valid baud rates: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
Project Structure
ulog/
src/ # Source files
ulog.sh # Main logger script (multi-device)
ulog-export # Session export/list tool
ulog-genconfig # Config generator
ulog.conf # Default configuration
services/ # Systemd units
ulog-genconfig.path # Watch config for changes
ulog-genconfig.service
ulog-rollover.service
ulog-rollover.timer
packaging/ # Distribution packages
arch/ # Arch Linux (AUR)
debian/ # Debian/Ubuntu
Security
- Runs as dedicated
uloguser (not root) - Systemd sandboxing (ProtectSystem, PrivateTmp, NoNewPrivileges)
- Input validation on all config values
- Config files must be root-owned (0640)
- Device paths strictly validated
- See SECURITY.md for details
Dependencies
- socat
- moreutils (provides
ts) - coreutils (provides
realpath)
License
MIT