fix: actually bound the Zomboid log archive, which logrotate could not
The logrotate config added with the Sophie overhaul claimed to bound PZ's own logs. It did not. data/Logs had reached 18 GB across 112 entries and 146k files, and rotation had never once fired there. Two reasons, both wrong assumptions on my part. PZ rolls its logs into dated directories -- logs_2025-12-14/ through logs_2026-08-26/, up to 279 MB each -- so the Logs/*.txt glob only ever matched a handful of loose files at the top. And it rotates by size: not one file in that tree exceeds 100M, because the growth is in the number of files, not the size of any of them. Age-based pruning is the right tool, so this adds a daily zomboid-log-prune timer keeping 14 days and deleting the emptied directories behind it. It runs under podman unshare, since the files belong to the container's UID. logrotate keeps server-console.txt, which is a single ever-growing file and genuinely is what it is good at. Narrowed its scope to say so rather than implying coverage it never had. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a0421226a2
commit
91d9f6b419
@@ -83,6 +83,13 @@ zomboid_mods_excluded:
|
||||
mod_id: IconsInventory
|
||||
reason: Sophie recommends removing Icon Inventory
|
||||
|
||||
# How long to keep PZ's own log archive under data/Logs.
|
||||
#
|
||||
# PZ rolls logs into dated directories and never prunes them; logrotate cannot
|
||||
# bound that, because the growth is in the number of files rather than the size
|
||||
# of any one of them. See containers/home/zomboid.yml.
|
||||
zomboid_log_retention_days: 14
|
||||
|
||||
# Mod IDs the Sophie preset's `Mods=` line gets wrong for a 42.20.3 server.
|
||||
#
|
||||
# Every workshop item below is in the preset's own WorkshopItems= list and
|
||||
|
||||
@@ -174,6 +174,38 @@
|
||||
notify: restorecon podman
|
||||
tags: zomboid-conf
|
||||
|
||||
- name: deploy zomboid log prune script
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: zomboid/zomboid-log-prune.sh.j2
|
||||
dest: "{{ podman_home }}/bin/zomboid-log-prune.sh"
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_user }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: deploy zomboid log prune units
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: "zomboid/zomboid-log-prune.{{ item }}.j2"
|
||||
dest: "{{ podman_home }}/.config/systemd/user/zomboid-log-prune.{{ item }}"
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_user }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- service
|
||||
- timer
|
||||
notify: reload zomboid systemd
|
||||
|
||||
- name: enable zomboid log prune timer
|
||||
become: true
|
||||
become_user: "{{ podman_user }}"
|
||||
ansible.builtin.systemd:
|
||||
name: zomboid-log-prune.timer
|
||||
scope: user
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
|
||||
# The server's own logs, not the container's. PZ holds these fds open for the
|
||||
# life of the process, so copytruncate is mandatory -- a rename would leave it
|
||||
# writing into an unlinked inode and the file would appear to stop growing.
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
- import_tasks: containers/home/gregtime.yml
|
||||
vars:
|
||||
image: localhost/greg-time-bot:3.14.1
|
||||
image: localhost/greg-time-bot:3.15.0
|
||||
tags: gregtime
|
||||
|
||||
# Gated on zomboid_enabled (roles/podman/defaults/main.yml) so it can be taken
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
# {{ ansible_managed }}
|
||||
#
|
||||
# Project Zomboid's own log files. These are separate from the container's
|
||||
# stdout, which podman rotates itself via the k8s-file driver's max_size.
|
||||
# Project Zomboid's server console, which is a single ever-growing file. This is
|
||||
# separate from the container's stdout, which podman rotates itself via the
|
||||
# k8s-file driver's max_size.
|
||||
#
|
||||
# Scope is deliberately just this file. PZ's other logs live in dated
|
||||
# directories under Logs/ that grow in file *count*, not file size, so nothing
|
||||
# there ever crosses a rotation threshold -- those are pruned by age instead,
|
||||
# via zomboid-log-prune.timer.
|
||||
#
|
||||
# copytruncate is mandatory here: the server holds these fds open for the whole
|
||||
# life of the process, so a rename would leave it writing into an unlinked
|
||||
@@ -10,7 +16,6 @@
|
||||
# The Discord bot tails server-console.txt from a byte offset and resets that
|
||||
# offset when the file shrinks, so a truncate under it is safe.
|
||||
{{ zomboid_path }}/data/server-console.txt
|
||||
{{ zomboid_path }}/data/Logs/*.txt
|
||||
{
|
||||
# size, not a time directive: logrotate's daily timer is when this is
|
||||
# *checked*, 100M is when it actually rotates. Specifying both makes
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[Unit]
|
||||
Description=Prune Zomboid log archive older than {{ zomboid_log_retention_days }} days
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart={{ podman_home }}/bin/zomboid-log-prune.sh
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Prune Project Zomboid's own log archive.
|
||||
#
|
||||
# PZ rolls its logs into dated directories under Logs/ (logs_YYYY-MM-DD/, plus
|
||||
# loose YYYY-MM-DD_HH-MM_*.txt at the top) and never removes them. That is not
|
||||
# something logrotate can bound: it rotates by size, and no individual file here
|
||||
# ever reaches a sensible threshold -- the growth is in the *number* of files.
|
||||
# 112 directories and 146k files had accumulated to 18 GB before this existed.
|
||||
#
|
||||
# Files are owned by the container's UID, so this runs under podman unshare.
|
||||
set -euo pipefail
|
||||
|
||||
LOGS="{{ zomboid_path }}/data/Logs"
|
||||
DAYS={{ zomboid_log_retention_days }}
|
||||
|
||||
[[ -d "$LOGS" ]] || exit 0
|
||||
|
||||
before=$(podman unshare du -sh "$LOGS" 2>/dev/null | cut -f1)
|
||||
podman unshare find "$LOGS" -type f -mtime +"$DAYS" -delete 2>/dev/null || true
|
||||
# Second pass: the dated directories are empty once their files are gone.
|
||||
podman unshare find "$LOGS" -mindepth 1 -type d -empty -delete 2>/dev/null || true
|
||||
after=$(podman unshare du -sh "$LOGS" 2>/dev/null | cut -f1)
|
||||
|
||||
echo "zomboid log prune: keeping ${DAYS}d, ${before} -> ${after}"
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Prune the Zomboid log archive daily
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
Persistent=true
|
||||
RandomizedDelaySec=30m
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Reference in New Issue
Block a user