@aryan-vashishth/advanced-logger 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,322 @@
1
+ # advanced-logger: architecture (A to Z)
2
+
3
+ Package: `@aryan-vashishth/advanced-logger` (version in `package.json`).
4
+ A TypeScript logger for Playwright test projects. It is a port of the Java `core.logging` package ("VOID") with additions.
5
+ Runtime dependencies: none. `@playwright/test` is an optional peer dependency, needed only by the `/playwright` entry.
6
+
7
+ This document describes the code as it is. File and symbol names are exact. Behavior claims are backed by tests in `test/`.
8
+
9
+ ---
10
+
11
+ ## 1. What it does, in one paragraph
12
+
13
+ Test code calls `info.click('Submit')`, `warn.log('x')`, `error.table(rows)` and so on. Every call goes through one function (`dispatch` in `src/core.ts`), which builds a `LogEvent` and hands it to a list of sinks. Sinks write to the console (colored), to three plain-text trace files, optionally to a JSONL file, to an in-memory buffer (used to attach the log to a Playwright report on failure), and to any custom sink. Configuration comes from four layers (defaults, config file, env vars, `configure()` calls). Each Playwright worker is a separate process with its own logger state, writing its own files.
14
+
15
+ ## 2. Repository layout
16
+
17
+ ```
18
+ src/
19
+ index.ts public API barrel (main entry)
20
+ playwright.ts Playwright entry: `test` (with auto fixture), `expect`, `initRun`
21
+ logger.ts the four level instances: debug, info, warn, error
22
+ actions.ts LogActions class (all action methods), fields(), formatValue()
23
+ core.ts dispatch(): the single funnel; INFO truncation; themed(); test context
24
+ config.ts LogConfig, defaults, layered build, configure(), env parsing, run id
25
+ configFile.ts logger.config.* discovery, loading, validation
26
+ theme.ts LogIntent, the one built-in theme, resolveStyle()
27
+ ansi.ts escape-code factory, color catalog, stripAnsi
28
+ caller.ts stack parsing: "caller" suffix and "[CHAIN]"
29
+ sinks.ts Sink interface, built-in sinks, file writing, retention, registry
30
+ test/
31
+ logger.test.ts, logger.aggressive.test.ts core behavior (vitest)
32
+ colors.test.ts fg/bg/ansi/callerColor matrix
33
+ config-file.test.ts discovery, forms, precedence, failures
34
+ truncate.test.ts infoLogsCharLimit + its hint
35
+ retention.test.ts maxRuns, maxLogFiles, recent/missing-run-id guards
36
+ separable.test.ts consoleWorker, consoleTest, missing initRun() warning, configure() validation
37
+ multi-worker.test.ts spawns real Playwright with 2 workers (fixtures/multi-worker/)
38
+ *.spec.ts, playwright*.config.ts, global-setup.ts Playwright e2e/demo specs
39
+ dist/ tsc output (CommonJS, ES2022), gitignored, what npm publishes
40
+ ```
41
+
42
+ Build: `tsc -p tsconfig.build.json` (module CommonJS, moduleResolution Node10, declarations + source maps, rootDir `src`). `prepare` runs the build on `npm install`/publish. Tests: `npm run test:unit` (vitest, `test/**/*.test.ts`), `npm run test:e2e` (Playwright, 2 workers, `test/*.spec.ts`, fixtures ignored), `npm test` runs both.
43
+
44
+ Published entry points (`package.json` `exports`):
45
+
46
+ | Import path | File | Purpose |
47
+ |---|---|---|
48
+ | `@aryan-vashishth/advanced-logger` | `dist/index.js` | `info/warn/error/debug`, `configure`, `defineConfig`, helpers |
49
+ | `@aryan-vashishth/advanced-logger/playwright` | `dist/playwright.js` | drop-in `test`/`expect` with logging fixture |
50
+
51
+ ## 3. Module dependency graph
52
+
53
+ ```
54
+ index.ts ──► logger ──► actions ──► core ──► caller
55
+ │ │ ├────► sinks
56
+ │ │ └────► theme
57
+ ├──► config ◄──────────────┐
58
+ └──► theme, ansi │
59
+ config ──► configFile (runtime) theme ──► config (runtime, reads fg/bg)
60
+ config ──► theme (type only) configFile ──► config (types only)
61
+ sinks ──► config, theme, ansi caller ──► config (type only)
62
+ playwright ──► config, core, sinks, logger
63
+ ```
64
+
65
+ Two potential cycles are deliberately broken with `import type`: `config.ts` imports only the *type* `LevelName` from `theme.ts`, and `configFile.ts` imports only *types* from `config.ts`. `theme.ts` imports `config()` at runtime (to read `fg`/`bg`). Do not add runtime imports in the other direction.
66
+
67
+ ## 4. The call path (the most important flow)
68
+
69
+ ```
70
+ info.click('Submit') actions.ts LogActions.click
71
+ └► this.msg(LogIntent.INTERACTION, 'CLICK [>]', m)
72
+ └► dispatch('INFO', intent, themed(level,intent), label, str(m)) core.ts
73
+ 1. cfg = config() (lazy build on first call, see §6)
74
+ 2. INFO truncation branch (see §9) may emit 3 events and return
75
+ 3. emit(...):
76
+ a. sinks = activeSinks().filter(s => s.accepts(level, cfg))
77
+ b. if none accept: return (no stack is ever captured)
78
+ c. resolveCaller(cfg) caller.ts: parse new Error().stack
79
+ d. build LogEvent {time, ts, level, intent, label, message, color,
80
+ caller, chain, worker, test}
81
+ e. for each sink: try { sink.write(ev, cfg) } catch -> one stderr line
82
+ ```
83
+
84
+ Key properties:
85
+
86
+ - **Single funnel.** Everything (actions, tables, trees, Playwright fixture banner lines) ends in `dispatch`. Cross-cutting features (truncation) live there.
87
+ - **Cheap rejection first.** `Sink.accepts(level, cfg)` runs before any stack capture, which is the expensive part. If the root level hides the line and file sinks are off, no stack is captured.
88
+ - **A logger never fails a test.** A throwing sink is caught and reported once per call on stderr. The one deliberate exception is a broken config file (see §7), which throws.
89
+ - **Color is baked at call time.** `themed()` computes the escape prefix when the action is called and stores it in `LogEvent.color`. Sinks do not recompute it.
90
+
91
+ ### Level instances and actions
92
+
93
+ `logger.ts` exports four `LogActions` instances: `debug`, `info`, `warn`, `error`. `LogActions` (`actions.ts`) has one method per action, each a thin wrapper `this.msg(intent, label, message)`:
94
+
95
+ | Intent | Methods (label) |
96
+ |---|---|
97
+ | INTERACTION | click, checkbox, text, input, dropdown, toggle, upload, hover, clear, key, password (masked) |
98
+ | NAVIGATION | navigate, tab, frame, breadcrumb |
99
+ | OBSERVE | wait, search, result |
100
+ | VERIFY | verifying |
101
+ | SUCCESS | success, complete, resolved |
102
+ | ALERT | error, failed, timeout, validation, fallback, skip |
103
+ | DATA | grid, table, row |
104
+ | BASE | log, tree |
105
+
106
+ Composite methods:
107
+
108
+ - `log(...)` is overloaded: string; object/array/map (table or indexed list); `(heading, fields)` or `(heading, k, v, ...)` (tree); `(heading, value)`.
109
+ - `table(rows, title?)` renders an ASCII table through `renderTable`, then calls `dispatch(level, null, color, 'TABLE', ...)` with **intent `null`** (a pre-colored block). `table("text")` is just a TABLE line.
110
+ - `row`, `tree`, `resolved` emit several `msg()` lines (one `dispatch` each).
111
+ - Redaction: values whose key contains any of `redactKeys` (case-insensitive substring) print as `***` in tree/table/row.
112
+ - Malformed arguments never throw (`safeFields` keeps a dangling key under `(unpaired)`); `fields()` itself throws on an odd count by design.
113
+
114
+ ## 5. The event model
115
+
116
+ ```ts
117
+ interface LogEvent {
118
+ time: Date; ts: string; // ts is pre-formatted via cfg.tsFormat
119
+ level: 'DEBUG'|'INFO'|'WARN'|'ERROR';
120
+ intent: LogIntent | null; // null = pre-colored block (table)
121
+ label: string; // e.g. 'CLICK [>]', 'INFO', 'TABLE'
122
+ message: string; // may be multi-line
123
+ color: string; // resolved ANSI prefix; '' means none
124
+ caller: string; // "Callee.method ← Caller.method", plain text
125
+ chain: string; // in-project call chain, leaf first, plain text
126
+ worker: string; // 'w<TEST_WORKER_INDEX>' or 'main'
127
+ test?: string; // full title path, set by the Playwright fixture (jsonl)
128
+ testTitle?: string; // the test's own title (consoleTest prefix)
129
+ }
130
+ interface Sink { accepts(level, cfg): boolean; write(ev, cfg): void }
131
+ ```
132
+
133
+ Rendered line shape: `<ts> │ <label> │ <message line>` where `│` is `cfg.segmentDivider`. Multi-line messages are split on a Java-`\R`-equivalent regex (`LINE_BREAKS`) and each line gets its own prefix.
134
+
135
+ ## 6. Configuration
136
+
137
+ ### 6.1 `LogConfig` (every option)
138
+
139
+ | Option | Type / default | Meaning |
140
+ |---|---|---|
141
+ | `level` | `'debug'\|'info'\|'warn'\|'error'\|'off'`, `info` | Root threshold for console + partial-trace |
142
+ | `ansi` | bool, auto-detected | Master color switch. `false` overrides `fg`, `bg`, `callerColor` |
143
+ | `fg` | bool, `true` | Foreground colors (intent color; level color on BASE lines; bold) |
144
+ | `bg` | bool, `true` | The theme background (one constant, `BG_BLACK`, for all levels) |
145
+ | `callerColor` | bool, `false` | Color the caller suffix separately (console, debug level). Independent of fg/bg |
146
+ | `infoLogsCharLimit` | number\|null, `null` | INFO truncation limit (§11). null/0 = off |
147
+ | `maxRuns` | number\|null, `null` | Retention per trace kind, in whole runs (§12). null/0 = off |
148
+ | `maxLogFiles` | number\|null, `null` | Retention per trace kind, in files (§12). null/0 = off |
149
+ | `consoleWorker` | bool, `false` | Console lines prefixed `w<N> │ ` (§9) |
150
+ | `consoleTest` | bool, `false` | Console lines prefixed with the test title, max 40 chars (§9) |
151
+ | `tsFormat` | string\|fn, `yyyy-MM-dd HH:mm:ss.SSS` | Java-style pattern or `(Date)=>string` |
152
+ | `segmentDivider` | string, `' │ '` | Column separator |
153
+ | `tableCellLimit`, `tableCellLimitEnabled` | 40, false | Truncate table/row cells |
154
+ | `suppressContains`, `suppressMethodPrefixes`, `includeOnlyPrefixes` | Sets | Caller/chain frame filters (§8) |
155
+ | `projectRoots` | string[], `[cwd]` | Frames under these form the `[CHAIN]` |
156
+ | `console` | bool, true | Console sink on/off |
157
+ | `files` | `{debugTrace, partialTrace, fullTrace, jsonl}` | Per-file toggles (jsonl default false) |
158
+ | `logDir` | string, `./logs` | Output root |
159
+ | `githubAnnotations` | bool, `GITHUB_ACTIONS==='true'` | Emit `::error::`/`::warning::` lines |
160
+ | `redactKeys` | string[] | Keys masked in structured output |
161
+ | `attach` | `'on-failure'\|'always'\|'never'` | Playwright attachment policy |
162
+
163
+ `LogConfigPatch` = `Partial<LogConfig>` with the Set-typed fields accepting any iterable and `files` partial. It is the type `configure()` and config files accept.
164
+
165
+ ### 6.2 Layers and precedence (lowest to highest)
166
+
167
+ 1. **Built-in defaults**: `builtinDefaults(env)` in `config.ts`. Only terminal/CI heuristics for `ansi` and `GITHUB_ACTIONS` for annotations read the environment here.
168
+ 2. **Config file** (`logger.config.*`, §7).
169
+ 3. **Environment variables**: `applyEnv()`.
170
+ 4. **`configure()` calls** in code mutate the live object afterwards, so they always win.
171
+
172
+ Environment variables: `VOID_LOG_LEVEL`, `VOID_LOG_DIR`, `VOID_LOG_ANSI`, `VOID_LOG_FG`, `VOID_LOG_BG`, `VOID_LOG_JSONL`, `VOID_LOG_INFO_LOGS_CHAR_LIMIT`, `VOID_LOG_MAX_RUNS`, `VOID_LOG_MAX_FILES`, `VOID_LOG_CONFIG`, `VOID_RUN_ID`, `VOID_RUN_DATE`, plus `NO_COLOR` / `FORCE_COLOR`. Booleans: `1/true/yes/on` true, anything else non-empty false. An invalid level or non-numeric limit is ignored (so it cannot override a lower layer). `NO_COLOR`/`FORCE_COLOR` count as env-level (they beat `ansi` in a file); terminal auto-detection counts as default-level (the file beats it). See `explicitAnsi()` vs `heuristicAnsi()`.
173
+
174
+ ### 6.3 Lazy, per-process state
175
+
176
+ `config.ts` holds module state `CURRENT: LogConfig | undefined`.
177
+
178
+ - `config()` returns `CURRENT ?? build()`. The first call in a process builds the config (including reading the config file). Every process, including each Playwright worker, does this independently.
179
+ - `build()` sets `CURRENT = cfg` early as a **re-entrancy guard**: a config file that imports this package and touches `config()` while loading sees the defaults instead of recursing. On failure it sets `CURRENT = undefined` and rethrows, so every later call throws again (no silent fallback to defaults).
180
+ - `configure(patch | fn)`, the `enable*/disable*` mutators, and every internal reader go through `config()`, so they trigger the load first. Therefore a `configure()` call made before any log call still sits above the file.
181
+ - `configure(patch)` runs the patch through `checkPatch` (the config file's validator, §7) with the source label `configure()`. Unlike a file, it never throws: each problem is written to stderr once per process (`WARNED`, cleared by `resetConfig()`) and that key is left out; the rest applies. A non-object patch warns and is ignored. The callback form is not checked.
182
+ - `resetConfig()` clears `CURRENT`, forgets the cached config file (`forgetConfigFile()` deletes it from `require.cache`), and rebuilds. Used by tests.
183
+ - A mutable `LIMIT_SOURCE` records which layer set `infoLogsCharLimit` (`default|file|env|code`) for the truncation hint.
184
+
185
+ **Process model consequence** (verified by `multi-worker.test.ts`): `configure()` inside Playwright's `globalSetup` runs in the runner process and does **not** reach workers. Only env vars are inherited. That is why `initRun()` communicates through `process.env.VOID_RUN_ID`/`VOID_RUN_DATE`, and why the config file exists.
186
+
187
+ ## 7. Config file loading (`configFile.ts`)
188
+
189
+ - Discovery in `process.cwd()`: `logger.config.ts`, `.js`, `.cjs`, `.json`, first existing wins (`CONFIG_FILE_NAMES`). No file: silently fine, behavior identical to 0.1.0.
190
+ - `VOID_LOG_CONFIG` overrides the path (resolved against cwd). An explicit path that does not exist **throws** (deliberate: a typo should not be silent).
191
+ - Loaded with a lazy `require(file)` inside `loadConfigFile`. Under Playwright, its TypeScript hook transpiles `.ts`; under plain Node, type stripping or CJS handles it. No transpiler dependency. `unwrapDefault` handles `__esModule` interop (`export default`), `module.exports =`, and JSON.
192
+ - Forms: a plain object (`LogConfigPatch`) or `(config: LogConfig) => LogConfigPatch`. The function receives a **clone** of the defaults (`cloneConfig`), so it cannot mutate live state. `defineConfig()` is an identity helper for typing.
193
+ - Validation (table `KEYS`): `checkPatch(value, where)` returns the clean patch plus one message per problem (unknown option name, such as a typo like `levl`; wrong type; bad `files` sub-key), and drops `undefined` values. `validatePatch` throws the first problem for a file; `configure()` warns about each one instead (§6.3). File error messages contain the absolute file path; load failures (`fail()`) wrap the original in `cause`.
194
+ - Loaded once per process (Node's require cache plus `CURRENT`). `loadedConfigFile()` exposes the path for messages.
195
+
196
+ ## 8. Caller and chain resolution (`caller.ts`)
197
+
198
+ Parses `new Error().stack` (limit raised to 60 temporarily) with `FRAME_RE`. `displayName()` turns frames into readable names:
199
+
200
+ - `Class.method` when V8 reports a type (instance, static, async, class-field arrow all verified); `Class.(constructor)` for `new`.
201
+ - Free functions and plain-object types (`Object`, `Module`, `Function`, ...) become `<fileBase>.<function>`.
202
+ - Frames inside the logger's own folder (`SELF_DIR`, computed at load from this file's path) are always dropped. This replaces the Java logger's method-name-prefix suppression, so user methods like `login()` are not hidden.
203
+
204
+ Two outputs:
205
+
206
+ - `caller`: first surviving frame is the callee, the next frame with a different display name is the caller: `Callee ← Caller`.
207
+ - `chain`: every surviving frame under `projectRoots` (excluding `node_modules`/`node:`), consecutive duplicates collapsed, leaf first, joined by ` ← `.
208
+
209
+ Filters: `suppressMethodPrefixes`, `includeOnlyPrefixes` (path or display prefix), `suppressContains` (default `node_modules`, `node:`, `<anonymous>`).
210
+
211
+ If the chain comes out empty, `projectRoots` does not cover the test code; set `configure({ projectRoots: [__dirname] })`.
212
+
213
+ ## 9. Output sinks (`sinks.ts`)
214
+
215
+ `activeSinks()` returns, in order: console, partial-trace, debug-trace, full-trace, jsonl, capture, then custom sinks (`addSink`/`removeSink`).
216
+
217
+ | Sink | accepts | Content |
218
+ |---|---|---|
219
+ | console | `cfg.console` and level ≥ root | Colored line; caller suffix only when root level is `debug` |
220
+ | partial-trace | file toggle and level ≥ root | Same lines as console, plain text |
221
+ | debug-trace | file toggle, **all levels** | Plain text + caller suffix |
222
+ | full-trace | file toggle, **all levels** | Plain text + `[CHAIN] <chain>` suffix |
223
+ | jsonl | `files.jsonl` | One JSON record per event (opt-in) |
224
+ | capture | an active capture exists and level ≥ root | In-memory lines for the Playwright attachment |
225
+
226
+ Files: `<logDir>/<runDate>/<kind>/<kind>-<runId>-<worker>.log` (`traceFilePath`). Writes are **synchronous** (`fs.writeSync` on cached fds in `FD_CACHE`), one file per worker, so parallel workers never interleave and a crash loses nothing. Every file line is prefixed `w<N> │ ` and passes through `stripAnsi`, so **plain-text sinks never contain escape codes** regardless of color flags. `closeAllFiles()` closes fds (and clears prune bookkeeping).
227
+
228
+ Console rendering (`consoleSink`):
229
+ - Opt-in prefix (`consolePrefix`), placed before the timestamp and inside the color block: `w<N> │ ` when `consoleWorker`, then `<testTitle> │ ` when `consoleTest` and a test is running (line breaks flattened, cut to `TEST_TAG_MAX` = 40 chars with `...`). The worker part uses a literal ` │ `, like the file prefix, not `segmentDivider`. The GitHub annotation text carries the same prefix. File sinks do not use it: they are already per worker, and tests are bracketed by `TEST START`/`TEST END`.
230
+ - `ansi` off: plain.
231
+ - `ansi` on: `wrap(s) = ev.color ? ev.color + s + RESET : s`. When `fg` and `bg` are both off, `ev.color` is `''` and the body is bare (no stray reset).
232
+ - `callerColor` on and a caller exists: body wrapped, then `div + CALLER_FG + caller + RESET`. Not gated by `fg`/`bg`; only `ansi:false` silences it.
233
+ - `githubAnnotations`: after each line, `::error::`/`::warning::` for ERROR/ALERT/WARN events.
234
+
235
+ ## 10. Color model (`theme.ts`, `ansi.ts`)
236
+
237
+ One built-in theme (HIGH_CONTRAST). `resolveStyle(level, intent)` = foreground + background:
238
+
239
+ - Foreground: for `BASE` intent, `LEVEL_FG[level]` (white, amber, red, grey, all bold); otherwise `INTENT_FG[intent]`.
240
+ - Background: constant `BG_BLACK` for every level (there is no per-level background).
241
+ - `config().fg` false drops the foreground part; `config().bg` false drops the background; both false returns `''`.
242
+ - `themed(level, intent)` in `core.ts` returns `''` when `ansi` is off, else `resolveStyle`.
243
+ - Tables build their own bold/reset around the title; those are emitted only when a style exists and `fg` is on (bold belongs to the foreground).
244
+
245
+ `ansi.ts` is a catalog and factory (`sgr`, `fg16`, `rgbFg`, ... named `FG_*`, `BG_*`, `RGB_FG`, ...), plus `stripAnsi` and `fgFromStyle`.
246
+
247
+ ## 11. INFO truncation (`infoLogsCharLimit`, in `dispatch`)
248
+
249
+ Condition: `level==='INFO'`, `intent !== null` (tables excluded; they have `tableCellLimit`), limit > 0, message longer than the limit, and INFO is visible at the root level (otherwise nothing is truncated or warned, since the traces already hold the full text).
250
+
251
+ Then three events are emitted via `emit()`:
252
+
253
+ 1. INFO, original label: `message.slice(0, limit) + '... (<total> chars)'`
254
+ 2. WARN, label `WARN`: `INFO log exceeded the <limit> char threshold (<total> chars). Refer to the debug logs to see the full text. <hint>`
255
+ 3. DEBUG, same label (a plain `log` line's `INFO` label becomes `DEBUG`), full text.
256
+
257
+ `infoLimitHint()` (in `config.ts`) tells the reader what to edit, depending on `LIMIT_SOURCE`: the config file's absolute path, the env var name, or the `configure()` call.
258
+
259
+ ## 12. Log file retention (`maxRuns`, `maxLogFiles`, in `sinks.ts`)
260
+
261
+ `pruneOnce(cfg, kind)` runs after the first write of each kind in a process (guarded by `PRUNED`). It lists `<logDir>/*/<kind>/<kind>-*.(log|jsonl)` across all date folders and groups files by run id, parsed from `<kind>-<runId>-<main|wN>.<ext>` (a name without a worker suffix counts as its own run). A run's age is its newest file's mtime.
262
+
263
+ - `maxLogFiles`: of the files outside the current run, the newest `maxLogFiles - currentRunFiles` are kept.
264
+ - `maxRuns`: of the runs other than the current one, the newest `maxRuns - 1` are kept; older runs are marked whole.
265
+ - A file goes if either limit marks it. Then two guards apply: files whose name contains the current run id are never marked (parallel workers share it), and a run whose newest file is younger than `RECENT_RUN_MS` (1 hour) is never deleted, because another runner or CI shard may still be writing it. Neither limit is a hard cap.
266
+ - Skipped entirely when `runIdMissing()` (§13): without a shared run id, each worker's "current run" is its own pid-based id, and its siblings' live files would look like an older run.
267
+
268
+ Emptied kind and date folders are removed. Best effort; all errors swallowed.
269
+
270
+ ## 13. Run identity and workers (`config.ts`)
271
+
272
+ - `initRun()` (call from `globalSetup`) sets `process.env.VOID_RUN_ID` and `VOID_RUN_DATE` if absent, so every worker (which inherits env) shares one run id. `getRun()` falls back to a per-process id if unset.
273
+ - `runIdMissing()` is true in a Playwright worker (`TEST_WORKER_INDEX` set) without `VOID_RUN_ID`, meaning `initRun()` was never called in the runner. Then `traceFilePath` writes one stderr warning per process (`RUN_ID_WARNED`, reset by `closeAllFiles()`) and retention is off (§12). A worker cannot fix this itself: env it sets is not seen by its siblings.
274
+ - Only process-based workers are supported. A `worker_threads` thread starts with a copy of its parent's `process.env`, so it gets the same `workerLabel()` and run id, and appends to the same files through its own fds, with no way to tell its lines apart.
275
+ - `workerLabel()` is `w<TEST_WORKER_INDEX>` under Playwright, else `main`. It appears in file names, line prefixes and events.
276
+
277
+ ## 14. Playwright integration (`playwright.ts`)
278
+
279
+ `test = base.extend({ voidLog: [fn, { auto: true }] })`: an auto fixture active for every test. Per test it: sets the test context (`setTestContext(titlePath.join(' > '), title)`: the path tags JSONL records, the title feeds `consoleTest`), starts a `captureLogs()` buffer, logs `TEST START`, runs the test, then logs `TEST END | status | ms` (`error.failed` on failure, `info.success` otherwise), and attaches the captured text as `void-log` per `cfg.attach` (`on-failure` default). It also re-exports `expect` and `initRun`. Tests import `test`/`expect` from this entry instead of `@playwright/test`.
280
+
281
+ ## 15. Extension points
282
+
283
+ - **Custom sink**: `addSink({ accepts(level,cfg){...}, write(ev,cfg){...} })`. Receives the same `LogEvent`; `ev.color` is ANSI, strip it for plain output.
284
+ - **In-memory capture**: `captureLogs()` returns `{ text(), stop() }`.
285
+ - **New action**: add a method in `LogActions` calling `this.msg(intent, label, m)`. For a new intent, add it to `LogIntent` and `INTENT_FG` in `theme.ts`.
286
+ - **New config option**: add to `LogConfig` and `builtinDefaults`; add to the `KEYS` table in `configFile.ts` (validation); optionally an env var in `applyEnv`; document in README; add tests. `LogConfigPatch` updates automatically.
287
+
288
+ ## 16. Invariants and gotchas (read before changing code)
289
+
290
+ 1. Everything goes through `dispatch`. Do not write to sinks directly.
291
+ 2. Do not capture a stack before `accepts()` has approved at least one sink.
292
+ 3. `config.ts` <-> `theme.ts`/`configFile.ts` cycles are avoided with `import type`. Keep it that way.
293
+ 4. File sinks must stay escape-free: they rely on `stripAnsi` at write time.
294
+ 5. `intent === null` means "pre-colored block" (tables). Truncation and `callerColor` logic assume this.
295
+ 6. `configure()` must go through `config()` so the config file is loaded first; never touch `CURRENT` directly elsewhere.
296
+ 7. A bad config file must keep throwing (no silent fallback). `build()` resets `CURRENT` on failure for this reason.
297
+ 8. Files are written synchronously on purpose; do not buffer.
298
+ 9. The default theme/`fg`/`bg` defaults must keep 0.1.0 output byte-identical.
299
+ 10. Config is built lazily at first use (not at import). An env var changed between import and the first log call is honored; this is the one intentional difference from 0.1.0.
300
+ 11. In regexes written inside template literals, escape backslashes (`\\.`); a past bug came from exactly this.
301
+ 12. Retention must never run in a worker without a shared run id (`runIdMissing()`), and must never delete the current run or a run touched within `RECENT_RUN_MS`.
302
+ 13. `configure()` never throws on bad input; it warns and skips. Only a config file fails loudly.
303
+ 14. New output options that change line format default to off, so existing console and file output stays byte-identical.
304
+
305
+ ## 17. Differences from the Java logger
306
+
307
+ Dropped: custom themes, `setTheme`, width/arrow settings, file rotation and gzip archives. Changed: caller frames are excluded by path rather than method-name prefix. Added: secret redaction, JSONL sink, custom sinks, in-memory capture, Playwright fixture with attachment, per-worker files, config file, `fg`/`bg`, INFO truncation, file and run retention, console worker/test prefixes.
308
+
309
+ ## 18. Testing map
310
+
311
+ | Behavior | Test file |
312
+ |---|---|
313
+ | Console/file output, levels, caller/chain, redaction, malformed input | `logger.test.ts`, `logger.aggressive.test.ts` |
314
+ | fg/bg/ansi/callerColor combinations across all actions, env parsing | `colors.test.ts` |
315
+ | Discovery order, forms, precedence, `VOID_LOG_CONFIG`, loud failures | `config-file.test.ts` |
316
+ | Truncation text, WARN/DEBUG lines, hint by source | `truncate.test.ts` |
317
+ | Retention by files and runs, protection of current and recent runs, missing run id, foreign files | `retention.test.ts` |
318
+ | consoleWorker/consoleTest prefixes, missing-run-id warning, `configure()` validation | `separable.test.ts` |
319
+ | Real Playwright, 2 workers, `.ts` config, `globalSetup` isolation, console prefixes, shared vs split run id | `multi-worker.test.ts` + `fixtures/multi-worker/` |
320
+ | Visual/e2e demos | `*.spec.ts` via `test/playwright.config.ts` |
321
+
322
+ Tests use `resetConfig()` plus `configure({ logDir: tmp, ansi: false, tsFormat: () => 'TS' })` for deterministic output, and spy on `process.stdout.write`. Config-file tests `chdir` into a temp dir so no stray `logger.config.*` leaks in.
package/CHANGELOG.md ADDED
@@ -0,0 +1,73 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@aryan-vashishth/advanced-logger`. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses [Semantic Versioning](https://semver.org/). While the version is below 1.0.0, a minor release may add options but keeps existing defaults and output unchanged unless noted.
4
+
5
+ ## [0.3.0] - 2026-10-14
6
+
7
+ Makes mixed logs from parallel runs separable, and stops a missing setup step from scattering or deleting logs. Console and file output are unchanged unless you turn on the new options.
8
+
9
+ ### Added
10
+
11
+ - `maxRuns` option (env `VOID_LOG_MAX_RUNS`): keeps the newest N runs per trace kind, current run included, and deletes older runs whole. A run's age is its newest file's modification time.
12
+ - `consoleWorker` option (default `false`): prefixes console lines with the worker, `w<N> │ ` (or `main │ ` outside Playwright), the same prefix trace-file lines already have.
13
+ - `consoleTest` option (default `false`): prefixes console lines with the running test's title, cut to 40 characters. Needs the Playwright fixture.
14
+ - A one-time stderr warning in a Playwright worker that has no `VOID_RUN_ID`, meaning `initRun()` was never called in `globalSetup`.
15
+ - `runIdMissing()` export, true in that situation.
16
+ - `setTestContext(test, title?)` takes an optional short title for the console prefix. The Playwright fixture passes the test's own title.
17
+ - `LogEvent.testTitle` for custom sinks.
18
+ - README sections on redaction scope (only top-level structured keys are masked; free text and nested objects are not) and on `worker_threads` (not supported).
19
+
20
+ ### Changed
21
+
22
+ - `configure({...})` now checks its patch with the config file's validator. An unknown option or a wrongly typed value prints one stderr warning and is skipped; the rest of the patch still applies. It never throws. Before, any key and value were stored as given. The callback form, `configure((cfg) => ...)`, is not checked.
23
+ - Retention (`maxLogFiles` and `maxRuns`) never deletes a run that has a file modified in the last hour, so another runner or CI shard writing to the same folder keeps its files. Neither limit is a hard cap.
24
+ - GitHub annotation lines carry the `consoleWorker` / `consoleTest` prefix when those options are on.
25
+
26
+ ### Fixed
27
+
28
+ - Without `initRun()`, each Playwright worker used its own run id, so with `maxLogFiles` set it could delete a sibling worker's live log files as "older". Retention is now off in such a worker.
29
+
30
+ ## [0.2.0] - 2026-10-13
31
+
32
+ Adds a project config file, independent color toggles, INFO truncation and log retention. With no config file and no new options set, output is identical to 0.1.0.
33
+
34
+ ### Added
35
+
36
+ - Project config file: `logger.config.ts`, `.js`, `.cjs` or `.json` in the working directory, or the path in `VOID_LOG_CONFIG`. It is loaded once per process, so every Playwright worker reads it. It default-exports an object or a `(config) => patch` function. `defineConfig()` types it.
37
+ - Config precedence, lowest to highest: built-in defaults, config file, environment variables, `configure()` calls.
38
+ - Strict config file validation: a file that throws, has the wrong shape, has an unknown option or has a wrongly typed value fails with an error naming the file, on every use until fixed. An explicit `VOID_LOG_CONFIG` that does not exist is an error.
39
+ - `fg` and `bg` options (env `VOID_LOG_FG`, `VOID_LOG_BG`) to turn the foreground colors and the theme background on and off independently. Bold, including table titles, follows `fg`.
40
+ - `enableFg()`, `disableFg()`, `isFgEnabled()` and the `Bg` equivalents.
41
+ - `infoLogsCharLimit` option (env `VOID_LOG_INFO_LOGS_CHAR_LIMIT`): INFO lines longer than the limit print truncated with the total char count, followed by a WARN saying where to raise the limit and a DEBUG line with the full text. Tables are excluded.
42
+ - `maxLogFiles` option (env `VOID_LOG_MAX_FILES`): keeps the newest N files per trace kind across date folders. The current run's files are never deleted, and only files named like the logger's own output are touched.
43
+ - `ARCHITECTURE.md`, shipped in the package, describing the internals end to end.
44
+ - README installation, entry points, quick start and uninstall sections.
45
+
46
+ ### Changed
47
+
48
+ - Configuration is built lazily on first use, not at import, so an environment variable changed between import and the first log call is now honored.
49
+ - With `fg` and `bg` both off, console lines carry no escape codes on the line body, not even a lone reset.
50
+ - Environment variables apply only when set and valid. An invalid `VOID_LOG_LEVEL` is ignored instead of overriding a lower layer.
51
+
52
+ ## [0.1.0] - 2026-10-05
53
+
54
+ First release on npm. A self-contained TypeScript port of the VOID `core.logging` package for Playwright projects, with no runtime dependencies.
55
+
56
+ ### Added
57
+
58
+ - Level loggers `debug`, `info`, `warn` and `error`, each with intent-based actions such as `click`, `log`, `success`, `failed`, `password` (masked), `table`, `tree` and `row`, plus `fields()` for structured values.
59
+ - Console sink with the HIGH_CONTRAST theme. ANSI is auto-detected and controlled by `VOID_LOG_ANSI`, `NO_COLOR` and `FORCE_COLOR`. A caller suffix is shown at `debug` level, optionally colored with `callerColor`.
60
+ - Plain-text trace files under `logs/<date>/`: `partial-trace` (console-visible lines), `debug-trace` (every level, caller suffix) and `full-trace` (every level, `[CHAIN]` suffix). They are written synchronously, one file per Playwright worker, with every line prefixed `w<N> │ `.
61
+ - Opt-in JSONL sink (`VOID_LOG_JSONL=1`) with one JSON record per call, including `worker` and `test`.
62
+ - Secret redaction of structured values by key (`redactKeys`).
63
+ - Custom sinks (`addSink`, `removeSink`) and in-memory capture (`captureLogs`).
64
+ - Caller and in-project chain resolution, with filters (`suppressContains`, `suppressMethodPrefixes`, `includeOnlyPrefixes`, `projectRoots`).
65
+ - Table cell truncation (`tableCellLimit`).
66
+ - GitHub Actions `::error::` / `::warning::` annotations.
67
+ - Playwright entry (`@aryan-vashishth/advanced-logger/playwright`): a drop-in `test` / `expect` whose auto fixture tags each test, logs `TEST START` / `TEST END` and attaches the test's log to the report (`attach`: `on-failure` by default).
68
+ - `initRun()` to share one run id across Playwright workers via `VOID_RUN_ID` / `VOID_RUN_DATE`.
69
+ - Environment variables `VOID_LOG_LEVEL`, `VOID_LOG_DIR`, `VOID_LOG_ANSI`, `VOID_LOG_JSONL` and `VOID_RUN_ID`, and `configure()` for code.
70
+
71
+ [0.3.0]: https://www.npmjs.com/package/@aryan-vashishth/advanced-logger/v/0.3.0
72
+ [0.2.0]: https://www.npmjs.com/package/@aryan-vashishth/advanced-logger/v/0.2.0
73
+ [0.1.0]: https://www.npmjs.com/package/@aryan-vashishth/advanced-logger/v/0.1.0
package/README.md CHANGED
@@ -3,7 +3,67 @@
3
3
  Self-contained TypeScript port of the VOID `core.logging` package, for Playwright projects.
4
4
  No runtime dependencies other than `@playwright/test` (optional, only needed for the `@aryan-vashishth/advanced-logger/playwright` entry).
5
5
 
6
- Install it as a package (`npm install <path-or-git-url-to-this-repo>`), or copy `src/` directly into your own project (for example `src/logger/`) and import by relative path if you'd rather not take a dependency.
6
+ ## Installation
7
+
8
+ Published on npm as [`@aryan-vashishth/advanced-logger`](https://www.npmjs.com/package/@aryan-vashishth/advanced-logger). No registry login or token is needed, because the package is public.
9
+
10
+ ```bash
11
+ npm install @aryan-vashishth/advanced-logger
12
+ ```
13
+
14
+ Pin an exact version if you want reproducible installs:
15
+
16
+ ```bash
17
+ npm install @aryan-vashishth/advanced-logger@0.3.0
18
+ ```
19
+
20
+ Requirements:
21
+
22
+ - TypeScript types are bundled (`dist/*.d.ts`). The compiled output targets ES2022, and it is tested on Node 24.
23
+ - For the Playwright entry, `@playwright/test` >= 1.40.0 must be installed in your project (it is an optional peer dependency).
24
+
25
+ Check the installed version with `npm ls @aryan-vashishth/advanced-logger`, and update with `npm update @aryan-vashishth/advanced-logger`.
26
+
27
+ ### Entry points
28
+
29
+ | Import | Use |
30
+ |---|---|
31
+ | `@aryan-vashishth/advanced-logger` | `info`, `warn`, `error`, `debug`, `fields`, `configure`, ... for page objects and helpers |
32
+ | `@aryan-vashishth/advanced-logger/playwright` | Drop-in `test` / `expect` that tag each test, print a banner and attach the log on failure |
33
+
34
+ ### Quick start in a Playwright project
35
+
36
+ 1. Install the package (above).
37
+ 2. Create `global-setup.ts` so all workers share one run id:
38
+
39
+ ```ts
40
+ import { initRun } from '@aryan-vashishth/advanced-logger';
41
+ export default async () => { initRun(); };
42
+ ```
43
+
44
+ 3. Reference it in `playwright.config.ts`: `globalSetup: './global-setup.ts'`.
45
+ If you skip this, each worker prints a one-time `VOID_RUN_ID is not set` warning to stderr. Its files then carry their own run id, and log retention is turned off in that worker, so no worker can delete another's live files.
46
+ 4. In specs, import `test` and `expect` from `@aryan-vashishth/advanced-logger/playwright` instead of `@playwright/test`.
47
+ 5. Run your tests. Logs are written under `./logs/<date>/` (change with `VOID_LOG_DIR`).
48
+
49
+ If the caller chain (`[CHAIN]` in `full-trace`) comes out empty, set the project root explicitly. It defaults to the working directory:
50
+
51
+ ```ts
52
+ import { configure } from '@aryan-vashishth/advanced-logger';
53
+ configure({ projectRoots: [__dirname] });
54
+ ```
55
+
56
+ ### Uninstall or migrate from a git install
57
+
58
+ ```bash
59
+ npm uninstall @aryan-vashishth/advanced-logger
60
+ ```
61
+
62
+ If you previously installed from the GitHub URL, remove that dependency entry first so the lockfile stops recording `git+ssh://` addresses, then install from npm as shown above.
63
+
64
+ You can also copy `src/` into your own project (for example `src/logger/`) and import by relative path if you would rather not take a dependency.
65
+
66
+ ## Usage
7
67
 
8
68
  ```ts
9
69
  // tests: import test/expect from the Playwright entry so every test is tagged, bannered and its log attached on failure
@@ -32,16 +92,138 @@ globalSetup: './global-setup.ts' // export default async () => { initRun(); }
32
92
 
33
93
  Files are written synchronously, one per Playwright worker (`...-w<index>.log`), so parallel workers never interleave and a crash loses nothing.
34
94
 
95
+ Workers are identified by Playwright's `TEST_WORKER_INDEX`, one process per worker. Node `worker_threads` are not supported: a thread starts with a copy of its parent's environment, so it gets the same worker label (`main` outside Playwright) and appends to the same files as the code that started it, with nothing to tell their lines apart.
96
+
97
+ ### Telling parallel console output apart: consoleWorker, consoleTest
98
+
99
+ With several workers, console lines from different tests interleave. Two opt-in prefixes say where each line came from (both off by default, so the console looks the same as in 0.2.0):
100
+
101
+ ```ts
102
+ configure({ consoleWorker: true, consoleTest: true });
103
+ // w1 │ logs in with a valid user │ 2026-10-13 16:25:06.083 │ INFO │ Click: Submit
104
+ ```
105
+
106
+ - `consoleWorker` adds the worker (`w<index>`, or `main` outside Playwright), the same prefix every trace-file line already has.
107
+ - `consoleTest` adds the running test's own title, cut to 40 characters. It needs the Playwright fixture (`test` from `@aryan-vashishth/advanced-logger/playwright`); lines logged outside a test have no test segment.
108
+ - Both apply to the console only, including GitHub annotations. The trace files are already one file per worker with `TEST START` / `TEST END` around each test, and JSONL records already carry `worker` and the full `test` path.
109
+
35
110
  ## Configuration
36
111
 
37
- Environment: `VOID_LOG_LEVEL` (debug/info/warn/error/off), `VOID_LOG_DIR`, `VOID_LOG_ANSI`, `VOID_LOG_JSONL`, `VOID_RUN_ID`, plus standard `NO_COLOR` / `FORCE_COLOR`.
38
- Code: `configure({ level, ansi, callerColor, tsFormat, segmentDivider, tableCellLimit, tableCellLimitEnabled, files, console, redactKeys, attach, ... })`.
112
+ Environment: `VOID_LOG_LEVEL` (debug/info/warn/error/off), `VOID_LOG_DIR`, `VOID_LOG_ANSI`, `VOID_LOG_FG`, `VOID_LOG_BG`, `VOID_LOG_JSONL`, `VOID_LOG_INFO_LOGS_CHAR_LIMIT`, `VOID_LOG_MAX_RUNS`, `VOID_LOG_MAX_FILES`, `VOID_LOG_CONFIG`, `VOID_RUN_ID`, plus standard `NO_COLOR` / `FORCE_COLOR`. Boolean variables accept `1/true/yes/on` and `0/false/no/off`.
113
+ Code: `configure({ level, infoLogsCharLimit, maxRuns, maxLogFiles, consoleWorker, consoleTest, ansi, fg, bg, callerColor, tsFormat, segmentDivider, tableCellLimit, tableCellLimitEnabled, files, console, redactKeys, attach, ... })`.
114
+
115
+ `configure({...})` checks its patch the same way the config file is checked, but it never throws, since a logging option should not fail a test. An unknown option (such as a typo like `levl`) or a wrongly typed value prints one warning to stderr and is skipped; the rest of the patch still applies. The callback form, `configure((cfg) => ...)`, is not checked.
39
116
 
40
117
  The single theme (HIGH_CONTRAST) is on when ANSI is on: `enableAnsi()` / `disableAnsi()`.
41
118
 
119
+ ### Config file
120
+
121
+ Put a `logger.config.ts` (or `.js`, `.cjs`, `.json`) in the project root, which is `process.cwd()`. The first one found, in that order, is loaded once per process, the first time the logger is used. Every Playwright worker is its own process, so every worker reads it.
122
+
123
+ ```ts
124
+ // logger.config.ts
125
+ import { defineConfig } from '@aryan-vashishth/advanced-logger';
126
+
127
+ export default defineConfig({
128
+ level: 'debug',
129
+ fg: true,
130
+ bg: false,
131
+ redactKeys: ['password', 'token', 'pin'],
132
+ files: { jsonl: true },
133
+ projectRoots: [__dirname],
134
+ });
135
+ ```
136
+
137
+ The default export is either a plain object (the same shape `configure()` accepts) or a function `(config) => patch`. The function receives a copy of the built-in defaults and returns a patch. `defineConfig()` only adds typing, and its type is exactly `LogConfigPatch`.
138
+
139
+ Precedence, lowest to highest:
140
+
141
+ 1. Built-in defaults
142
+ 2. Config file
143
+ 3. Environment variables (`VOID_LOG_*`, `NO_COLOR`, `FORCE_COLOR`)
144
+ 4. Explicit `configure()` calls in code
145
+
146
+ Notes:
147
+
148
+ - `configure()` inside Playwright's `globalSetup` does **not** reach the workers. `globalSetup` runs in the runner process, and each worker is a separate process with its own logger state. Only environment variables are inherited by workers (that is how `initRun()` shares the run id). A config file does reach them.
149
+ - Set `VOID_LOG_CONFIG` to use a different path (absolute, or relative to the working directory). Unlike the default lookup, an explicit path that does not exist is an error.
150
+ - No file at all is fine and changes nothing. A file that exists but throws, has the wrong shape, an unknown option name (for example a typo such as `levl`) or a wrongly typed value fails with an error that names the file. It keeps failing on every use until fixed.
151
+ - TypeScript files are loaded with `require()`, so Playwright's own transpiler (or Node's type stripping) handles them. Use `.js`, `.cjs` or `.json` if your runner cannot load `.ts`. There is no runtime dependency.
152
+ - An invalid `VOID_LOG_LEVEL` is ignored, so it never overrides the config file.
153
+ - `NO_COLOR` and `FORCE_COLOR` count as environment variables, so they beat `ansi` in the file. Terminal auto-detection does not: the file beats it.
154
+
155
+ ### Limiting how many logs are kept: maxRuns, maxLogFiles
156
+
157
+ `maxRuns: 5` (or `VOID_LOG_MAX_RUNS=5`) keeps the 5 newest runs in each of `partial-trace`, `debug-trace`, `full-trace` and `jsonl`, counted across all date folders and including the current run. Older runs are deleted whole, never one worker's file at a time. A run's age is the modification time of its newest file. Date folders left empty are removed. Unset, `null` or `0` keeps everything (the default; an env value of `0` turns off a limit set in the config file).
158
+
159
+ `maxLogFiles: 20` (or `VOID_LOG_MAX_FILES=20`) is the older setting and counts files instead: it keeps the 20 newest files per kind. Each run writes one file per worker, so with 4 workers it holds about 5 runs, and it can leave part of a run behind. Prefer `maxRuns`. If both are set, a file is deleted when either limit says so.
160
+
161
+ Neither limit is a hard cap. These are never deleted:
162
+
163
+ - The current run's files. Parallel workers share one run id, so a run with more workers than `maxLogFiles` exceeds it.
164
+ - Any run with a file modified in the last hour. Another runner or CI shard writing to the same log folder at the same time may still be using it.
165
+ - Anything, in a Playwright worker without a shared run id (`initRun()` was not called). Each worker would see its siblings' live files as an older run, so retention is off in that worker and it prints a warning instead.
166
+
167
+ Cleanup runs once per process, per kind, right after the first write, and is best effort: a failure never reaches your test. Only files named like this logger's output (`<kind>-*.log` / `.jsonl`) are touched, so other files in the log folder are safe.
168
+
169
+ ### Redaction: redactKeys
170
+
171
+ Values are masked as `***` when their **key** contains one of `redactKeys` (case-insensitive substring; the defaults cover `password`, `secret`, `token`, `authorization`, `apikey` and similar). This applies to structured output only: `fields(...)`, trees, rows and tables. Two gaps to know about:
172
+
173
+ - Free text is not scanned, so `` info.log(`password is ${pw}`) `` prints the password in clear.
174
+ - Only top-level keys are checked. A nested object is printed as JSON as it is, so `fields('user', { password: pw })` shows the password.
175
+
176
+ Pass secrets as top-level fields, use `info.password(value)` (which prints one `*` per character), or keep them out of messages.
177
+
178
+ ### Truncating long INFO logs: infoLogsCharLimit
179
+
180
+ `infoLogsCharLimit: 200` (or `VOID_LOG_INFO_LOGS_CHAR_LIMIT=200`) caps INFO log messages at 200 characters. When one is longer, three lines are logged:
181
+
182
+ ```
183
+ INFO │ xxxxxxxx... (259 chars)
184
+ WARN │ INFO log exceeded the 200 char threshold (259 chars). Refer to the debug logs to see the full text. To increase the limit, change infoLogsCharLimit in /path/to/logger.config.ts.
185
+ DEBUG │ <the full 259 characters, no limit>
186
+ ```
187
+
188
+ - The WARN also says where to raise the limit: the config file's full path when the value came from the file, the env var name when it came from the environment, or the `configure()` call when it was set in code.
189
+ - Leave it unset, `null` or `0` for no limit (the default). An env value of `0` turns off a limit set in the config file.
190
+ - A message of exactly the limit is not truncated. The count in `(N chars)` is the original length.
191
+ - Applies to INFO only, and not to `table()` output (use `tableCellLimit` for that). Action lines keep their label (`CLICK [>]`) in all three lines.
192
+ - Only applies when INFO is visible at the root `level`. When it is not, nothing is truncated or warned about, and the debug and full traces already hold the full text.
193
+ - The full text is in `debug-trace` and `full-trace` files (they capture every level), and on the console when `level` is `debug`. `partial-trace`, the console and the Playwright attachment get the truncated line plus the WARN.
194
+
195
+ ### Colors: ansi, fg, bg, callerColor
196
+
197
+ | Option | Env | Default | Controls |
198
+ |---|---|---|---|
199
+ | `ansi` | `VOID_LOG_ANSI` | auto-detected | Master switch. `false` means no escape codes at all, whatever the other flags say. |
200
+ | `fg` | `VOID_LOG_FG` | `true` | Foreground colors: the text color per intent, and the level color on plain `log` lines. Bold goes with it. |
201
+ | `bg` | `VOID_LOG_BG` | `true` | The theme background. |
202
+ | `callerColor` | none | `false` | Colors the caller suffix separately (console, debug level). |
203
+
204
+ With `ansi: true`:
205
+
206
+ | `fg` | `bg` | Console line |
207
+ |---|---|---|
208
+ | true | true | foreground + background (the 0.1.0 output) |
209
+ | true | false | foreground only |
210
+ | false | true | background only |
211
+ | false | false | no escape codes on the line body |
212
+
213
+ - The background is a single color for every level. There is no per-level background; the level only picks the foreground, and only on plain `log` lines.
214
+ - `callerColor` is its own opt-in and is **not** gated by `fg`/`bg`. With `fg: false, bg: false, callerColor: true` the body is bare and only the caller suffix is colored. `ansi: false` silences it too.
215
+ - Tables, trees, rows and every action follow the same flags, including the table title's bold. Plain-text file sinks (partial, debug and full traces, JSONL) never contain escape codes.
216
+ - Runtime switches: `enableFg()` / `disableFg()` / `isFgEnabled()` and the `Bg` equivalents.
217
+
218
+ ## More documentation
219
+
220
+ [ARCHITECTURE.md](ARCHITECTURE.md) describes the internals end to end: file layout, the dispatch pipeline, config layering, sinks, caller resolution and the Playwright fixture. It ships inside the npm package.
221
+
222
+ [CHANGELOG.md](CHANGELOG.md) lists what changed in each version, including any change to defaults or output. It also ships in the package.
223
+
42
224
  ## Differences from the Java logger
43
225
 
44
226
  - Custom themes, `setTheme`, `tsWidth/levelWidth/actionWidth` and `traceArrow` are dropped (the width and arrow settings were never used by the renderer).
45
227
  - Caller frames from the logger's own folder are excluded by path. Java excluded frames by method-name prefix (`log`, `info`, ...), which also hides user methods such as `login()`; that is not reproduced.
46
228
  - No file rotation or gzip archives.
47
- - Added: secret redaction in fields/tables, JSONL sink, custom sinks (`addSink`), in-memory capture, Playwright fixture with log attachment, per-worker files.
229
+ - Added: secret redaction in fields/tables, JSONL sink, custom sinks (`addSink`), in-memory capture, Playwright fixture with log attachment, per-worker files, run-based retention, worker and test prefixes on the console.
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}