commit
This commit is contained in:
146
backend/error_screenshot.py
Normal file
146
backend/error_screenshot.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
错误截图保存工具
|
||||
当发生错误时自动截图并保存,便于问题排查
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from playwright.async_api import Page
|
||||
|
||||
|
||||
# 截图保存目录
|
||||
SCREENSHOT_DIR = Path("error_screenshots")
|
||||
SCREENSHOT_DIR.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
async def save_error_screenshot(
|
||||
page: Optional[Page],
|
||||
error_type: str,
|
||||
error_message: str = "",
|
||||
prefix: str = ""
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
保存错误截图
|
||||
|
||||
Args:
|
||||
page: Playwright 页面对象
|
||||
error_type: 错误类型(如:login_failed, send_code_failed, publish_failed等)
|
||||
error_message: 错误信息(可选,会添加到日志)
|
||||
prefix: 文件名前缀(可选)
|
||||
|
||||
Returns:
|
||||
截图文件路径,失败返回None
|
||||
"""
|
||||
if not page:
|
||||
print("[错误截图] 页面对象为空,无法截图", file=sys.stderr)
|
||||
return None
|
||||
|
||||
try:
|
||||
# 生成文件名:年月日时分秒_错误类型.png
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
# 清理错误类型字符串(移除特殊字符)
|
||||
safe_error_type = "".join(c for c in error_type if c.isalnum() or c in ('_', '-'))
|
||||
|
||||
# 组合文件名
|
||||
if prefix:
|
||||
filename = f"{prefix}_{timestamp}_{safe_error_type}.png"
|
||||
else:
|
||||
filename = f"{timestamp}_{safe_error_type}.png"
|
||||
|
||||
filepath = SCREENSHOT_DIR / filename
|
||||
|
||||
# 截图
|
||||
await page.screenshot(path=str(filepath), full_page=True)
|
||||
|
||||
# 打印日志
|
||||
print(f"[错误截图] 已保存: {filepath}", file=sys.stderr)
|
||||
if error_message:
|
||||
print(f"[错误截图] 错误信息: {error_message}", file=sys.stderr)
|
||||
|
||||
# 返回文件路径
|
||||
return str(filepath)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[错误截图] 截图失败: {str(e)}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def cleanup_old_screenshots(days: int = 7):
|
||||
"""
|
||||
清理旧的错误截图
|
||||
|
||||
Args:
|
||||
days: 保留最近几天的截图,默认7天
|
||||
"""
|
||||
try:
|
||||
import time
|
||||
current_time = time.time()
|
||||
cutoff_time = current_time - (days * 24 * 60 * 60)
|
||||
|
||||
deleted_count = 0
|
||||
for file in SCREENSHOT_DIR.glob("*.png"):
|
||||
if file.stat().st_mtime < cutoff_time:
|
||||
file.unlink()
|
||||
deleted_count += 1
|
||||
|
||||
if deleted_count > 0:
|
||||
print(f"[错误截图] 已清理 {deleted_count} 个超过 {days} 天的旧截图", file=sys.stderr)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[错误截图] 清理旧截图失败: {str(e)}", file=sys.stderr)
|
||||
|
||||
|
||||
async def save_screenshot_with_html(
|
||||
page: Optional[Page],
|
||||
error_type: str,
|
||||
error_message: str = "",
|
||||
prefix: str = ""
|
||||
) -> tuple[Optional[str], Optional[str]]:
|
||||
"""
|
||||
保存错误截图和HTML源码(用于深度调试)
|
||||
|
||||
Args:
|
||||
page: Playwright 页面对象
|
||||
error_type: 错误类型
|
||||
error_message: 错误信息(可选)
|
||||
prefix: 文件名前缀(可选)
|
||||
|
||||
Returns:
|
||||
(截图路径, HTML路径),失败返回(None, None)
|
||||
"""
|
||||
if not page:
|
||||
return None, None
|
||||
|
||||
try:
|
||||
# 生成文件名
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
safe_error_type = "".join(c for c in error_type if c.isalnum() or c in ('_', '-'))
|
||||
|
||||
if prefix:
|
||||
base_filename = f"{prefix}_{timestamp}_{safe_error_type}"
|
||||
else:
|
||||
base_filename = f"{timestamp}_{safe_error_type}"
|
||||
|
||||
# 保存截图
|
||||
screenshot_path = SCREENSHOT_DIR / f"{base_filename}.png"
|
||||
await page.screenshot(path=str(screenshot_path), full_page=True)
|
||||
|
||||
# 保存HTML
|
||||
html_path = SCREENSHOT_DIR / f"{base_filename}.html"
|
||||
html_content = await page.content()
|
||||
with open(html_path, 'w', encoding='utf-8') as f:
|
||||
f.write(html_content)
|
||||
|
||||
print(f"[错误截图] 已保存截图: {screenshot_path}", file=sys.stderr)
|
||||
print(f"[错误截图] 已保存HTML: {html_path}", file=sys.stderr)
|
||||
if error_message:
|
||||
print(f"[错误截图] 错误信息: {error_message}", file=sys.stderr)
|
||||
|
||||
return str(screenshot_path), str(html_path)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[错误截图] 保存截图和HTML失败: {str(e)}", file=sys.stderr)
|
||||
return None, None
|
||||
Reference in New Issue
Block a user