| name | logging-enablement |
| description | Set up structured JSONL logging in a codebase for both production code and test frameworks (unit tests, integration tests). Supports C#, JavaScript/TypeScript, Python, and Rust. Use when asked to "add logging", "set up structured logging", "enable test logging", "make this debuggable", "add JSONL logging", "configure log output", "instrument this code with logs", "fix unit test logging", "set up test framework logging", "add logging to tests", "replace Console.WriteLine in tests", or "configure xUnit/NUnit/MSTest/Jest/Vitest/pytest logging". NOT for debugging issues (use debug-with-logs) or reviewing logging quality (use logging-review agent).
|
| user-invocable | true |
| disable-model-invocation | false |
| allowed-tools | Read, Grep, Glob, Bash, Edit, Write |
Logging Enablement
Set up structured JSONL logging in a codebase so it's ready for log-first debugging.
When to Use
- Adding structured logging to a codebase that doesn't have it
- Converting
Console.WriteLine / print() / console.log() to structured logging
- Setting up test harness logging with test context enrichment
- Configuring JSONL file output for log querying
When NOT to Use
- Debugging an issue → Use
debug-with-logs skill
- Reviewing logging in a PR → Use
logging-review agent
Workflow
Step 1: Detect Language and Frameworks
Scan the codebase to determine:
-
Primary language(s): Look for project files
.csproj / .sln → C#
package.json → JavaScript/TypeScript
pyproject.toml / setup.py / requirements.txt → Python
Cargo.toml → Rust
-
Test framework(s): Look for test configuration
- C#:
xunit / NUnit / MSTest references in .csproj
- JS/TS:
jest.config.* / vitest.config.* / .mocharc.*
- Python:
pytest.ini / conftest.py / unittest imports
- Rust:
#[cfg(test)] blocks, tests/ directory
-
Existing logging: Check for current logging setup
- Grep for logging library imports/usages
- Check for any log configuration files
- Note any
Console.Write / print() / console.log usage
Step 2: Audit Current Logging State
Classify the codebase into one of:
| State | Description | Action |
|---|
| No logging | No logging library, uses print/console | Full enablement needed |
| Unstructured logging | Has logging library but text format | Configure JSONL formatter |
| Structured but not JSONL | JSON logging but missing canonical fields | Align field names |
| Already compliant | JSONL with canonical fields | Verify and skip |
Step 3: Apply Enablement
Read the appropriate language-specific reference guide:
For each guide, follow:
- Install required packages
- Configure the logger with JSONL output
- Set up canonical field names per log-render-spec.md
- Add test context enrichment (for test projects)
- Add example log statements at key decision points
- For client/browser projects, configure log forwarding to a server backend and add
source: "client" field to every log entry
Step 4: Verify with DuckDB
After enablement, verify the logging output is queryable:
- Run the application or tests to generate log output
- Query the JSONL file with DuckDB:
SELECT "@t", "@l", "@logger", "@m"
FROM read_json_auto('app.log.jsonl')
LIMIT 5;
SELECT "test-case-name", "test-module-name", "@m"
FROM read_json_auto('test-results.log.jsonl')
WHERE "test-case-name" IS NOT NULL
LIMIT 5;
- Confirm:
Key Decisions
Which logging library?
Use whatever the project already uses. If starting fresh, prefer:
| Language | Recommended | Why |
|---|
| C# | Serilog | Native CompactJsonFormatter produces canonical @t/@l/@m |
| JS/TS | Pino | Fastest, native JSON output, minimal config |
| Python | structlog | Composable processors, clean JSON output |
| Rust | tracing + tracing-subscriber | Ecosystem standard, JSON layer available |
Where to log?
Add logging at decision points — places where the code chooses a path:
- Conditional branches (
if/else, switch)
- Error handling (
catch, error returns)
- External calls (DB queries, HTTP requests, message sends)
- State transitions (status changes, mode switches)
- Loop boundaries (entering/exiting, iteration counts)
What level?
See log-format-spec.md for the full level guide. Quick rule:
- Trace: Breakpoint-level — variable values, intermediate state, debugger-equivalent. EUII permitted (stripped from release builds).
- Debug: OCE area identification — positive handshakes narrowing WHERE, not WHAT. EUII forbidden.
- Information: Production bug sequence — execution flow, event timeline reconstruction. EUII forbidden.
- Warning: Unexpected but recoverable — retry, fallback, degraded mode. EUII forbidden.
- Error: Operation failure, recoverable at higher level. EUII forbidden.
- Fatal: Unrecoverable, immediate attention required. EUII forbidden.
EUII Policy
- Trace only — EUII is permitted because Trace is stripped from release builds
- Forbidden at Debug+ — these levels persist in production
- Practical guidance: if a log template includes email, user name, display name, IP, phone number, or session/auth token, it must be Trace-level or the EUII must be removed
Reference Files
- Log Render Spec — Canonical field names (shared spec)
- Language-specific guides in
reference/{language}/