log-inspection
Inspect and query hook event logs. Subcommands: sessions, timeline, trace, agents, team, stats, coverage, daily.
What this skill does
# Log Inspection
Query and inspect observability hook logs from JSONL files.
## Arguments
Subcommand is the first argument:
- **`sessions`** -- List all sessions with event counts and duration
- **`timeline [session-id]`** -- Chronological event list with seq numbers
- **`trace <tool-use-id>`** -- Show pre/post pairing for a tool invocation
- **`agents`** -- Subagent lifecycle (start/stop/duration)
- **`team`** -- TeammateIdle and TaskCompleted activity
- **`stats`** -- Aggregate statistics (event breakdown, tool usage, corruption count)
- **`coverage`** -- Which of 14 event types have been observed
- **`daily`** -- Show daily summaries from sessions-index.jsonl (v1.6.0)
## Log File Location
Look for log files at:
```text
{project}/.claude/logs/hooks/events-{YYYY-MM-DD}.jsonl
{project}/.claude/logs/hooks/events-{YYYY-MM-DD}.jsonl.gz (compressed cold logs)
```
Use Glob to find all available log files:
```text
Glob(".claude/logs/hooks/events-*.jsonl")
Glob(".claude/logs/hooks/events-*.jsonl.gz")
```
**Note:** Files older than 7 days are automatically compressed to `.jsonl.gz` (configurable via `CLAUDE_HOOK_LOG_COMPRESS_AFTER_DAYS`). DuckDB reads `.jsonl.gz` natively; use `zcat | jq` on Unix for manual inspection.
## Workflow
### Step 1: Locate Log Files
Find all hook log files in the project:
```text
Glob(".claude/logs/hooks/events-*.jsonl")
Glob(".claude/logs/hooks/events-*.jsonl.gz")
Glob(".claude/logs/hooks/sessions-index.jsonl")
```
If no log files exist, inform the user that logging must be enabled via `CLAUDE_HOOK_LOG_EVENTS_ENABLED=1`.
### Step 2: Execute Subcommand
#### `sessions`
Parse `sessions-index.jsonl` if it exists. Use the `type` field to discriminate entries (`session_start`, `session_end`, `agent_start`, `agent_stop`). For backward compatibility, entries without `type` are inferred from the presence of `started_at` (session_start) or `ended_at` (session_end). Otherwise, scan event log files for `sessionstart` and `sessionend` events. Display:
| Session ID | Started | Ended | Model | Events | Duration |
|------------|---------|-------|-------|--------|----------|
The enriched index also includes `cwd`, `transcript_path`, `model`, and `agent_type` on session_start entries.
#### `timeline [session-id]`
Read the log file and display events in seq order. If session-id is provided, filter to that session. Display:
```text
seq timestamp event tool_name pid
1 2026-02-15T18:13:23 sessionstart - 12345
2 2026-02-15T18:13:24 userpromptsubmit - 12345
3 2026-02-15T18:13:25 pretooluse Read 12346
4 2026-02-15T18:13:25 posttooluse Read 12346
```
#### `trace <tool-use-id>`
Find pretooluse and posttooluse/posttoolusefailure entries with the given tool_use_id. Display the pair showing timing and success/failure.
#### `agents`
First check `sessions-index.jsonl` for `agent_start` and `agent_stop` entries (direct lookup, no event scanning needed). Fall back to scanning event log files for `subagentstart` and `subagentstop` events if index is missing. Display:
| Agent ID | Type | Started (seq) | Stopped (seq) | Duration |
|----------|------|---------------|---------------|----------|
#### `team`
First check `sessions-index.jsonl` for `task_completed` and `teammate_idle` entries (direct lookup, added in v1.8.0). Fall back to scanning event log files for `teammateidle` and `taskcompleted` events if index entries are missing. Display:
| Time | Type | Teammate | Team | Task Subject |
|------|------|----------|------|--------------|
#### `stats`
Parse all entries and compute:
- **Event breakdown**: Count of each event type
- **Tool usage**: Most frequently used tools (from pretooluse events)
- **Error rate**: posttoolusefailure count / total tool uses
- **Avg duration_ms**: Average hook processing time
- **Corruption count**: Lines that fail JSON parsing
- **Unique sessions**: Count of distinct session_id values
- **Seq range**: Min and max seq values
Use Bash with Python one-liners for aggregation. For `.jsonl.gz` files, use `gzip.open` to read:
```bash
python3 -c "
import json, gzip, glob
from collections import Counter
events = Counter()
tools = Counter()
errors = 0
corrupt = 0
durations = []
sessions = set()
def read_lines(path):
if path.endswith('.gz'):
with gzip.open(path, 'rt', encoding='utf-8') as f:
return f.readlines()
with open(path, 'r', encoding='utf-8') as f:
return f.readlines()
for path in sorted(glob.glob('.claude/logs/hooks/events-*.jsonl') + glob.glob('.claude/logs/hooks/events-*.jsonl.gz')):
for line in read_lines(path):
line = line.strip()
if not line:
continue
try:
e = json.loads(line)
events[e.get('event','')] += 1
if 'tool_name' in e:
tools[e['tool_name']] += 1
if e.get('event') == 'posttoolusefailure':
errors += 1
durations.append(e.get('duration_ms', 0))
sessions.add(e.get('session_id',''))
except json.JSONDecodeError:
corrupt += 1
print(f'Events: {dict(events)}')
print(f'Top tools: {tools.most_common(10)}')
print(f'Error rate: {errors}/{events.get(\"pretooluse\",0)} tool uses')
print(f'Avg duration: {sum(durations)/len(durations):.2f}ms' if durations else 'No entries')
print(f'Corrupted lines: {corrupt}')
print(f'Unique sessions: {len(sessions)}')
"
```
**Note:** `hook_event_name` was removed from entries in v1.4.0 and fully suppressed from `extra_fields` in v1.7.0.
#### `coverage`
Check which of the 14 event types have been captured. Display:
```text
Event Coverage Report
=====================
[x] pretooluse (142 events)
[x] posttooluse (140 events)
[x] userpromptsubmit (8 events)
[ ] precompact (0 events)
...
Coverage: 12/14 event types observed
```
The 14 required types are: `pretooluse`, `posttooluse`, `posttoolusefailure`, `permissionrequest`, `notification`, `userpromptsubmit`, `stop`, `subagentstart`, `subagentstop`, `precompact`, `sessionstart`, `sessionend`, `teammateidle`, `taskcompleted`.
#### `daily`
Parse `sessions-index.jsonl` for `daily_summary` entries (v1.6.0). Display:
| Date | Events | Sessions | Errors | Avg Duration |
|------|--------|----------|--------|--------------|
Daily summaries are generated automatically on the first `sessionstart` of each day for the previous day's logs.
### Step 3: Format Output
Present results in a clear, readable format. Use markdown tables where appropriate. Include the log file path and date range in the header.
## DuckDB Queries (Advanced)
For large log files, suggest DuckDB for analytical queries:
```sql
-- Load JSONL directly
SELECT event, count(*) as cnt
FROM read_json_auto('.claude/logs/hooks/events-2026-02-15.jsonl')
GROUP BY event ORDER BY cnt DESC;
-- Tool usage with timing
SELECT tool_name, count(*) as uses, avg(duration_ms) as avg_ms
FROM read_json_auto('.claude/logs/hooks/events-2026-02-15.jsonl')
WHERE event = 'pretooluse'
GROUP BY tool_name ORDER BY uses DESC;
-- Find corrupted entries (seq gaps)
SELECT seq, lag(seq) OVER (ORDER BY seq) as prev_seq
FROM read_json_auto('.claude/logs/hooks/events-2026-02-15.jsonl')
WHERE seq - lag(seq) OVER (ORDER BY seq) > 1;
```
## Usage Examples
```bash
# List sessions
/claude-code-observability:log-inspection sessions
# Timeline for current session
/claude-code-observability:log-inspection timeline
# Trace a specific tool call
/claude-code-observability:log-inspection trace toolu_01abc123
# Event type coverage
/claude-code-observability:log-inspection coverage
# Full statistics
/claude-code-observability:log-inspection stats
```
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.