Add check_errors.py cron job for API error monitoring

- New check_errors.py: scans last 1 hour of logs, sends Slack @channel only on errors
- Add to system crontab (every 5 min)
- Update setup.sh to include check_errors.py in crontab setup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kroutony 2026-03-15 12:34:52 +00:00
parent 2c5fb53ef3
commit 24c3f033d2
2 changed files with 73 additions and 2 deletions

68
check_errors.py Executable file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""Check API errors in the last hour and send Slack alert if any found."""
import os
import sys
from datetime import datetime, timedelta
sys.path.insert(0, os.path.dirname(__file__))
import slack_notifier
LOG_FILES = [
"trading.log",
"sync_cost_basis.log",
"cron.log",
]
LOOKBACK_MINUTES = 60
def collect_recent_errors() -> list[str]:
since = datetime.now() - timedelta(minutes=LOOKBACK_MINUTES)
since_str = since.strftime("%Y-%m-%d %H:%M")
errors = []
for logfile in LOG_FILES:
path = os.path.join(os.path.dirname(__file__), logfile)
if not os.path.exists(path):
continue
with open(path) as f:
for line in f:
if "[ERROR]" not in line:
continue
# Only compare lines that start with a timestamp
if not line[:4].isdigit():
continue
if line[:16] >= since_str:
errors.append(line.rstrip())
return errors
def main():
errors = collect_recent_errors()
if not errors:
return
# Deduplicate and limit
unique = list(dict.fromkeys(errors))
display = unique[:20]
remaining = len(unique) - len(display)
lines = [
"<!channel>",
f"⚠️ *API 錯誤警報* (最近 {LOOKBACK_MINUTES} 分鐘,共 {len(unique)} 筆)",
"",
]
for e in display:
lines.append(f"• `{e[:200]}`")
if remaining > 0:
lines.append(f"\n...另有 {remaining} 筆錯誤")
slack_notifier._send({"text": "\n".join(lines)})
if __name__ == "__main__":
main()

View File

@ -118,6 +118,7 @@ echo "[6/6] Setting up crontab..."
CRON_MAIN="*/5 * * * * sleep 30 && cd $PROJECT_DIR && /usr/bin/python3 main.py >> cron.log 2>&1" CRON_MAIN="*/5 * * * * sleep 30 && cd $PROJECT_DIR && /usr/bin/python3 main.py >> cron.log 2>&1"
CRON_SYNC="2,32 * * * * cd $PROJECT_DIR && /usr/bin/python3 sync_cost_basis.py >> sync_cost_basis_cron.log 2>&1" CRON_SYNC="2,32 * * * * cd $PROJECT_DIR && /usr/bin/python3 sync_cost_basis.py >> sync_cost_basis_cron.log 2>&1"
CRON_CHECK="*/5 * * * * cd $PROJECT_DIR && /usr/bin/python3 check_errors.py 2>&1"
CRON_ENV="PATH=$HOME/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" CRON_ENV="PATH=$HOME/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
CRON_PYPATH="PYTHONPATH=$HOME/.local/lib/python3.12/site-packages" CRON_PYPATH="PYTHONPATH=$HOME/.local/lib/python3.12/site-packages"
@ -136,6 +137,7 @@ $CRON_PYPATH
$CRON_MAIN $CRON_MAIN
$CRON_SYNC $CRON_SYNC
$CRON_CHECK
CRONTAB CRONTAB
) | crontab - ) | crontab -
echo " crontab installed ✓" echo " crontab installed ✓"
@ -159,3 +161,4 @@ echo ""
echo "Crontab 排程:" echo "Crontab 排程:"
echo " main.py: 每 5 分鐘(延遲 30 秒)" echo " main.py: 每 5 分鐘(延遲 30 秒)"
echo " sync_cost_basis.py: 每小時 :02 和 :32" echo " sync_cost_basis.py: 每小時 :02 和 :32"
echo " check_errors.py: 每 5 分鐘(有錯才 Slack @channel"