Persistent USB log mirror for GL.iNet/OpenWrt routers that keeps default logging behavior unchanged while writing a copy to USB.
OpenWrt keeps system logs in memory by default. That is fast and normal, but logs are lost after reboot.
This project mirrors logs to USB so they survive reboots while preserving normal logread behavior.
- ✅ Does not replace
logddestination. - ✅ Keeps normal
logreadbehavior. - ✅ Adds a second persistent copy on USB.
- ✅ Waits/retries if USB is not mounted yet.
- ✅ Includes size-based rotation.
sh -c "$(curl -fsSL https://raw.githubusercontent.com/zippyy/GL.iNet-ExternalUSB-Logs/main/install.sh)"/usr/bin/usb-log-mirror.sh/etc/init.d/usb-log-mirror/etc/usb-log-mirror.conf- Default log output:
<detected_mount>/gl-usb-logs/system.log(for example/mnt/sda1/gl-usb-logs/system.log)
USB_MOUNT="/mnt/sda1"
AUTO_DETECT_STORAGE="1"
PREFERRED_MOUNTS="/mnt/sda1 /mnt/sdb1 /mnt/mmcblk0p1 /mnt/mmcblk1p1"
FALLBACK_LOCAL_DIR="/logs-backup"
LOG_SUBDIR="gl-usb-logs"
LOG_NAME="system.log"
MAX_SIZE_KB="5120"
MAX_FILES="5"
RETRY_SECONDS="10"
CHECK_EVERY_LINES="50"curl -fsSL https://raw.githubusercontent.com/zippyy/GL.iNet-ExternalUSB-Logs/main/usb-log-mirror.sh -o /usr/bin/usb-log-mirror.sh
curl -fsSL https://raw.githubusercontent.com/zippyy/GL.iNet-ExternalUSB-Logs/main/usb-log-mirror.init -o /etc/init.d/usb-log-mirror
curl -fsSL https://raw.githubusercontent.com/zippyy/GL.iNet-ExternalUSB-Logs/main/usb-log-mirror.conf -o /etc/usb-log-mirror.conf
chmod +x /usr/bin/usb-log-mirror.sh /etc/init.d/usb-log-mirror
chmod 0644 /etc/usb-log-mirror.conf
/etc/init.d/usb-log-mirror enable
/etc/init.d/usb-log-mirror restart# service status
/etc/init.d/usb-log-mirror status
# normal OpenWrt logs still work
logread | tail -n 20
# One liner to check path:
/usr/bin/usb-log-mirror.sh check
# check selected target:
# - "ok: <mount>" means USB/SD storage is active
# - "ok-local: /logs-backup" means local fallback is active
CHECK_OUT="$(/usr/bin/usb-log-mirror.sh check)"
printf '%s\n' "$CHECK_OUT"
if printf '%s\n' "$CHECK_OUT" | grep -q '^ok: '; then
MOUNT="$(printf '%s\n' "$CHECK_OUT" | sed -n 's/^ok: //p')"
TARGET="$MOUNT"
elif printf '%s\n' "$CHECK_OUT" | grep -q '^ok-local: '; then
TARGET="$(printf '%s\n' "$CHECK_OUT" | sed -n 's/^ok-local: //p')"
else
echo "usb-log-mirror target is not ready"
exit 1
fi
# check mirror output on active target
ls -lah "$TARGET/gl-usb-logs/"
tail -n 20 "$TARGET/gl-usb-logs/system.log"
# generate a test log line and confirm it lands in mirror
logger -t usb-log-mirror-test "USB mirror verification $(date -Iseconds)"
sleep 2
grep -n "usb-log-mirror-test" "$TARGET/gl-usb-logs/system.log" | tail -n 1sh -c "$(curl -fsSL https://raw.githubusercontent.com/zippyy/GL.iNet-ExternalUSB-Logs/main/uninstall.sh)"/etc/init.d/usb-log-mirror stop
/etc/init.d/usb-log-mirror disable
rm -f /etc/init.d/usb-log-mirror /usr/bin/usb-log-mirror.sh
# optional: rm -f /etc/usb-log-mirror.conf