頻道日誌
將 Discord 頻道活動以結構化 JSONL 檔案串流輸出,用於稽核、合規,以及分析用途。
問題背景
你需要可靠的稽核紀錄來追蹤 Discord 伺服器中發生的事件。可能是為了合規、社群分析,或只是要保留歷史記錄。Discord 內建稽核日誌欄位有限,也不會保存訊息內容。
解法
使用 discli listen 即時串流事件,並導向寫入日誌檔。每筆事件都是一個獨立的 JSON 物件(JSONL 格式,一行一筆),因此可以直接用 jq、grep 或 Python 工具快速解析與分析。
完整可執行範例
#!/bin/bash# channel-logger.sh — 將 Discord 頻道訊息串流輸出為 JSONL 日誌。
CHANNEL="${1:?用法:$0 <channel> [logfile]}"LOGFILE="${2:-discord-${CHANNEL}-$(date +%Y%m%d).jsonl}"
echo "開始記錄 #${CHANNEL} 到 ${LOGFILE}..." >&2echo "按 Ctrl+C 可停止。" >&2
discli --json listen --channel "$CHANNEL" --events messages | while read -r event; do # 將原始 JSON 事件逐行寫入日誌 echo "$event" >> "$LOGFILE"
# 在終端機輸出可讀摘要 author=$(echo "$event" | jq -r '.author') content=$(echo "$event" | jq -r '.content') timestamp=$(echo "$event" | jq -r '.timestamp[:19]' | tr 'T' ' ') echo "[${timestamp}] ${author}: ${content}"done
echo "記錄已停止。" >&2執行方式:
chmod +x channel-logger.sh./channel-logger.sh general# 或改用自訂日誌檔:./channel-logger.sh general /var/log/discord/general.jsonl#!/usr/bin/env python3"""channel_logger.py — 將 Discord 事件串流輸出為 JSONL,並每日輪換檔案。"""
import jsonimport subprocessimport sysfrom datetime import datetime, timezonefrom pathlib import Path
CHANNEL = sys.argv[1] if len(sys.argv) > 1 else NoneLOG_DIR = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(".")
if not CHANNEL: print("用法:python channel_logger.py <channel> [log_directory]", file=sys.stderr) sys.exit(1)
LOG_DIR.mkdir(parents=True, exist_ok=True)
def get_log_path(): """依日期產生日誌檔路徑,用於每日輪替。""" date_str = datetime.now(timezone.utc).strftime("%Y-%m-%d") return LOG_DIR / f"discord-{CHANNEL}-{date_str}.jsonl"
current_date = Nonelog_file = None
# 開始監聽cmd = ["discli", "--json", "listen", "--channel", CHANNEL, "--events", "messages"]proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
print(f"開始記錄 #{CHANNEL} 到 {LOG_DIR}/。按 Ctrl+C 可停止。", file=sys.stderr)
try: for line in proc.stdout: line = line.strip() if not line: continue
try: event = json.loads(line) except json.JSONDecodeError: continue
# 每日輪替 today = datetime.now(timezone.utc).date() if today != current_date: if log_file: log_file.close() log_file = open(get_log_path(), "a", encoding="utf-8") current_date = today print(f"[rotate] 正在寫入 {get_log_path()}", file=sys.stderr)
# 寫入原始 JSONL log_file.write(json.dumps(event, default=str) + "\n") log_file.flush()
# 在終端機輸出摘要 ts = event.get("timestamp", "")[:19].replace("T", " ") author = event.get("author", "unknown") content = event.get("content", "") print(f"[{ts}] {author}: {content}")
except KeyboardInterrupt: print("\n記錄器已停止。", file=sys.stderr)finally: if log_file: log_file.close() proc.terminate()執行方式:
python channel_logger.py general ./logs#!/bin/bash# multi-logger.sh — 同步記錄多個頻道。
LOG_DIR="${1:-./discord-logs}"mkdir -p "$LOG_DIR"
CHANNELS=("general" "support" "announcements" "dev-chat")
echo "正在記錄 ${#CHANNELS[@]} 個頻道到 ${LOG_DIR}/..." >&2
pids=()for channel in "${CHANNELS[@]}"; do logfile="${LOG_DIR}/${channel}-$(date +%Y%m%d).jsonl" discli --json listen --channel "$channel" --events messages >> "$logfile" & pids+=("$!") echo " #${channel} -> ${logfile}" >&2done
echo "按 Ctrl+C 可停止全部記錄器。" >&2
# 等待 Ctrl+C,之後清除trap 'echo "正在停止..."; kill "${pids[@]}" 2>/dev/null; exit 0' INT TERMwait逐步解說
啟動事件串流
discli listen 會開啟與 Discord 的 WebSocket 連線,並以 JSONL 逐行輸出事件。--channel 用來指定頻道,--events messages 則只保留訊息事件。
discli --json listen --channel general --events messages每一行輸出皆為完整 JSON 物件:
{"event":"message","server":"我的伺服器","channel":"general","channel_id":"123...","author":"Alice","author_id":"456...","content":"大家好!","timestamp":"2026-03-15T10:30:00+00:00","message_id":"789...","mentions_bot":false,"attachments":[],"reply_to":null}寫入 JSONL 檔案
每筆 JSON 事件都以獨立一行附加到日誌檔。JSONL(JSON Lines)即每行皆為合法 JSON 物件,配合 jq、sed、Python 都很容易處理。
建議每次 write 後呼叫 flush()(或使用逐行緩衝輸出),避免程序異常時遺失已接收的事件。
用 jq 分析
取得日誌後,可用 jq 提取關鍵訊息:
# 每位作者的訊息數jq -r '.author' discord-general-2026-03-15.jsonl | sort | uniq -c | sort -rn
# 搜尋關鍵字jq -r 'select(.content | test("bug"; "i")) | "\(.author): \(.content)"' discord-general-2026-03-15.jsonl
# 每小時訊息數jq -r '.timestamp[:13]' discord-general-2026-03-15.jsonl | sort | uniq -c
# 列出所有作者jq -r '.author' discord-general-2026-03-15.jsonl | sort -u
# 取出含附件的訊息jq 'select(.attachments | length > 0)' discord-general-2026-03-15.jsonl設定檔案輪替
Python 版本內建每日輪替,每天會自動建立新檔;bash 版本可自行在檔名加入日期,或搭配 logrotate:
# 使用 cron 每日輪替(午夜)# crontab -e0 0 * * * pkill -f "discli.*listen.*general" && /path/to/channel-logger.sh general /var/log/discord/general-$(date +\%Y\%m\%d).jsonl &邊際案例與陷阱
磁碟空間。 熱門頻道每天可能產生數十 MB 到數百 MB 日誌。建議監控磁碟用量,並定期清除舊檔。簡單做法可在 cron 加上:find /var/log/discord -name "*.jsonl" -mtime +30 -delete
編碼問題。 Discord 訊息可能包含各種 Unicode 字元(emoji、RTL 文字、零寬字元)。寫入檔案請固定使用 encoding="utf-8",並透過 json.dumps(event, default=str, ensure_ascii=False) 保留原始文字。
重啟期間事件遺失。 如果記錄器程序當機或重啟,當中間斷期間的事件會遺失。discli listen 僅支援即時串流,不會補播缺漏。若要零缺口日誌,建議搭配定期 discli message history 回補。
隱私與合規。 記錄訊息內容可能涉及隱私法規(GDPR、CCPA)。請在伺服器規範中聲明紀錄行為,並建立使用者刪除請求處理流程。
擴充方向
上傳到雲端儲存
將每日完成的日誌上傳到 S3、GCS 或 Azure Blob。可在午夜後用排程壓縮並上傳前一日檔案。
導入 SQLite 分析
將 JSONL 解析成 SQLite,建立訊息、作者、頻道等資料表,進行更彈性的查詢分析。
即時關鍵字告警
在串流上加上關鍵字過濾,遇到特定詞立即通知監控頻道或 webhook。可結合 Moderation Bot 模式。
Grafana 儀表板
將訊息數、活躍使用者、回應時間等指標輸出到 Prometheus / InfluxDB,再用 Grafana 做即時監控。