JSON File Channel
JSONFileLog is a drop-in replacement for FileLog that writes structured JSON instead of plain text. Every entry is a typed object — no regex parsing at query time.
import { JSONFileLog } from "@warlock.js/logger";
const channel = new JSONFileLog({ storagePath: process.cwd() + "/storage/logs", chunk: "daily",});File format
Section titled “File format”The extension is always json, regardless of the extension option. Each file is a JSON object with a messages array:
{ "messages": [ { "content": "New user created", "level": "info", "date": "15-03-2024 10:22:01", "module": "users", "action": "register" }, { "content": "Card declined", "level": "error", "date": "15-03-2024 10:22:03", "module": "payments", "action": "charge", "stack": [ "Error: Card declined", " at chargeCard (/app/src/payments.ts:42:11)", " at processTicksAndRejections (node:internal/process/task_queues:95:5)" ] } ]}Differences from FileLog
Section titled “Differences from FileLog”| Aspect | FileLog | JSONFileLog |
|---|---|---|
| Output format | Plain-text lines | JSON object with messages array |
| Error stack | Raw multi-line string after [trace] | Split on newlines, stored as string[] in stack |
| Message field | Pre-formatted log line | content field holds the original string |
| File extension | Configurable (default "log") | Always "json" |
It inherits every FileLog option and supports the same chunking, rotation, and groupBy features.
Safe serialization
Section titled “Safe serialization”JSONFileLog writes through safe-stable-stringify (the same library Pino and Winston use), so the context payload can carry shapes that would otherwise throw in JSON.stringify:
| Shape | Serialized as |
|---|---|
| Circular reference | handled (no throw) |
BigInt | stringified value |
Function / symbol | dropped (standard JSON behavior) |
Error (top-level or nested in context) | { name, message, stack, ...enumerableProps } |
| Class instance | enumerable own properties — same as default JSON |
The channel does not tag class instances with their class name. If you need a specific shape, pre-shape the value before passing it to context:
await log.error("orders", "checkout", "Card declined", { order: { id: order.id, status: order.status }, // not the full Order instance declineReason,});