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:
2026-10-13 17:54:05 +03:30
parent f4831e93a7
commit 3559c43902
10 changed files with 180 additions and 7 deletions

View File

@@ -1060,13 +1060,28 @@ OFFSITE_WAL_SLOT = os.environ.get('OFFSITE_WAL_SLOT', '')
# بیش از این عقب‌ماندن هشدار است. ۶۴ مگ ≈ چهار فایلِ WAL؛ در ترافیکِ عادی عقب‌ماندگی نزدیکِ صفر است.
OFFSITE_WAL_MAX_LAG_BYTES = 64 * 2**20
# چرخشِ فایلِ لاگ: 'size' (پیش‌فرض، Docker و محلی) = ۶ فایلِ ۱۰ مگی و قدیمی‌ها پاک می‌شوند؛
# 'external' (سرور) = برنامه هرگز پاک نمی‌کند، `ops/applogs/archive-app-log.sh` هر شب app.log را جابه‌جا و
# فشرده می‌کند و ۲۴۷ آن را برای همیشه نگه می‌دارد. WatchedFileHandler پس از جابه‌جایی فایلِ تازه باز می‌کند،
# که با ۴ پروسه‌ی gunicorn امن‌تر از چرخشِ داخلیِ RotatingFileHandler است (آن هر پروسه جدا می‌چرخاند).
LOG_FILE_ROTATION = os.environ.get('LOG_FILE_ROTATION', 'size')
if LOG_FILE_ROTATION not in ('size', 'external'):
raise ImproperlyConfigured(f"LOG_FILE_ROTATION باید 'size' یا 'external' باشد، نه {LOG_FILE_ROTATION!r}")
if LOG_DIR:
os.makedirs(LOG_DIR, exist_ok=True)
LOGGING['handlers']['file'] = {
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOG_DIR, 'app.log'),
'maxBytes': 10 * 1024 * 1024, # 10MB در هر فایل، قبل از rotate
'backupCount': 5,
'formatter': 'json',
}
if LOG_FILE_ROTATION == 'external':
LOGGING['handlers']['file'] = {
'class': 'logging.handlers.WatchedFileHandler',
'filename': os.path.join(LOG_DIR, 'app.log'),
'formatter': 'json',
}
else:
LOGGING['handlers']['file'] = {
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOG_DIR, 'app.log'),
'maxBytes': 10 * 1024 * 1024, # 10MB در هر فایل، قبل از rotate
'backupCount': 5,
'formatter': 'json',
}
LOGGING['root']['handlers'].append('file')