Skills: Fortgeschrittenes Logging und Debugging

Einfaches Debugging stützt sich auf print, fortgeschrittenes Debugging auf systematische Logging-Mechanismen.

Dieser Artikel stellt vor, wie man strukturiertes Logging für Skill-Skripte einrichtet, sowie fortgeschrittene Techniken zur Lokalisierung von Problemen in komplexen Ausführungsabläufen.


Ersetze print durch logging

printGeeignet für schnelles Debugging, aber in Produktions-Skills sollte man auf daslogging-Modul der Python-Standardbibliothek umsteigen.

Der Vorteil der Protokollierung besteht darin, dass Sie die Ausgabestufe steuern können – während der Entwicklung DEBUG-Informationen ausgeben und in der Produktion nur WARNING und höher.

Beispiel

# Dateipfad: scripts/logger_setup.py
import logging
import sys
from datetime import datetime

def get_logger(name: str, level: str = "INFO") -> logging.Logger:
    """
Erstellen Sie einen strukturierten Logger

Parameter:
name: Logger-Name, normalerweise der Modulname (__name__)
level: Log-Level, DEBUG / INFO / WARNING / ERROR
    """

    logger = logging.getLogger(name)
    logger.setLevel(getattr(logging, level.upper(), logging.INFO))

    # Wiederholtes Hinzufügen von Handlern vermeiden
    if logger.handlers:
        return logger

    # Konsolenausgabe: menschenlesbares Format
    console = logging.StreamHandler(sys.stdout)
    console.setFormatter(logging.Formatter(
        "[%(asctime)s] [%(levelname)s] %(name)s - %(message)s",
        datefmt="%H:%M:%S"
    ))
    logger.addHandler(console)

    # Dateiausgabe: in Logdatei schreiben (optional)
    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

# Verwendungsbeispiel
if __name__ == "__main__":
    log = get_logger(__name__, level="DEBUG")

    log.debug("Debug-Info: Dateipfad = /mnt/user-data/uploads/example.csv")
    log.info("Dateiverarbeitung starten")
    log.warning("Dateigröße überschreitet 50MB, die Verarbeitung könnte langsam sein")
    log.error("Datei konnte nicht gelesen werden: FileNotFoundError")
[10:23:01] [DEBUG]   __main__ - 调试信息:文件路径 = /mnt/user-data/uploads/example.csv
[10:23:01] [INFO]    __main__ - 开始处理文件
[10:23:01] [WARNING] __main__ - 文件大小超过 50MB,处理可能较慢
[10:23:01] [ERROR]   __main__ - 文件读取失败:FileNotFoundError

Verfolgung der Ausführungszeit

Wenn ein Skill langsam ausgeführt wird, müssen Sie die zeitintensiven Engpass-Schritte identifizieren.

Beispiel

# Dateipfad: scripts/timer.py
import time
import functools
import logging

log = logging.getLogger(__name__)

def timeit(func):
    """Dekorator: erfasst automatisch die Ausführungszeit einer Funktion"""
    @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__} dauerte {elapsed:.3f} Sekunden")
        return result
    return wrapper

# Verwendung: Fügen Sie den @timeit-Dekorator zu der Funktion hinzu, die Sie messen möchten
@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()

# Sie können auch einen Kontextmanager zur manuellen Zeitmessung verwenden
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} dauerte {elapsed:.3f} Sekunden")

# Verwende den Timer-Kontextmanager
if __name__ == "__main__":
    with Timer("Daten lesen und bereinigen"):
        import pandas as pd
        df = pd.read_csv("/mnt/user-data/uploads/example_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 秒

Strukturiertes Logging: JSON-Format ausgeben

Wenn Logs von Programmen geparst werden müssen (anstatt von Menschen gelesen zu werden), ist das JSON-Format besser geeignet.

Beispiel

# Dateipfad: scripts/json_logger.py
import json
import sys
from datetime import datetime

def log_event(level: str, event: str, **context):
    """
Strukturierte JSON-Logs ausgeben

Parameter:
level: Log-Level (info / warning / error)
event: Ereignisname
context: Zusätzliche Kontext-Schlüssel-Wert-Paare
    """

    entry = {
        "timestamp": datetime.now().isoformat(),
        "level": level,
        "event": event,
        **context
    }
    # stderr für die Log-Ausgabe verwenden, um eine Vermischung mit der normalen Ausgabe des Skripts zu vermeiden
    print(json.dumps(entry, ensure_ascii=False), file=sys.stderr)

# Verwendungsbeispiel
log_event("info",    "file_loaded",   file="/mnt/user-data/uploads/example.csv", rows=1024)
log_event("warning", "null_detected", column="score", count=12)
log_event("error",   "parse_failed",  reason="Kodierung ist nicht UTF-8")
{"timestamp": "2026-05-18T10:23:05", "level": "info",    "event": "file_loaded",   "file": "/mnt/user-data/uploads/example.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"}

Debugging der SKILL.md-Anweisungsausführung

Wenn Claude nicht gemäß den Anweisungen in SKILL.md handelt, können Sie das Problem lokalisieren, indem Sie „Kontrollpunkte“ in SKILL.md einfügen.

## 调试检查点(开发模式,发布前删除)

在执行每个步骤前,先以以下格式输出一行状态确认:

`[STEP N] 开始:{步骤名称},输入:{关键参数}`

示例:
`[STEP 1] 开始:读取文件,输入:/mnt/user-data/uploads/example.csv`
`[STEP 2] 开始:数据清洗,输入:1024 行`

这样可以在出错时快速定位到哪个步骤失败。

Debugging-Kontrollpunkte sind temporär. Nach Abschluss des Debuggings müssen diese Anweisungen unbedingt aus SKILL.md entfernt werden, sonst sehen Benutzer bei normaler Nutzung überflüssige Debug-Ausgaben.


Schnellreferenz für häufige Debugging-Szenarien

SzenarioDebugging-Methode
Skill wird nicht ausgelöstBeschreibung prüfen, mit komplexen Prompts testen, run_loop.py zum Optimieren ausführen
Skript meldet ImportErrorpip install ausführen, prüfen, ob der Paketname mit dem Importnamen übereinstimmt
DateipfadfehlerZuerst ls /mnt/user-data/uploads/ ausführen, um den Dateinamen zu bestätigen
Verstümmelte AusgabeBeim Lesen von Dateien explizit encoding="utf-8" angeben
Falsche Ausführungsreihenfolge der SchritteVerwende eine nummerierte Liste in SKILL.md, um die Reihenfolge der Schritte zu verdeutlichen
Leeres ErgebnisFüge print an Schlüsselstellen im Skript hinzu, um zu bestätigen, bei welchem Schritt die Daten leer werden
Weitere Erweiterungen