I was looking for a way to remove a specific message from the systemd journal. This didn't seem like an uncommon scenario (e.g. accidentally running a wrong command or having lots of spam).
It appears to be infeasible to redact specific entries by modifying an existing file, because the systemd Journal format is primarily designed to support appending, which involves optional compression, hashing, updating counters, indexing references to offsets and hashes. I tried this at first, but would not recommend anyone to do this.
To remove specific entries, I found that the next best thing is to generate a new log file based on the existing log file (e.g. the Python script from the other answer does this). Systemd actually ships the necessary tools to easily modify log entries using this principle.
Short version
In essence, export the journal to a text format, and then convert it back to a journal:
journalctl --file=system.journal -o export | /lib/systemd/systemd-journal-remote --output=result.journal
This mechanism can easily be extended by piping the initial output to a program/script (such as awk, sed, etc.) to do automatic filtering before piping it to systemd-journal-remote
.
A more manual approach is to write the text to a file, modify the file by hand with a text editor and then converting it back to a .journal
file. This is explained in more detail below.
Long version
Here is the longer version, a step-by-step guide to modify an existing journal (tested on ArchLinux, using an Ubuntu live USB, systemd 246).
First, ensure that the journal has been closed. For example by shutting down your computer.
Boot a different device (via a bootable live USB for example). This is to be able to make changes without inadvertently impacting the journal.
To minimize accidental side effects, mount the original disk as read-only. For example:
$ sudo mount -o ro /dev/sda1 /mnt
another example, if you're using LUKS to encrypt the device:
$ sudo cryptsetup luksOpen /dev/sda1 whateverName
$ sudo mount -o ro /dev/mapper/whateverName /mnt
If your current device doesn't have systemd / journalctl, use a chroot to be able to use the binaries from your read-only disk. The minimum to get this to work is as follows:
$ sudo mount --bind /tmp /mnt/tmp
$ sudo mount --bind /tmp /mnt/var/tmp
$ sudo mount -t proc /proc /mnt/proc
$ sudo chroot /mnt
When you are ready, export the journal.
$ journalctl --file=system.journal -o export > /tmp/export.txt
Edit the export to redact, add, modify or remove entries. You can do this outside the chroot if you want to, e.g. with vi -b /tmp/export.txt
.
Example of the output: https://www.freedesktop.org/wiki/Software/systemd/export/
When you have made the desired modifications, convert it back to a journal using systemd-journal-remote
. This binary is not in bin / $PATH
, so you need to use the absolute path to the program's location:
$ /lib/systemd/systemd-journal-remote --output=/tmp/result.journal /tmp/export.txt
Verify that the journal has the desired output, e.g. by paging through the journal with:
$ journalctl --file=/tmp/result.journal
If you are satisfied, proceed with the next step. Otherwise repeat from step 6.
Exit the chroot (CtrlD or simply exit
) and undo step 4, if needed:
$ sudo umount /mnt/proc
$ sudo umount /mnt/tmp
$ sudo umount /mnt/var/tmp
Now we are about to overwrite the original journal.
If you have mounted the volume as read-only (step 3), remount as writable.
$ sudo mount -o remount,rw /mnt
To avoid unwanted changes in file attributes or ownership, just replace the content instead of copying the file.
# cat /tmp/result.journal > /mnt/var/log/journal/MACHINE_ID_HERE/system.journal
or if you aren't running in a root shell, use sudo tee outfile >/dev/null
, like this:
$ </tmp/result.journal sudo tee /mnt/var/log/journal/MACHINE_ID_HERE/system.journal >/dev/null
Unmount the disk (from step 3 / step 10) if needed.
$ sudo umount /mnt
If you had opened an encrypted volume (at step 3), lock it again:
$ sudo cryptsetup luksClose whateverName