| name | slog |
| description | Structured logging workflow for debugging code paths with per-run JSONL log files. Use when the user says "use slog", asks for structured logging, wants to instrument a flow, run it, and inspect logs. Triggers on requests like "use slog", "add structured logs", "log this flow", or "debug with slog".
|
Structured Logging with slog
Debug or verify a concrete code path by writing newline-delimited JSON logs to a run-specific file, exercising the path, and reading the output.
Default workflow
- Create a fresh run file (never reuse the previous one):
bun <skill-path>/scripts/slog.ts new signup-before-fix
- The helper writes
.context/slog/current.env. If your dev scripts source this file, a service restart picks up the new slog target automatically.
- For one-shot commands, export the printed
SLOG_FILE, SLOG_RUN_ID, and SLOG_LABEL values directly.
- Add focused structured logs near decisions, boundaries, and surprising state changes.
- Trigger the code path yourself when possible.
- Read the log file and summarize what changed.
- For the next run, mint a new file name again.
Verification loop:
- Form a hypothesis about the current or expected behavior.
- Mint a fresh slog run.
- Add focused logs around the branch or boundary that proves or disproves the hypothesis.
- Exercise the real path.
- Read the slog file and confirm what happened.
Per-run file naming
Files are created in .context/slog/:
.context/slog/20260402T193501Z-a1b2c3d-dirty-signup-before-fix.jsonl
Captures: timestamp, git SHA, dirty/clean state, and human label.
Standard log shape
Use JSONL. One JSON object per line with stable keys:
{
"ts": "2026-04-02T19:35:01.123Z",
"runId": "20260402T193501Z-a1b2c3d-dirty-signup-before-fix",
"source": "src/server/example.ts",
"event": "signup.user-created",
"step": "after-insert",
"data": { "userId": "123", "workspaceId": "456" }
}
Rules:
- Keep keys stable across runs so diffs are meaningful.
- Prefer small scalar fields and shallow objects.
- Do not log secrets, tokens, cookies, or raw auth headers.
- Include IDs, counts, branch decisions, and error summaries.
TypeScript helper pattern
Drop this into the code path under investigation:
import fs from "node:fs";
import path from "node:path";
function appendSlog(
source: string,
event: string,
data: Record<string, unknown> = {},
step?: string,
): void {
const file = process.env.SLOG_FILE;
if (!file) return;
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.appendFileSync(
file,
JSON.stringify({
ts: new Date().toISOString(),
runId: process.env.SLOG_RUN_ID ?? "manual",
source,
event,
step,
data,
}) + "\n",
);
}
Guidance:
- Add logs at system boundaries: request entry, parsed input, DB read/write, branch selection, downstream call, returned output, caught error.
- If the code already uses a logger, keep it. Add file logging alongside only for the investigation.
- Remove temporary instrumentation after the session unless the user wants to keep it.
Triggering the code path
After instrumenting, try to run the path yourself. Preferred order:
- Existing unit or integration test
- Small targeted script
- Existing CLI command
- Local HTTP request
- Browser automation
If you cannot trigger it directly, give the user exact steps including: the command to create a run, whether services need a restart, the action to perform, and the command to read logs afterward.
Reading logs
bun <skill-path>/scripts/slog.ts latest
bun <skill-path>/scripts/slog.ts latest file
bun <skill-path>/scripts/slog.ts list
Useful follow-ups:
tail -n 200 "$(bun <skill-path>/scripts/slog.ts latest file)"
jq -c . "$(bun <skill-path>/scripts/slog.ts latest file)"
rg '"event"' "$(bun <skill-path>/scripts/slog.ts latest file)"
Comparing runs
- Create a new run with a label capturing the hypothesis (
before-null-guard, after-parse-fix).
- Keep the old file.
- Compare normalized outputs:
jq -S . .context/slog/run-a.jsonl > /tmp/run-a.jsonl
jq -S . .context/slog/run-b.jsonl > /tmp/run-b.jsonl
diff -u /tmp/run-a.jsonl /tmp/run-b.jsonl
Completion standard
Do not stop after adding logs. The full workflow is:
- Create a new run file
- Instrument the code path
- Run the path if possible
- Read the file
- Explain what the logs say
If step 3 is impossible, explicitly say what the user needs to do manually.