add excel failure alert log with error digest
This commit is contained in:
parent
c382665753
commit
fa631100ba
@ -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 = ""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user