App logs kept forever: nightly gzip on 249 (LOG_FILE_ROTATION=external), hourly pull to 247 via a forced-command key, health warns if the archive stops
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
33
ops/applogs/archive-app-log.sh
Executable file
33
ops/applogs/archive-app-log.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
# روی ۲۴۹، هر شب (zareian-applog-archive.timer). app.log را به logs/archive/ میبرد و فشرده میکند.
|
||||
# برنامه با LOG_FILE_ROTATION=external از WatchedFileHandler استفاده میکند و پس از جابهجایی خودش app.log تازه
|
||||
# میسازد؛ خطی که در همان لحظه نوشته شود در فایلِ جابهجاشده میماند، گم نمیشود.
|
||||
# اینجا فقط ۳۰ روز میماند (دیسکِ ۲۴۹ پر است) و فقط فایلی پاک میشود که ۲۴۷ گرفتنش را تأیید کرده
|
||||
# (`.shipped`)؛ نسخهی همیشگی روی ۲۴۷ است (pull-app-logs.sh). فقط زیرِ ~/mathapp-v2/logs مینویسد.
|
||||
set -euo pipefail
|
||||
LOGS=/home/administrator/mathapp-v2/logs
|
||||
ARCH="$LOGS/archive"
|
||||
mkdir -p "$ARCH"
|
||||
chmod 750 "$ARCH"
|
||||
stamp=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
|
||||
# app.log.1..5 از RotatingFileHandlerِ پیشین (پیش از LOG_FILE_ROTATION=external) هم یک بار بایگانی میشوند.
|
||||
for f in "$LOGS"/app.log.[0-9]*; do
|
||||
[ -e "$f" ] || continue
|
||||
n=${f##*.}
|
||||
mv "$f" "$ARCH/app-$stamp-old$n.log"
|
||||
done
|
||||
if [ -s "$LOGS/app.log" ]; then
|
||||
mv "$LOGS/app.log" "$ARCH/app-$stamp.log"
|
||||
sleep 5 # نوشتنِ در جریانِ workerها روی فایلِ قدیمی تمام شود
|
||||
fi
|
||||
for f in "$ARCH"/app-*.log; do
|
||||
[ -e "$f" ] || continue
|
||||
gzip -9 "$f"
|
||||
chmod 640 "$f.gz"
|
||||
done
|
||||
|
||||
find "$ARCH" -name 'app-*.log.gz' -mtime +30 | while read -r gz; do
|
||||
[ -e "$gz.shipped" ] && rm -f -- "$gz" "$gz.shipped"
|
||||
done
|
||||
echo "archived $(ls "$ARCH"/app-*.log.gz 2>/dev/null | wc -l) files in $ARCH"
|
||||
26
ops/applogs/pull-app-logs.sh
Executable file
26
ops/applogs/pull-app-logs.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
# روی ۲۴۷، هر ساعت (zareian-applog-pull.timer). بایگانیِ فشردهی لاگِ برنامه را از ۲۴۹ میگیرد و
|
||||
# **برای همیشه** در ~/zareian-pgbackup/app-logs/ نگه میدارد (تصمیمِ مالک ۲۰۲۶-۱۰-۱۳؛ برآورد حدودِ ۱ گیگ در سال
|
||||
# با ۶۰۰ کاربرِ فعال). هیچ فایلی اینجا پاک نمیشود. کلید فقط serve-archive.sh را اجرا میکند.
|
||||
set -euo pipefail
|
||||
DEST=/home/administrator/zareian-pgbackup/app-logs
|
||||
mkdir -p "$DEST"
|
||||
r() { ssh -i /home/administrator/.ssh/zareian_applogs -o BatchMode=yes -o ConnectTimeout=20 \
|
||||
administrator@192.168.200.164 "$@"; }
|
||||
|
||||
free_kb=$(df --output=avail -k "$DEST" | tail -1)
|
||||
[ "$free_kb" -gt 3000000 ] || { echo "disk too full ($free_kb KB free); skipping" >&2; exit 1; }
|
||||
|
||||
got=0
|
||||
for name in $(r list); do
|
||||
[[ "$name" =~ ^app-[0-9]{8}T[0-9]{6}Z(-old[0-9]+)?\.log\.gz$ ]] || { echo "skip odd name: $name" >&2; continue; }
|
||||
if [ ! -s "$DEST/$name" ]; then
|
||||
r get "$name" > "$DEST/.$name.part"
|
||||
gzip -t "$DEST/.$name.part"
|
||||
chmod 600 "$DEST/.$name.part"
|
||||
mv "$DEST/.$name.part" "$DEST/$name"
|
||||
got=$((got + 1))
|
||||
fi
|
||||
r ack "$name"
|
||||
done
|
||||
echo "fetched $got new; $(ls "$DEST" | wc -l) files, $(du -sh "$DEST" | cut -f1) in $DEST"
|
||||
17
ops/applogs/serve-archive.sh
Executable file
17
ops/applogs/serve-archive.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# روی ۲۴۹: فرمانِ اجباریِ کلیدِ zareian-applogs (authorized_keys با restrict,command="…این فایل").
|
||||
# آن کلید (روی ۲۴۷) جز این سه کار هیچ کاری نمیتواند: شِل، پورت و فایلِ دیگری ندارد.
|
||||
# list نامِ فایلهای بایگانی
|
||||
# get NAME محتوای یک فایل
|
||||
# ack NAME «۲۴۷ گرفت و سالم بود» → NAME.shipped (پس از ۳۰ روز اینجا پاک شود)
|
||||
set -euo pipefail
|
||||
ARCH=/home/administrator/mathapp-v2/logs/archive
|
||||
read -r cmd name extra <<<"${SSH_ORIGINAL_COMMAND:-}"
|
||||
[ -z "${extra:-}" ] || { echo "bad request" >&2; exit 2; }
|
||||
valid() { [[ "$1" =~ ^app-[0-9]{8}T[0-9]{6}Z(-old[0-9]+)?\.log\.gz$ ]] && [ -f "$ARCH/$1" ]; }
|
||||
case "$cmd" in
|
||||
list) cd "$ARCH" && ls -1 app-*.log.gz 2>/dev/null || true ;;
|
||||
get) valid "${name:-}" || { echo "no such file" >&2; exit 2; }; cat -- "$ARCH/$name" ;;
|
||||
ack) valid "${name:-}" || { echo "no such file" >&2; exit 2; }; touch -- "$ARCH/$name.shipped" ;;
|
||||
*) echo "bad request" >&2; exit 2 ;;
|
||||
esac
|
||||
8
ops/applogs/zareian-applog-archive.service
Normal file
8
ops/applogs/zareian-applog-archive.service
Normal file
@@ -0,0 +1,8 @@
|
||||
# روی ۲۴۹.
|
||||
[Unit]
|
||||
Description=Zareian MathApp: nightly gzip of app.log into logs/archive
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=administrator
|
||||
ExecStart=/home/administrator/mathapp-v2/ops/applogs/archive-app-log.sh
|
||||
10
ops/applogs/zareian-applog-archive.timer
Normal file
10
ops/applogs/zareian-applog-archive.timer
Normal file
@@ -0,0 +1,10 @@
|
||||
# روی ۲۴۹. ساعتِ سرور تهران است.
|
||||
[Unit]
|
||||
Description=Zareian MathApp: nightly app.log archive
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 00:05:00
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
8
ops/applogs/zareian-applog-pull.service
Normal file
8
ops/applogs/zareian-applog-pull.service
Normal file
@@ -0,0 +1,8 @@
|
||||
# روی ۲۴۷.
|
||||
[Unit]
|
||||
Description=Zareian MathApp: fetch archived app logs from 249 (kept forever)
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=administrator
|
||||
ExecStart=/home/administrator/zareian-pgbackup/bin/pull-app-logs.sh
|
||||
11
ops/applogs/zareian-applog-pull.timer
Normal file
11
ops/applogs/zareian-applog-pull.timer
Normal file
@@ -0,0 +1,11 @@
|
||||
# روی ۲۴۷.
|
||||
[Unit]
|
||||
Description=Zareian MathApp: hourly fetch of archived app logs
|
||||
|
||||
[Timer]
|
||||
OnCalendar=hourly
|
||||
RandomizedDelaySec=300
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Reference in New Issue
Block a user