- 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>
69 lines
1.6 KiB
Python
Executable File
69 lines
1.6 KiB
Python
Executable File
#!/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()
|