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:
parent
2c5fb53ef3
commit
24c3f033d2
68
check_errors.py
Executable file
68
check_errors.py
Executable 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()
|
||||||
3
setup.sh
3
setup.sh
@ -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)"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user