template/.claude/skills/analyze-logs/SKILL.md
Analyze application logs from the .evlog/logs/ directory. Use when debugging errors, investigating slow requests, understanding request patterns, or answering questions about application behavior. Reads structured NDJSON wide events written by evlog's file system drain.
npx skillsauth add charles5277/nuxt-supabase-starter analyze-logsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Read and analyze structured wide-event logs from the local .evlog/logs/ directory to debug errors, investigate performance issues, and understand application behavior.
Logs are written by evlog's file system drain as .jsonl files, organized by date.
Format detection: The drain supports two modes:
pretty: false): One compact JSON object per line. Parse line-by-line.pretty: true): Multi-line indented JSON per event. Parse by reading the entire file and splitting on top-level objects (e.g. JSON.parse('[' + content.replace(/\}\n\{/g, '},{') + ']')) or use a streaming JSON parser.Always check the first few bytes of the file to detect the format: if the second character is a newline or ", it's NDJSON; if it's a space or newline followed by spaces, it's pretty-printed.
Search order — check these locations relative to the project root:
.evlog/logs/ (default).evlog/logs/ inside app directories (monorepos: apps/*/.evlog/logs/)Use glob to find log files:
.evlog/logs/*.jsonl
*/.evlog/logs/*.jsonl
apps/*/.evlog/logs/*.jsonl
Files are named by date: 2026-03-14.jsonl. Start with the most recent file.
The file system drain may not be enabled. Guide the user to set it up:
import { createFsDrain } from 'evlog/fs'
// Nuxt / Nitro: server/plugins/evlog-drain.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog:drain', createFsDrain())
})
// Hono / Express / Elysia: pass in middleware options
app.use(evlog({ drain: createFsDrain() }))
// Fastify: pass in plugin options
await app.register(evlog, { drain: createFsDrain() })
// NestJS: pass in module options
EvlogModule.forRoot({ drain: createFsDrain() })
// Standalone: pass to initLogger
initLogger({ drain: createFsDrain() })
After setup, the user needs to trigger some requests to generate logs, then re-analyze.
Each line is a self-contained JSON object (wide event). Key fields:
| Field | Type | Description |
| ---------------- | -------- | --------------------------------------------------------------- |
| timestamp | string | ISO 8601 timestamp |
| level | string | info, warn, error, debug |
| service | string | Service name |
| environment | string | development, production, etc. |
| method | string | HTTP method (GET, POST, etc.) |
| path | string | Request path (/api/checkout) |
| status | number | HTTP response status code |
| duration | string | Request duration ("234ms") |
| requestId | string | Unique request identifier |
| error | object | Error details: name, message, stack, statusCode, data |
| error.data.why | string | Human-readable explanation of what went wrong |
| error.data.fix | string | Suggested fix for the error |
| source | string | client for browser logs, absent for server logs |
| userAgent | object | Parsed browser/OS/device info |
All other fields are application-specific context added via log.set() (e.g. user, cart, payment).
Read the latest .jsonl file. Each line is one JSON event. Parse each line independently.
Filter based on the user's question:
"level":"error" or status >= 400pathduration (e.g. "706ms") and filter high values"source":"client"timestamp valuesFor each relevant event:
path, method, status, levelerror.message, error.data.why, and the stack traceerror.data.fix for suggested remediationFilter: level === "error"
Group by: error.message or path
Look for: recurring patterns, common failure modes
Filter: parse duration string, compare > threshold (e.g. 1000ms)
Sort by: duration descending
Look for: specific endpoints, time-of-day patterns
Filter: requestId === "the-request-id"
Result: single wide event with all context for that request
Group events by: path
Count: total events vs error events per path
Look for: endpoints with high error ratios
Split by: source === "client" vs no source field
Compare: error patterns between client and server
Look for: client errors that don't have corresponding server errors (network issues)
error.data.why and error.data.fix fields are evlog-specific structured error fields. When present, they provide the most actionable information."706ms"). Parse the numeric part for comparisons."source":"client" originated from browser-side logging and were sent to the server via the transport endpoint..gitignore'd automatically — they exist only on the local machine or server where the app runs.development
Pinia official Vue state management library, type-safe and extensible. Use when defining stores, working with state/getters/actions, or implementing store patterns in Vue apps.
development
Pinia Store 架構規範。Use when creating app/stores/**/*.ts files, working with defineStore, managing global state, or building Pinia stores. Always use this skill for store design patterns, naming conventions, and state management architecture.
tools
Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or scroll-driven reveals — make users ask "how did they do that?"
content-media
Improve interface performance across loading speed, rendering, animations, images, and bundle size. Makes experiences faster and smoother.