/cw-debug — CloudWatch Log Investigation Skill
You are investigating a production issue using CloudWatch Logs Insights. Follow the structured methodology below, adapting queries based on what you discover in each phase.
Arguments
The user will invoke this skill as:
/cw-debug <log_group> <filter_pattern> <hours_back> <region> "<issue_description>"
log_group: The CloudWatch log group path (e.g., /aws/ecs/my-service)
filter_pattern: Any string to filter logs — a user ID, request ID, service name, error code, or any identifier relevant to the investigation
hours_back: How many hours of logs to search (e.g., 24, 168 for 7 days)
region: AWS region (e.g., us-east-1)
issue_description: Free-text description of the problem being investigated (bug, performance issue, unexpected behavior, etc.)
Setup
- Always use
.venv/bin/python to run scripts
- The skill has its own self-contained CloudWatch utility at
${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/scripts/cw.py
- Do NOT import from
cloudwatch_utils.py — use the skill's own module instead
- To use in inline scripts, add the scripts dir to
sys.path then import:import sys, os
sys.path.insert(0, os.path.expanduser("${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/scripts"))
from cw import CWClient
cw = CWClient(region="{region}")
results = cw.query("{query}", hours_back={hours_back}, log_group="{log_group}")
cw.print_table(results)
- Or use the CLI directly:
.venv/bin/python ${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/scripts/cw.py \
--region {region} --log-group "{log_group}" --hours {hours_back} \
--query "fields @timestamp, @message | limit 25"
- Available
CWClient methods:
cw.query(query_string, hours_back, log_group) — single log group query
cw.query_multi(query_string, hours_back, log_groups) — query multiple log groups, merge results with _log_group tag
CWClient.summarize_stats(results, value_field, group_field=None) — compute count/avg/min/p50/p90/p95/p99/max from fetched results
CWClient.time_bucket_counts(results, timestamp_field, bucket_minutes) — group into time buckets for spike detection
CWClient.print_table(results) — ASCII table output
CWClient.print_json(results) — JSON output
cw.save(results, name) — save to investigations/<name>.csv
- Refer to
${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/query_library.md for pre-built query templates
Rules
- Analyze before querying: After every query result, analyze the data and explain what you found before running the next query. Never chain queries blindly.
- Adapt parse patterns: Phase 1 reveals the actual log format. Use those discovered patterns (field names, delimiters, JSON structure) in all subsequent phases. Do NOT assume a log format before seeing real logs.
- Do not write files unless user explicitly asks. Print findings to stdout. Only save CSVs or reports when the user requests it.
- Read the local codebase to correlate log findings with source code when investigating bugs. Use Grep and Read to find relevant code paths that correspond to log patterns.
- Be iterative: If a phase reveals something unexpected, adjust the investigation plan. Skip strategies that don't apply; repeat queries with refined parameters if needed.
Phase 1 — Reconnaissance (always runs)
Goal: Understand what's in the logs before writing targeted queries.
- Sample raw logs — Fetch 20-30 raw log entries to see the actual format:
fields @timestamp, @message
| filter @message like /{filter_pattern}/
| sort @timestamp desc
| limit 25
- Read the raw logs carefully. Identify:
- Log format (JSON, key-value, plain text?)
- Available field names and delimiters
- What
parse patterns will work
- Get message type distribution — Count unique message types:
fields @timestamp, @message
| filter @message like /{filter_pattern}/
| stats count(*) by msg
(Adapt msg to whatever field holds the message type in the actual logs)
- Check log volume over time to spot anomalies:
filter @message like /{filter_pattern}/
| stats count(*) as cnt by bin(1h)
| sort bin asc
- Classify the issue type based on logs and the issue description. Determine which category best fits:
- Error/Bug — exceptions, failures, unexpected responses
- Performance — slow responses, timeouts, high latency
- Data/Behavioral — unexpected data, wrong outputs, logic issues
- Unknown — insufficient signal, needs broader exploration
Summarize reconnaissance findings before moving on: log format, key fields, volume patterns, and issue classification.
Phase 2 — Adaptive Investigation
Goal: Based on Phase 1 findings and the issue classification, select 2-4 strategies from the table below. Explain why each strategy was chosen before executing it.
| Strategy |
When to use |
What it does |
| Error Analysis |
Errors or exceptions found in logs, or issue describes a bug |
Count errors by type, examine temporal distribution, extract stack traces |
| Performance Analysis |
Slow responses, timeouts, or latency mentioned in issue |
Parse response times, compute percentiles, find slowest operations |
| Deep Trace |
Need to understand the full lifecycle of a specific request or event |
Trace a request/correlation ID through its complete lifecycle |
| Code Correlation |
Bug or unexpected behavior, need to find root cause in source |
Read local codebase to find code paths matching log patterns, identify potential root cause |
| Entity Tracking |
Need to understand a specific user, session, or entity's experience |
Trace all activity for a given identifier over time |
| Cross-Service |
Evidence suggests the issue spans multiple services |
Fan out to other log groups using query_multi, correlate timestamps |
Error Analysis
- Filter for error-level logs, exceptions, HTTP 4xx/5xx, or failure keywords
- Count errors by type/message and bin by time intervals (5m or 15m) to find spikes
- Extract representative stack traces or error messages for the most frequent errors
Performance Analysis
- Parse response times or duration fields from logs (adapt parse pattern to Phase 1 findings)
- Compute stats: count, avg, p50, p90, p95, p99, max using
CWClient.summarize_stats()
- Identify the slowest operations and correlate with the reported issue timeline
Deep Trace
Code Correlation
- Use Grep to search the local codebase for function names, error messages, or log strings found in logs
- Read the matching source files to understand the code paths involved
- Identify potential root causes: missing error handling, race conditions, incorrect logic
Entity Tracking
- Use the filter pattern or a discovered entity ID to trace all activity over the time window
- Build a chronological timeline of events for that entity
- Identify patterns: repeated retries, long gaps, error sequences, state transitions
Cross-Service
- Identify related log groups from log content (references to other services, queue names, etc.)
- Use
cw.query_multi() to query the same time windows or correlation IDs across multiple log groups
- Correlate timestamps to determine where the issue originates and how it propagates
Phase 3 — Summary
Goal: Synthesize findings into a clear investigation summary.
Print to stdout:
- Root Cause / Hypotheses — ranked by strength of evidence. If the root cause is clear, state it directly. If inconclusive, list top hypotheses with confidence levels.
- Supporting Evidence — key log entries, patterns, and data points that support each hypothesis.
- Actionable Recommendations — concrete next steps to fix, mitigate, or further investigate.
Output
Print a concise investigation summary to stdout. If the user asks for a written report, use the RCA template at ${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/rca_template.md.
1---2name: cw-debug3description: Cw Debug4---56# /cw-debug — CloudWatch Log Investigation Skill78You are investigating a production issue using CloudWatch Logs Insights. Follow the structured methodology below, adapting queries based on what you discover in each phase.910## Arguments1112The user will invoke this skill as:13```14/cw-debug <log_group> <filter_pattern> <hours_back> <region> "<issue_description>"15```1617- `log_group`: The CloudWatch log group path (e.g., `/aws/ecs/my-service`)18- `filter_pattern`: Any string to filter logs — a user ID, request ID, service name, error code, or any identifier relevant to the investigation19- `hours_back`: How many hours of logs to search (e.g., `24`, `168` for 7 days)20- `region`: AWS region (e.g., `us-east-1`)21- `issue_description`: Free-text description of the problem being investigated (bug, performance issue, unexpected behavior, etc.)2223## Setup2425- Always use `.venv/bin/python` to run scripts26- The skill has its own self-contained CloudWatch utility at `${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/scripts/cw.py`27- **Do NOT import from `cloudwatch_utils.py`** — use the skill's own module instead28- To use in inline scripts, add the scripts dir to `sys.path` then import:29 ```python30 import sys, os31 sys.path.insert(0, os.path.expanduser("${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/scripts"))32 from cw import CWClient3334 cw = CWClient(region="{region}")35 results = cw.query("{query}", hours_back={hours_back}, log_group="{log_group}")36 cw.print_table(results)37 ```38- Or use the CLI directly:39 ```bash40 .venv/bin/python ${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/scripts/cw.py \41 --region {region} --log-group "{log_group}" --hours {hours_back} \42 --query "fields @timestamp, @message | limit 25"43 ```44- Available `CWClient` methods:45 - `cw.query(query_string, hours_back, log_group)` — single log group query46 - `cw.query_multi(query_string, hours_back, log_groups)` — query multiple log groups, merge results with `_log_group` tag47 - `CWClient.summarize_stats(results, value_field, group_field=None)` — compute count/avg/min/p50/p90/p95/p99/max from fetched results48 - `CWClient.time_bucket_counts(results, timestamp_field, bucket_minutes)` — group into time buckets for spike detection49 - `CWClient.print_table(results)` — ASCII table output50 - `CWClient.print_json(results)` — JSON output51 - `cw.save(results, name)` — save to `investigations/<name>.csv`52- Refer to `${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/query_library.md` for pre-built query templates5354## Rules5556- **Analyze before querying**: After every query result, analyze the data and explain what you found before running the next query. Never chain queries blindly.57- **Adapt parse patterns**: Phase 1 reveals the actual log format. Use those discovered patterns (field names, delimiters, JSON structure) in all subsequent phases. Do NOT assume a log format before seeing real logs.58- **Do not write files unless user explicitly asks.** Print findings to stdout. Only save CSVs or reports when the user requests it.59- **Read the local codebase to correlate log findings with source code when investigating bugs.** Use Grep and Read to find relevant code paths that correspond to log patterns.60- **Be iterative**: If a phase reveals something unexpected, adjust the investigation plan. Skip strategies that don't apply; repeat queries with refined parameters if needed.6162---6364## Phase 1 — Reconnaissance (always runs)6566**Goal**: Understand what's in the logs before writing targeted queries.67681. **Sample raw logs** — Fetch 20-30 raw log entries to see the actual format:69 ```70 fields @timestamp, @message71 | filter @message like /{filter_pattern}/72 | sort @timestamp desc73 | limit 2574 ```752. **Read the raw logs carefully**. Identify:76 - Log format (JSON, key-value, plain text?)77 - Available field names and delimiters78 - What `parse` patterns will work793. **Get message type distribution** — Count unique message types:80 ```81 fields @timestamp, @message82 | filter @message like /{filter_pattern}/83 | stats count(*) by msg84 ```85 (Adapt `msg` to whatever field holds the message type in the actual logs)864. **Check log volume over time** to spot anomalies:87 ```88 filter @message like /{filter_pattern}/89 | stats count(*) as cnt by bin(1h)90 | sort bin asc91 ```925. **Classify the issue type** based on logs and the issue description. Determine which category best fits:93 - **Error/Bug** — exceptions, failures, unexpected responses94 - **Performance** — slow responses, timeouts, high latency95 - **Data/Behavioral** — unexpected data, wrong outputs, logic issues96 - **Unknown** — insufficient signal, needs broader exploration9798Summarize reconnaissance findings before moving on: log format, key fields, volume patterns, and issue classification.99100---101102## Phase 2 — Adaptive Investigation103104**Goal**: Based on Phase 1 findings and the issue classification, select 2-4 strategies from the table below. Explain why each strategy was chosen before executing it.105106| Strategy | When to use | What it does |107|---|---|---|108| Error Analysis | Errors or exceptions found in logs, or issue describes a bug | Count errors by type, examine temporal distribution, extract stack traces |109| Performance Analysis | Slow responses, timeouts, or latency mentioned in issue | Parse response times, compute percentiles, find slowest operations |110| Deep Trace | Need to understand the full lifecycle of a specific request or event | Trace a request/correlation ID through its complete lifecycle |111| Code Correlation | Bug or unexpected behavior, need to find root cause in source | Read local codebase to find code paths matching log patterns, identify potential root cause |112| Entity Tracking | Need to understand a specific user, session, or entity's experience | Trace all activity for a given identifier over time |113| Cross-Service | Evidence suggests the issue spans multiple services | Fan out to other log groups using `query_multi`, correlate timestamps |114115### Error Analysis116- Filter for error-level logs, exceptions, HTTP 4xx/5xx, or failure keywords117- Count errors by type/message and bin by time intervals (5m or 15m) to find spikes118- Extract representative stack traces or error messages for the most frequent errors119120### Performance Analysis121- Parse response times or duration fields from logs (adapt parse pattern to Phase 1 findings)122- Compute stats: count, avg, p50, p90, p95, p99, max using `CWClient.summarize_stats()`123- Identify the slowest operations and correlate with the reported issue timeline124125### Deep Trace126- Pick 3-5 request or correlation IDs from prior findings (slowest, most errors, etc.)127- Query full lifecycle for each ID:128 ```129 fields @timestamp, @message130 | filter @message like /{request_id}/131 | sort @timestamp asc132 | limit 200133 ```134- Build a timeline of each request: identify where time was spent and what failed135136### Code Correlation137- Use Grep to search the local codebase for function names, error messages, or log strings found in logs138- Read the matching source files to understand the code paths involved139- Identify potential root causes: missing error handling, race conditions, incorrect logic140141### Entity Tracking142- Use the filter pattern or a discovered entity ID to trace all activity over the time window143- Build a chronological timeline of events for that entity144- Identify patterns: repeated retries, long gaps, error sequences, state transitions145146### Cross-Service147- Identify related log groups from log content (references to other services, queue names, etc.)148- Use `cw.query_multi()` to query the same time windows or correlation IDs across multiple log groups149- Correlate timestamps to determine where the issue originates and how it propagates150151---152153## Phase 3 — Summary154155**Goal**: Synthesize findings into a clear investigation summary.156157Print to stdout:1581591. **Root Cause / Hypotheses** — ranked by strength of evidence. If the root cause is clear, state it directly. If inconclusive, list top hypotheses with confidence levels.1602. **Supporting Evidence** — key log entries, patterns, and data points that support each hypothesis.1613. **Actionable Recommendations** — concrete next steps to fix, mitigate, or further investigate.162163---164165## Output166167Print a concise investigation summary to stdout. If the user asks for a written report, use the RCA template at `${CLAUDE_PLUGIN_ROOT}/skills/cw-debug/rca_template.md`.