Skills Monitoring
After publishing a Skill, how do you know if it's working well? Are there frequent errors? Which steps are the slowest?
This article introduces how to establish observability for Skills, understanding the running state through logs and metrics.
* * *
## Three Dimensions of Observability
| Dimension | Questions Answered | Implementation |
| --- | --- | --- |
| Logs | What happened? What went wrong? | Structured JSON log files |
| Metrics | How many times executed? How long did it take? What's the success rate? | Append-write metric files |
| Trace | What steps did each execution go through? How long did each step take? | Step-level timestamp recording |
* * *
## Structured Log Output Standards
Skill scripts should write running logs to a fixed path file for later review.
## Example
# File path: scripts/skill_logger.py
import json
import os
import sys
from datetime import datetime, timezone
LOG_FILE ="/home/claude/skill_run.log"
def log(level: str, event: str, skill: str="", **context):
"""
Write structured log entry
Parameters:
level: Log level (info / warning / error)
event: Event Name (snake_case)
skill: Skill Name
context: Any additional fields
"""
entry ={
"ts": datetime.now(timezone.utc).isoformat(),
"level": level,
"event": event,
"skill": skill,
**context
}
line = json.dumps(entry, ensure_ascii=False)
# Output simultaneously to stderr (real-time visibility) and log file (persistence)
print(line,file=sys.stderr)
with open(LOG_FILE,"a", encoding="utf-8")as f:
f.write(line + "n")
# Usage example
if __name__ =="__main__":
log("info","skill_start",skill="data-analyzer",
file="/mnt/user-data/uploads/tutorial.csv")
log("info","step_complete",skill="data-analyzer",
step="clean", rows_removed=3, elapsed_ms=240)
log("info","skill_complete", skill="data-analyzer",
output="/mnt/user-data/outputs/report.xlsx", elapsed_ms=1830)
log("error","step_failed",skill="data-analyzer",
step="generate_chart", error="openpyxl not found")
{"ts": "2026-05-18T10:23:05+00:00", "level": "info", "event": "skill_start", "skill": "data-analyzer", "file": "/mnt/user-data/uploads/tutorial.csv"}{"ts": "2026-05-18T10:23:05+00:00", "level": "info", "event": "step_complete", "skill": "data-analyzer", "step": "clean", "rows_removed": 3, "elapsed_ms": 240}{"ts": "2026-05-18T10:23:07+00:00", "level": "info", "event": "skill_complete", "skill": "data-analyzer", "output": "/mnt/user-data/outputs/report.xlsx", "elapsed_ms": 1830}{"ts": "2026-05-18T10:23:07+00:00", "level": "error", "event": "step_failed", "skill": "data-analyzer", "step": "generate_chart", "error": "openpyxl not found"}
* * *
## Metrics Aggregation: Counting Executions and Success Rate
Extract key metrics from log files to understand the overall running status of the Skill.
## Example
# FilePath: scripts/metrics_report.py
# Aggregate Skill runtime metrics from log file
import json
import os
from collections import defaultdict
LOG_FILE ="/home/claude/skill_run.log"
def generate_metrics_report(log_file: str) ->dict:
"""Read log file and generate metrics summary"""
if not os.path.exists(log_file):
return{"error": f"Log file does not exist:{log_file}"}
counts = defaultdict(int)# Event counts by type
errors =[]# Error records
elapsed =[]# List of execution durations (ms)
with open(log_file, encoding="utf-8")as f:
for line in f:
line = line.strip()
if not line:
continue
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
event = entry.get("event","")
counts +=1
if entry.get("level")=="error":
errors.append({
"ts": entry.get("ts"),
"event": event,
"error":
YouTip