Silence Flask access logs and retain PM2 logs for 3 days.
Stop werkzeug request spam into PM2 error files, truncate oversized logs, and install daily logrotate with 3-day retention. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9968,5 +9968,8 @@ _purge_key_monitors_if_full_margin()
|
||||
|
||||
# 启动
|
||||
if __name__ == "__main__":
|
||||
from lib.common.flask_access_log_lib import silence_werkzeug_access_log
|
||||
|
||||
silence_werkzeug_access_log()
|
||||
threading.Thread(target=background_task, daemon=True).start()
|
||||
app.run(host=HOST, port=PORT, debug=DEBUG, threaded=True)
|
||||
|
||||
@@ -9844,5 +9844,8 @@ _purge_key_monitors_if_full_margin()
|
||||
|
||||
# 启动
|
||||
if __name__ == "__main__":
|
||||
from lib.common.flask_access_log_lib import silence_werkzeug_access_log
|
||||
|
||||
silence_werkzeug_access_log()
|
||||
threading.Thread(target=background_task, daemon=True).start()
|
||||
app.run(host=HOST, port=PORT, debug=DEBUG, threaded=True)
|
||||
|
||||
@@ -9564,5 +9564,8 @@ _purge_key_monitors_if_full_margin()
|
||||
|
||||
# 启动
|
||||
if __name__ == "__main__":
|
||||
from lib.common.flask_access_log_lib import silence_werkzeug_access_log
|
||||
|
||||
silence_werkzeug_access_log()
|
||||
threading.Thread(target=background_task, daemon=True).start()
|
||||
app.run(host=HOST, port=PORT, debug=DEBUG, threaded=True)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# PM2 日志策略:关灌屏后的兜底轮转 — 按天保留 3 天,单文件过大也切分.
|
||||
# 用法(root):
|
||||
# bash deploy/pm2_log_policy.sh
|
||||
# bash deploy/pm2_log_policy.sh --clean-only
|
||||
set -euo pipefail
|
||||
|
||||
PM2_LOG_DIR="${PM2_LOG_DIR:-/root/.pm2/logs}"
|
||||
LOGROTATE_CONF="${LOGROTATE_CONF:-/etc/logrotate.d/crypto_monitor_pm2}"
|
||||
RETENTION_DAYS="${RETENTION_DAYS:-3}"
|
||||
MAXSIZE="${MAXSIZE:-20M}"
|
||||
CLEAN_ONLY=0
|
||||
if [[ "${1:-}" == "--clean-only" ]]; then
|
||||
CLEAN_ONLY=1
|
||||
fi
|
||||
|
||||
echo ">>> PM2 log dir: ${PM2_LOG_DIR}"
|
||||
if [[ ! -d "${PM2_LOG_DIR}" ]]; then
|
||||
echo "目录不存在,跳过"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ">>> truncate oversized active logs (>20MB) and drop stale files older than ${RETENTION_DAYS}d"
|
||||
# 当前正在写的大文件用 truncate 清空内容(copytruncate/空写兼容 PM2 仍持有 fd)
|
||||
find "${PM2_LOG_DIR}" -type f -name '*.log' -size +20M -print -exec truncate -s 0 {} \;
|
||||
# 过期归档/旧编号日志直接删
|
||||
find "${PM2_LOG_DIR}" -type f \( -name '*.log' -o -name '*.log.gz' -o -name '*.log.[0-9]*' \) -mtime +"${RETENTION_DAYS}" -print -delete || true
|
||||
|
||||
if [[ "${CLEAN_ONLY}" -eq 1 ]]; then
|
||||
echo ">>> --clean-only done"
|
||||
du -sh "${PM2_LOG_DIR}" || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ">>> install logrotate: ${LOGROTATE_CONF} (daily, rotate ${RETENTION_DAYS}, maxsize ${MAXSIZE})"
|
||||
cat > "${LOGROTATE_CONF}" <<EOF
|
||||
${PM2_LOG_DIR}/*.log {
|
||||
daily
|
||||
rotate ${RETENTION_DAYS}
|
||||
maxsize ${MAXSIZE}
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
copytruncate
|
||||
dateext
|
||||
dateformat -%Y%m%d
|
||||
}
|
||||
EOF
|
||||
|
||||
# 立即跑一次(不强制等到 cron)
|
||||
if command -v logrotate >/dev/null 2>&1; then
|
||||
logrotate -f "${LOGROTATE_CONF}" || true
|
||||
else
|
||||
echo "warn: logrotate 未安装,仅完成清理;请 apt install logrotate"
|
||||
fi
|
||||
|
||||
echo ">>> size after"
|
||||
du -sh "${PM2_LOG_DIR}" || true
|
||||
ls -lah "${PM2_LOG_DIR}" | head -30 || true
|
||||
echo "done"
|
||||
@@ -23,10 +23,14 @@ echo ">>> force-close policy: gate=ON, binance/okx=OFF"
|
||||
python3 scripts/sync_common_trading_env.py --apply-force-close-policy "${DRY[@]}"
|
||||
|
||||
if [[ ${#DRY[@]} -gt 0 ]]; then
|
||||
echo "(dry-run, skip pm2 restart)"
|
||||
echo "(dry-run, skip pm2 log policy + restart)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ">>> pm2 log policy (silence leftover + 3-day retain)"
|
||||
sed -i 's/\r$//' deploy/pm2_log_policy.sh 2>/dev/null || true
|
||||
bash deploy/pm2_log_policy.sh
|
||||
|
||||
echo ">>> pm2 restart"
|
||||
pm2 restart crypto_gate crypto_binance crypto_okx manual-trading-hub manual-agent-gate 2>/dev/null \
|
||||
|| pm2 restart crypto-monitor-gate crypto-monitor-binance crypto-monitor-okx manual-trading-hub 2>/dev/null \
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
"""关闭 Flask/Werkzeug 开发服务器 access log 刷屏(避免灌满 PM2 error 日志)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
def silence_werkzeug_access_log() -> None:
|
||||
"""仅抑制 request access 行;WARNING/ERROR 仍可读."""
|
||||
log = logging.getLogger("werkzeug")
|
||||
log.setLevel(logging.WARNING)
|
||||
# 部分环境会挂 StreamHandler 到 stderr;抬高阈值即可
|
||||
for h in list(log.handlers):
|
||||
try:
|
||||
h.setLevel(logging.WARNING)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -0,0 +1,17 @@
|
||||
"""silence_werkzeug_access_log 烟雾测试."""
|
||||
import logging
|
||||
import unittest
|
||||
|
||||
from lib.common.flask_access_log_lib import silence_werkzeug_access_log
|
||||
|
||||
|
||||
class TestSilenceAccessLog(unittest.TestCase):
|
||||
def test_sets_warning_level(self):
|
||||
log = logging.getLogger("werkzeug")
|
||||
log.setLevel(logging.INFO)
|
||||
silence_werkzeug_access_log()
|
||||
self.assertGreaterEqual(log.level, logging.WARNING)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user