add excel failure alert log with error digest

This commit is contained in:
Mayorz 2026-03-04 16:54:39 +08:00
parent c382665753
commit fa631100ba

View File

@ -14,6 +14,7 @@ import re
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import threading
import time import time
import urllib.parse import urllib.parse
import uuid import uuid
@ -328,6 +329,16 @@ class OpenClawDingTalkBot(ChatbotHandler):
10, 10,
min(int(os.getenv("EXCEL_TEXT_PROMPT_COOLDOWN_SECONDS", "120")), 600), min(int(os.getenv("EXCEL_TEXT_PROMPT_COOLDOWN_SECONDS", "120")), 600),
) )
self.excel_alert_log_enabled = bool_env("EXCEL_ALERT_LOG_ENABLED", True)
self.excel_alert_log_path = (
os.getenv(
"EXCEL_ALERT_LOG_PATH",
"/opt/openclaw-dingtalk-bridge/logs/excel_converter_alerts.log",
).strip()
or "/opt/openclaw-dingtalk-bridge/logs/excel_converter_alerts.log"
)
self.excel_alert_detail_limit = max(200, min(int(os.getenv("EXCEL_ALERT_DETAIL_LIMIT", "1600")), 10000))
self._excel_alert_log_lock = threading.Lock()
self._recent_excel_success_ts = {} self._recent_excel_success_ts = {}
def _should_handle(self, msg: ChatbotMessage, text: str) -> bool: def _should_handle(self, msg: ChatbotMessage, text: str) -> bool:
@ -2253,6 +2264,71 @@ class OpenClawDingTalkBot(ChatbotHandler):
self.logger.exception("upload excel output to s3 failed: %s", exc) self.logger.exception("upload excel output to s3 failed: %s", exc)
return "" return ""
def _excel_error_summary(self, detail: str) -> str:
raw = str(detail or "").strip()
if not raw:
return "unknown_error"
lines = [line.strip() for line in raw.splitlines() if line.strip()]
if not lines:
return raw[:300]
for line in reversed(lines):
lower_line = line.lower()
if lower_line.startswith("traceback"):
continue
if lower_line.startswith("file "):
continue
if lower_line in {"^^^^^^", "^^^^^"}:
continue
return line[:300]
return lines[-1][:300]
def _record_excel_failure_alert(
self,
msg: ChatbotMessage,
file_name: str,
stage: str,
detail: str,
return_code: int | None = None,
stdout_text: str = "",
stderr_text: str = "",
) -> None:
normalized_detail = str(detail or "").strip() or "unknown_error"
summary = self._excel_error_summary(normalized_detail)
digest = hashlib.sha1(normalized_detail.encode("utf-8", errors="ignore")).hexdigest()[:12]
log_record = {
"ts": dt.datetime.now().isoformat(timespec="seconds"),
"event": "excel_convert_failed",
"stage": stage,
"digest": digest,
"summary": summary,
"return_code": return_code,
"file_name": str(file_name or ""),
"conversation_id": str(getattr(msg, "conversation_id", "") or ""),
"session_webhook": str(getattr(msg, "session_webhook", "") or ""),
"sender_staff_id": str(getattr(msg, "sender_staff_id", "") or ""),
"detail": normalized_detail[: self.excel_alert_detail_limit],
"stderr": str(stderr_text or "")[: self.excel_alert_detail_limit],
"stdout": str(stdout_text or "")[: self.excel_alert_detail_limit],
}
self.logger.warning(
"excel failure alert stage=%s digest=%s file=%s summary=%s",
stage,
digest,
file_name,
summary,
)
if not self.excel_alert_log_enabled:
return
try:
parent_dir = os.path.dirname(self.excel_alert_log_path) or "."
os.makedirs(parent_dir, exist_ok=True)
line = json.dumps(log_record, ensure_ascii=False)
with self._excel_alert_log_lock:
with open(self.excel_alert_log_path, "a", encoding="utf-8") as file_obj:
file_obj.write(line + "\n")
except Exception:
self.logger.exception("write excel alert log failed")
def _run_excel_image_link_job(self, msg: ChatbotMessage, file_payload: dict) -> tuple[str, bool]: def _run_excel_image_link_job(self, msg: ChatbotMessage, file_payload: dict) -> tuple[str, bool]:
if not self.excel_link_feature_enabled: if not self.excel_link_feature_enabled:
return "Excel 图片链接转图片功能未启用。", False return "Excel 图片链接转图片功能未启用。", False
@ -2282,6 +2358,12 @@ class OpenClawDingTalkBot(ChatbotHandler):
fh.write(response.content) fh.write(response.content)
except Exception as exc: except Exception as exc:
self.logger.exception("download incoming excel failed") self.logger.exception("download incoming excel failed")
self._record_excel_failure_alert(
msg,
file_name,
stage="download_source_excel",
detail=f"{type(exc).__name__}: {exc}",
)
return f"下载源文件失败:{exc}", False return f"下载源文件失败:{exc}", False
cmd = [ cmd = [
@ -2312,6 +2394,12 @@ class OpenClawDingTalkBot(ChatbotHandler):
timeout=self.excel_converter_timeout, timeout=self.excel_converter_timeout,
) )
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
self._record_excel_failure_alert(
msg,
file_name,
stage="excel_converter_timeout",
detail=f"timeout>{self.excel_converter_timeout}s",
)
return f"Excel 转换超时(>{self.excel_converter_timeout}秒),请稍后重试。", False return f"Excel 转换超时(>{self.excel_converter_timeout}秒),请稍后重试。", False
stdout_text = (proc.stdout or "").strip() stdout_text = (proc.stdout or "").strip()
@ -2319,6 +2407,15 @@ class OpenClawDingTalkBot(ChatbotHandler):
if proc.returncode != 0 or not os.path.exists(output_path): if proc.returncode != 0 or not os.path.exists(output_path):
detail = stderr_text or stdout_text or "未知错误" detail = stderr_text or stdout_text or "未知错误"
self.logger.error("excel converter failed code=%s detail=%s", proc.returncode, detail[:2500]) self.logger.error("excel converter failed code=%s detail=%s", proc.returncode, detail[:2500])
self._record_excel_failure_alert(
msg,
file_name,
stage="excel_converter_failed",
detail=detail,
return_code=proc.returncode,
stdout_text=stdout_text,
stderr_text=stderr_text,
)
return f"Excel 转换失败:{detail[:1200]}", False return f"Excel 转换失败:{detail[:1200]}", False
summary_line = "" summary_line = ""