HoRain云--Skills 日志与调试进阶
🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录
⛳️ 推荐
用 logging 替代 print
实例
执行时间追踪
实例
结构化日志:输出 JSON 格式
实例
调试 SKILL.md 的指令执行
常见调试场景速查
入门调试靠 print,进阶调试靠系统性的日志机制。
本篇介绍如何为 Skill 脚本建立结构化日志,以及在复杂执行流程中定位问题的进阶技巧。
用 logging 替代 print
print 适合快速调试,但在正式 Skill 中应改用 Python 标准库的 logging 模块。
logging 的优势是可以控制输出级别——开发时输出 DEBUG 信息,生产时只输出 WARNING 以上。
实例
# 文件路径:scripts/logger_setup.py
import logging
import sys
from datetime import datetime
def get_logger(name: str, level: str = "INFO") -> logging.Logger:
"""
创建结构化日志记录器
参数:
name: 日志器名称,通常用模块名(__name__)
level: 日志级别,DEBUG / INFO / WARNING / ERROR
"""
logger = logging.getLogger(name)
logger.setLevel(getattr(logging, level.upper(), logging.INFO))
# 避免重复添加 handler
if logger.handlers:
return logger
# 控制台输出:人类可读格式
console = logging.StreamHandler(sys.stdout)
console.setFormatter(logging.Formatter(
"[%(asctime)s] [%(levelname)s] %(name)s - %(message)s",
datefmt="%H:%M:%S"
))
logger.addHandler(console)
# 文件输出:写入日志文件(可选)
log_file = f"/home/claude/skill_{datetime.now().strftime('%Y%m%d')}.log"
file_handler = logging.FileHandler(log_file, encoding="utf-8")
file_handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s"
))
logger.addHandler(file_handler)
return logger
# 使用示例
if __name__ == "__main__":
log = get_logger(__name__, level="DEBUG")
log.debug("调试信息:文件路径 = /mnt/user-data/uploads/runoob.csv")
log.info("开始处理文件")
log.warning("文件大小超过 50MB,处理可能较慢")
log.error("文件读取失败:FileNotFoundError")
[10:23:01] [DEBUG] __main__ - 调试信息:文件路径 = /mnt/user-data/uploads/runoob.csv [10:23:01] [INFO] __main__ - 开始处理文件 [10:23:01] [WARNING] __main__ - 文件大小超过 50MB,处理可能较慢 [10:23:01] [ERROR] __main__ - 文件读取失败:FileNotFoundError
执行时间追踪
当 Skill 执行较慢时,需要找出耗时的瓶颈步骤。
实例
# 文件路径:scripts/timer.py
import time
import functools
import logging
log = logging.getLogger(__name__)
def timeit(func):
"""装饰器:自动记录函数执行时间"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
log.info(f"{func.__name__} 耗时 {elapsed:.3f} 秒")
return result
return wrapper
# 使用方式:在需要计时的函数上加 @timeit 装饰器
@timeit
def load_csv(file_path: str):
import pandas as pd
return pd.read_csv(file_path)
@timeit
def calculate_stats(df):
return df.describe()
# 也可以用上下文管理器手动计时
class Timer:
def __init__(self, label: str):
self.label = label
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, *args):
elapsed = time.perf_counter() - self.start
log.info(f"{self.label} 耗时 {elapsed:.3f} 秒")
# 使用 Timer 上下文管理器
if __name__ == "__main__":
with Timer("读取并清洗数据"):
import pandas as pd
df = pd.read_csv("/mnt/user-data/uploads/runoob_data.csv")
df = df.dropna()
[10:23:05] [INFO] load_csv 耗时 0.342 秒 [10:23:05] [INFO] calculate_stats 耗时 0.018 秒 [10:23:05] [INFO] 读取并清洗数据 耗时 0.361 秒
结构化日志:输出 JSON 格式
当日志需要被程序解析(而非人工阅读)时,JSON 格式更合适。
实例
# 文件路径:scripts/json_logger.py
import json
import sys
from datetime import datetime
def log_event(level: str, event: str, **context):
"""
输出结构化 JSON 日志
参数:
level: 日志级别(info / warning / error)
event: 事件名称
context: 附加的上下文键值对
"""
entry = {
"timestamp": datetime.now().isoformat(),
"level": level,
"event": event,
**context
}
# 使用 stderr 输出日志,避免与脚本的正常输出混合
print(json.dumps(entry, ensure_ascii=False), file=sys.stderr)
# 使用示例
log_event("info", "file_loaded", file="/mnt/user-data/uploads/runoob.csv", rows=1024)
log_event("warning", "null_detected", column="score", count=12)
log_event("error", "parse_failed", reason="编码不是 UTF-8")
{"timestamp": "2026-05-18T10:23:05", "level": "info", "event": "file_loaded", "file": "/mnt/user-data/uploads/runoob.csv", "rows": 1024} {"timestamp": "2026-05-18T10:23:05", "level": "warning", "event": "null_detected", "column": "score", "count": 12} {"timestamp": "2026-05-18T10:23:05", "level": "error", "event": "parse_failed", "reason": "编码不是 UTF-8"}调试 SKILL.md 的指令执行
当 Claude 没有按照 SKILL.md 的指令执行时,可以通过在 SKILL.md 中插入"检查点"来定位问题。
## 调试检查点(开发模式,发布前删除) 在执行每个步骤前,先以以下格式输出一行状态确认: `[STEP N] 开始:{步骤名称},输入:{关键参数}` 示例: `[STEP 1] 开始:读取文件,输入:/mnt/user-data/uploads/runoob.csv` `[STEP 2] 开始:数据清洗,输入:1024 行` 这样可以在出错时快速定位到哪个步骤失败。调试检查点是临时的。调试完成后,务必从 SKILL.md 中删除这些指令,否则正式使用时用户会看到多余的调试输出。
常见调试场景速查
| 场景 | 调试方法 |
|---|---|
| Skill 未触发 | 检查 description、使用复杂提示词测试、运行 run_loop.py 优化 |
| 脚本报 ImportError | 运行 pip install,检查包名与 import 名称是否匹配 |
| 文件路径报错 | 先 ls /mnt/user-data/uploads/ 确认文件名 |
| 输出乱码 | 在文件读取时显式指定 encoding="utf-8" |
| 步骤执行顺序不对 | 在 SKILL.md 中用编号列表明确步骤顺序 |
| 结果为空 | 在脚本关键节点加 print,确认数据在哪一步变空 |
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
