@void.01/advanced-logger 0.0.0-stage → 0.4.1
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.
- package/ARCHITECTURE.md +342 -0
- package/CHANGELOG.md +115 -0
- package/LICENSE +21 -0
- package/README.md +308 -2
- package/dist/actions.d.ts +79 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +337 -0
- package/dist/actions.js.map +1 -0
- package/dist/ansi.d.ts +144 -0
- package/dist/ansi.d.ts.map +1 -0
- package/dist/ansi.js +219 -0
- package/dist/ansi.js.map +1 -0
- package/dist/caller.d.ts +21 -0
- package/dist/caller.d.ts.map +1 -0
- package/dist/caller.js +129 -0
- package/dist/caller.js.map +1 -0
- package/dist/config.d.ts +152 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +398 -0
- package/dist/config.js.map +1 -0
- package/dist/configFile.d.ts +31 -0
- package/dist/configFile.d.ts.map +1 -0
- package/dist/configFile.js +211 -0
- package/dist/configFile.js.map +1 -0
- package/dist/core.d.ts +17 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +89 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +10 -0
- package/dist/logger.js.map +1 -0
- package/dist/playwright.d.ts +15 -0
- package/dist/playwright.d.ts.map +1 -0
- package/dist/playwright.js +47 -0
- package/dist/playwright.js.map +1 -0
- package/dist/redact.d.ts +8 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +36 -0
- package/dist/redact.js.map +1 -0
- package/dist/sinks.d.ts +80 -0
- package/dist/sinks.d.ts.map +1 -0
- package/dist/sinks.js +461 -0
- package/dist/sinks.js.map +1 -0
- package/dist/theme.d.ts +71 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +115 -0
- package/dist/theme.js.map +1 -0
- package/package.json +51 -4
package/README.md
CHANGED
|
@@ -1,3 +1,309 @@
|
|
|
1
|
-
#
|
|
1
|
+
# advanced-logger
|
|
2
|
+
|
|
3
|
+
Self-contained TypeScript port of the VOID `core.logging` package, for Playwright projects.
|
|
4
|
+
Source code and issues: [github.com/Aryan-Vashishth/advanced-logger](https://github.com/Aryan-Vashishth/advanced-logger).
|
|
5
|
+
No runtime dependencies other than `@playwright/test` (optional, only needed for the `@void.01/advanced-logger/playwright` entry).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Published on npm as [`@void.01/advanced-logger`](https://www.npmjs.com/package/@void.01/advanced-logger). No registry login or token is needed, because the package is public.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @void.01/advanced-logger
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Pin an exact version if you want reproducible installs:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @void.01/advanced-logger@0.4.0
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requirements:
|
|
22
|
+
|
|
23
|
+
- TypeScript types are bundled (`dist/*.d.ts`). The compiled output targets ES2022, and it is tested on Node 24.
|
|
24
|
+
- For the Playwright entry, `@playwright/test` >= 1.40.0 must be installed in your project (it is an optional peer dependency).
|
|
25
|
+
|
|
26
|
+
Check the installed version with `npm ls @void.01/advanced-logger`, and update with `npm update @void.01/advanced-logger`.
|
|
27
|
+
|
|
28
|
+
### Entry points
|
|
29
|
+
|
|
30
|
+
| Import | Use |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `@void.01/advanced-logger` | `info`, `warn`, `error`, `debug`, `fields`, `configure`, ... for page objects and helpers |
|
|
33
|
+
| `@void.01/advanced-logger/playwright` | Drop-in `test` / `expect` that tag each test, print a banner and attach the log on failure |
|
|
34
|
+
|
|
35
|
+
### Quick start in a Playwright project
|
|
36
|
+
|
|
37
|
+
1. Install the package (above).
|
|
38
|
+
2. Create `global-setup.ts` so all workers share one run id:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { initRun } from '@void.01/advanced-logger';
|
|
42
|
+
export default async () => { initRun(); };
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
3. Reference it in `playwright.config.ts`: `globalSetup: './global-setup.ts'`.
|
|
46
|
+
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.
|
|
47
|
+
4. In specs, import `test` and `expect` from `@void.01/advanced-logger/playwright` instead of `@playwright/test`.
|
|
48
|
+
5. Run your tests. Logs are written under `./logs/<date>/` (change with `VOID_LOG_DIR`).
|
|
49
|
+
|
|
50
|
+
If the caller chain (`[CHAIN]` in `full-trace`) comes out empty, set the project root explicitly. It defaults to the working directory:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { configure } from '@void.01/advanced-logger';
|
|
54
|
+
configure({ projectRoots: [__dirname] });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Uninstall or migrate from a git install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm uninstall @void.01/advanced-logger
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
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.
|
|
64
|
+
|
|
65
|
+
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.
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// tests: import test/expect from the Playwright entry so every test is tagged, bannered and its log attached on failure
|
|
71
|
+
import { test, expect } from '@void.01/advanced-logger/playwright';
|
|
72
|
+
import { info, warn, error, fields } from '@void.01/advanced-logger';
|
|
73
|
+
|
|
74
|
+
info.click('Submit');
|
|
75
|
+
info.log('Request', fields('method', 'POST'));
|
|
76
|
+
info.table([{ ID: 1, Name: 'Alice' }], 'Users');
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// playwright.config.ts: share one run id across workers
|
|
81
|
+
globalSetup: './global-setup.ts' // export default async () => { initRun(); }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Output
|
|
85
|
+
|
|
86
|
+
| Target | Content |
|
|
87
|
+
|---|---|
|
|
88
|
+
| Console | Themed lines at or above the root level. Caller suffix shown only at `debug`. |
|
|
89
|
+
| `logs/<date>/partial-trace/` | Console-visible lines, plain text |
|
|
90
|
+
| `logs/<date>/debug-trace/` | Every level, plain text, caller suffix |
|
|
91
|
+
| `logs/<date>/full-trace/` | Every level, plain text, `[CHAIN]` suffix |
|
|
92
|
+
| `logs/<date>/jsonl/` | One JSON record per call (opt-in: `VOID_LOG_JSONL=1`) |
|
|
93
|
+
| `logs/<date>/attachments/csv/` | One CSV file per logged table (on by default, see below) |
|
|
94
|
+
| `logs/<date>/attachments/json/` | One JSON file per logged table |
|
|
95
|
+
|
|
96
|
+
Files are written synchronously, one per Playwright worker (`...-w<index>.log`), so parallel workers never interleave and a crash loses nothing.
|
|
97
|
+
|
|
98
|
+
### Table attachments: CSV and JSON copies of every table
|
|
99
|
+
|
|
100
|
+
Every table you log also gets a CSV and a JSON file, so you can open the data in a spreadsheet or read it from code. A table needs a title, which is shown above it and names its files:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
info.table(rows, 'Order lines');
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
logs/2026-10-16/
|
|
108
|
+
partial-trace/partial-trace-20261016-101500-123-pid4242-w1.log ← the parent log (also in debug-trace, full-trace)
|
|
109
|
+
attachments/
|
|
110
|
+
csv/20261016-101500-123-pid4242-w1/ ← one folder per parent log
|
|
111
|
+
001-users.csv
|
|
112
|
+
002-order-lines.csv
|
|
113
|
+
json/20261016-101500-123-pid4242-w1/
|
|
114
|
+
001-users.json
|
|
115
|
+
002-order-lines.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **One folder per parent log.** Each worker's trace files are named `<kind>-<runId>-<worker>.log`, and that worker's tables go in the folder `<runId>-<worker>` under both `csv/` and `json/`.
|
|
119
|
+
- **File names are the number and the title.** `<NNN>-<title>`: `<NNN>` counts tables in that worker, in log order, so files sort the way they were logged. The title is lowercased and anything other than letters and digits becomes `-` (letters of any script are kept, so `Пользователи` stays readable). It is cut at 40 characters, and a title with no letters or digits becomes `table`. A number whose file already exists is skipped, never overwritten.
|
|
120
|
+
- **The title is required.** In TypeScript, `info.table(rows)` without a title no longer compiles. From plain JavaScript (or older compiled code), it still works: the table renders without a title row, its files are named `untitled`, and a one-time warning asks for a title. `info.log(object)`, which renders a table with no title row, names its files `log`; the tables of a logged list are named `list-item-0`, `list-item-1` and so on.
|
|
121
|
+
- **The logs point to the files.** After each table, debug-trace and full-trace get a line naming both files: `TABLE FILES │ attachments/csv/<runId>-<worker>/002-order-lines.csv | attachments/json/<runId>-<worker>/002-order-lines.json`. It is a DEBUG line, so the console and partial-trace show it only at `level: 'debug'`.
|
|
122
|
+
- **Full values.** Cells are never cut short in the files, even when `tableCellLimit` shortens them on the console.
|
|
123
|
+
- **Same redaction as the console.** Sensitive keys are masked at any depth, and with `redactText` so is sensitive text inside cells and the title.
|
|
124
|
+
- **CSV:** UTF-8 with a byte-order mark (so Excel shows non-ASCII text correctly), a header row, CRLF line ends, and RFC 4180 quoting. Objects and arrays are written as JSON text. A text cell starting with `=`, `+`, `-` or `@` gets a leading `'`, so a spreadsheet does not run it as a formula (plain negative numbers are left alone).
|
|
125
|
+
- **JSON:** `{ title, time, level, worker, runId, test, columns, rows }`. `test` is the full test path when the Playwright fixture is in use.
|
|
126
|
+
- Written for tables at every level, like debug-trace. Empty tables and `table("text")` lines write nothing.
|
|
127
|
+
- `maxRuns` deletes a run's attachment folders along with its logs. `maxLogFiles` does not count them.
|
|
128
|
+
- Turn it off with `files: { tables: false }` or `VOID_LOG_TABLES=0`.
|
|
129
|
+
|
|
130
|
+
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.
|
|
131
|
+
|
|
132
|
+
### Telling parallel console output apart: consoleWorker, consoleTest
|
|
133
|
+
|
|
134
|
+
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):
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
configure({ consoleWorker: true, consoleTest: true });
|
|
138
|
+
// w1 │ logs in with a valid user │ 2026-10-13 16:25:06.083 │ INFO │ Click: Submit
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- `consoleWorker` adds the worker (`w<index>`, or `main` outside Playwright), the same prefix every trace-file line already has.
|
|
142
|
+
- `consoleTest` adds the running test's own title, cut to 40 characters. It needs the Playwright fixture (`test` from `@void.01/advanced-logger/playwright`); lines logged outside a test have no test segment.
|
|
143
|
+
- 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.
|
|
144
|
+
|
|
145
|
+
## Configuration
|
|
146
|
+
|
|
147
|
+
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_TABLES`, `VOID_LOG_INFO_LOGS_CHAR_LIMIT`, `VOID_LOG_MAX_RUNS`, `VOID_LOG_MAX_FILES`, `VOID_LOG_RECENT_RUN_MINUTES`, `VOID_LOG_REDACT_TEXT`, `VOID_LOG_CONFIG`, `VOID_RUN_ID`, plus standard `NO_COLOR` / `FORCE_COLOR`. Boolean variables accept `1/true/yes/on` and `0/false/no/off`.
|
|
148
|
+
Code: `configure({ level, infoLogsCharLimit, maxRuns, maxLogFiles, recentRunMinutes, consoleWorker, consoleTest, ansi, fg, bg, callerColor, tsFormat, segmentDivider, tableCellLimit, tableCellLimitEnabled, files, console, redactKeys, redactText, attach, ... })`.
|
|
149
|
+
|
|
150
|
+
`configure()` checks what you pass 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; everything else still applies. This covers both forms: with a patch, `configure({...})`, a bad option is not applied; with a callback, `configure((cfg) => ...)`, a bad change is undone (the option goes back to its value from before the call, and an unknown one is removed). In a callback you may also assign an array to `suppressContains`, `suppressMethodPrefixes` or `includeOnlyPrefixes`; it is turned into a Set.
|
|
151
|
+
|
|
152
|
+
The single theme (HIGH_CONTRAST) is on when ANSI is on: `enableAnsi()` / `disableAnsi()`.
|
|
153
|
+
|
|
154
|
+
### Config file
|
|
155
|
+
|
|
156
|
+
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.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
// logger.config.ts
|
|
160
|
+
import { defineConfig } from '@void.01/advanced-logger';
|
|
161
|
+
|
|
162
|
+
export default defineConfig({
|
|
163
|
+
level: 'debug',
|
|
164
|
+
fg: true,
|
|
165
|
+
bg: false,
|
|
166
|
+
redactKeys: ['password', 'token', 'pin'],
|
|
167
|
+
files: { jsonl: true },
|
|
168
|
+
projectRoots: [__dirname],
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
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`.
|
|
173
|
+
|
|
174
|
+
Precedence, lowest to highest:
|
|
175
|
+
|
|
176
|
+
1. Built-in defaults
|
|
177
|
+
2. Config file
|
|
178
|
+
3. Environment variables (`VOID_LOG_*`, `NO_COLOR`, `FORCE_COLOR`)
|
|
179
|
+
4. Explicit `configure()` calls in code
|
|
180
|
+
|
|
181
|
+
Notes:
|
|
182
|
+
|
|
183
|
+
- `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.
|
|
184
|
+
- 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.
|
|
185
|
+
- 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.
|
|
186
|
+
- 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.
|
|
187
|
+
- An invalid `VOID_LOG_LEVEL` is ignored, so it never overrides the config file.
|
|
188
|
+
- `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.
|
|
189
|
+
|
|
190
|
+
### Limiting how many logs are kept: maxRuns, maxLogFiles
|
|
191
|
+
|
|
192
|
+
`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).
|
|
193
|
+
|
|
194
|
+
`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.
|
|
195
|
+
|
|
196
|
+
Neither limit is a hard cap. These are never deleted:
|
|
197
|
+
|
|
198
|
+
- The current run's files. Parallel workers share one run id, so a run with more workers than `maxLogFiles` exceeds it.
|
|
199
|
+
- Any run with a file modified in the last `recentRunMinutes` (default 60; env `VOID_LOG_RECENT_RUN_MINUTES`). Another runner or CI shard writing to the same log folder at the same time may still be using it. Set it to `0` to protect only the current run, for example when nothing else ever writes to the folder.
|
|
200
|
+
- 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.
|
|
201
|
+
|
|
202
|
+
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.
|
|
203
|
+
|
|
204
|
+
### Redaction: redactKeys, redactText
|
|
205
|
+
|
|
206
|
+
A key is sensitive when it contains one of `redactKeys` (case-insensitive substring). The defaults cover `password`, `passwd`, `secret`, `token`, `authorization`, `apikey` and `api_key`. Sensitive values print as `***` in two ways:
|
|
207
|
+
|
|
208
|
+
- **Structured values**, always: in `fields(...)`, trees, rows and tables, at any depth. `fields('user', { name: 'ann', password: pw })` prints `{"name":"ann","password":"***"}`. Nested objects, arrays and Maps are all checked, a `toJSON()` result is checked too, and your object is never modified.
|
|
209
|
+
- **Free text**, with `redactText: true` (the default; env `VOID_LOG_REDACT_TEXT`): any message, label text included. Masked forms are `key=value`, `key: value`, `"key":"value"` and `'key': 'value'` where the key contains a sensitive word, plus `Bearer <token>` and `Basic <credentials>`. The value ends at whitespace or `,` `;` `&` `"` `'` `}` `]`.
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
info.log('GET /api?access_token=abc123&page=2') → GET /api?access_token=***&page=2
|
|
213
|
+
info.log('Authorization: Bearer eyJhbGciOi...') → Authorization: Bearer ***
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Masking happens once, before anything is written, so the console, every trace file, JSONL and the Playwright attachment all get the masked text.
|
|
217
|
+
|
|
218
|
+
Limits of free-text masking:
|
|
219
|
+
|
|
220
|
+
- It is pattern-based, so it can miss a secret with no key next to it (`` `logged in as ann / hunter2` ``) and can mask a harmless value whose key contains a sensitive word (`tokens=3` prints `tokens=***`). Prefer passing secrets as fields, or `info.password(value)`, which prints one `*` per character.
|
|
221
|
+
- A value with spaces is masked only up to the first space.
|
|
222
|
+
- Set `redactText: false` to turn it off. Structured redaction stays on.
|
|
223
|
+
|
|
224
|
+
### Truncating long INFO logs: infoLogsCharLimit
|
|
225
|
+
|
|
226
|
+
`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:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
INFO │ xxxxxxxx... (259 chars)
|
|
230
|
+
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.
|
|
231
|
+
DEBUG │ <the full 259 characters, no limit>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- 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.
|
|
235
|
+
- 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.
|
|
236
|
+
- A message of exactly the limit is not truncated. The count in `(N chars)` is the original length.
|
|
237
|
+
- Applies to INFO only, and not to `table()` output (use `tableCellLimit` for that). Action lines keep their label (`CLICK [>]`) in all three lines.
|
|
238
|
+
- 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.
|
|
239
|
+
- 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.
|
|
240
|
+
|
|
241
|
+
### Colors: ansi, fg, bg, callerColor
|
|
242
|
+
|
|
243
|
+
| Option | Env | Default | Controls |
|
|
244
|
+
|---|---|---|---|
|
|
245
|
+
| `ansi` | `VOID_LOG_ANSI` | auto-detected | Master switch. `false` means no escape codes at all, whatever the other flags say. |
|
|
246
|
+
| `fg` | `VOID_LOG_FG` | `true` | Foreground colors: each action's own color, and the level color on plain `log` lines. Bold goes with it. |
|
|
247
|
+
| `bg` | `VOID_LOG_BG` | `true` | The theme background. |
|
|
248
|
+
| `callerColor` | none | `false` | Colors the caller suffix separately (console, debug level). |
|
|
249
|
+
|
|
250
|
+
With `ansi: true`:
|
|
251
|
+
|
|
252
|
+
| `fg` | `bg` | Console line |
|
|
253
|
+
|---|---|---|
|
|
254
|
+
| true | true | foreground + background (the default) |
|
|
255
|
+
| true | false | foreground only |
|
|
256
|
+
| false | true | background only |
|
|
257
|
+
| false | false | no escape codes on the line body |
|
|
258
|
+
|
|
259
|
+
- 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.
|
|
260
|
+
- See [Action colors](#action-colors) below for which color each action uses.
|
|
261
|
+
- `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.
|
|
262
|
+
- 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.
|
|
263
|
+
- Runtime switches: `enableFg()` / `disableFg()` / `isFgEnabled()` and the `Bg` equivalents.
|
|
264
|
+
|
|
265
|
+
### Action colors
|
|
266
|
+
|
|
267
|
+
Every action has its own foreground color, so a `click` line and an `input` line look different. Colors are grouped by what the action does, so the hue still tells you the kind of line at a glance:
|
|
268
|
+
|
|
269
|
+
| Kind | Hue | Actions |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| Interaction | blues, from cyan-blue to indigo | `click`, `hover`, `checkbox`, `toggle`, `dropdown`, `input`, `text`, `password`, `clear`, `key`, `upload` |
|
|
272
|
+
| Navigation | teals | `navigate`, `tab`, `frame`, `breadcrumb` |
|
|
273
|
+
| Observation | pinks and magentas | `wait`, `search`, `result` |
|
|
274
|
+
| Verification | gold | `verifying` |
|
|
275
|
+
| Data | violets | `grid`, `table`, `row` |
|
|
276
|
+
| Success | greens | `success`, `complete`, `resolved` |
|
|
277
|
+
| Alert | reds and oranges (`skip` is muted) | `failed`, `error`, `timeout`, `validation`, `fallback`, `skip` |
|
|
278
|
+
|
|
279
|
+
- Plain `log` lines keep their level's color: INFO white, WARN amber, ERROR red, DEBUG grey. `failed` uses the same red as ERROR.
|
|
280
|
+
- Table headers are darker shades of the table's violet, one per row, so title, column names and data read as three layers: the title row is the darkest (`TABLE_TITLE_FG`), the column-name row a muted mid shade (`TABLE_COLUMNS_FG`), and borders and data rows keep the table color. A title longer than the table widens the table instead of being cut.
|
|
281
|
+
- An action's color does not depend on the level: `warn.click()` and `info.click()` look the same, as before.
|
|
282
|
+
- Every color has at least 4.5:1 contrast on a dark terminal background (`#1e1e1e`). Colors within one kind are at least 10 apart in CIEDE2000 color difference, and colors of different kinds at least 12, so neighbors stay distinguishable. A test enforces these limits.
|
|
283
|
+
- The colors are 24-bit, so they need a truecolor terminal (VS Code, Windows Terminal, iTerm2 and most modern terminals). Each color is exported as `ACTION_FG`.
|
|
284
|
+
|
|
285
|
+
## Development
|
|
286
|
+
|
|
287
|
+
From a clone of this repository:
|
|
288
|
+
|
|
289
|
+
| Command | What it does |
|
|
290
|
+
|---|---|
|
|
291
|
+
| `npm test` | Unit tests (vitest), then the Playwright e2e specs |
|
|
292
|
+
| `npm run sweep` | Manual check of everything at once: prints every console style (each action's color, levels, tables, redaction, truncation, the color toggles, two workers in parallel), writes every file kind to `./logs` (or `VOID_LOG_DIR`) like any run, without deleting anything there, then lists this run's files with a preview of each and runs automatic checks on them (only this run's files, found by its run id) (no secrets or escape codes in any file, one CSV and JSON per table, names matching the trace files). It fails if a check fails; the console part is for you to look at. |
|
|
293
|
+
|
|
294
|
+
## More documentation
|
|
295
|
+
|
|
296
|
+
[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.
|
|
297
|
+
|
|
298
|
+
[CHANGELOG.md](CHANGELOG.md) lists what changed in each version, including any change to defaults or output. It also ships in the package.
|
|
299
|
+
|
|
300
|
+
## Differences from the Java logger
|
|
301
|
+
|
|
302
|
+
- Custom themes, `setTheme`, `tsWidth/levelWidth/actionWidth` and `traceArrow` are dropped (the width and arrow settings were never used by the renderer).
|
|
303
|
+
- 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.
|
|
304
|
+
- No file rotation or gzip archives.
|
|
305
|
+
- 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.
|
|
2
306
|
|
|
3
|
-
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type LevelName, type LogAction, LogIntent } from './theme';
|
|
2
|
+
export type Fields = Map<string, unknown> | Record<string, unknown>;
|
|
3
|
+
export type Row = Fields;
|
|
4
|
+
/** Ordered key/value builder. Throws on an odd number of arguments. */
|
|
5
|
+
export declare function fields(...pairs: unknown[]): Map<string, unknown>;
|
|
6
|
+
/** Java Arrays.deepToString-style rendering for arrays; JSON for plain objects. */
|
|
7
|
+
export declare function formatValue(v: unknown): string;
|
|
8
|
+
/**
|
|
9
|
+
* One instance per level (debug/info/warn/error). Every action method has its own foreground (ACTION_FG, in its
|
|
10
|
+
* intent's hue family) on the theme background; plain log lines use the level's foreground.
|
|
11
|
+
*/
|
|
12
|
+
export declare class LogActions {
|
|
13
|
+
readonly level: LevelName;
|
|
14
|
+
constructor(level: LevelName);
|
|
15
|
+
click(m: unknown): void;
|
|
16
|
+
checkbox(m: unknown): void;
|
|
17
|
+
text(m: unknown): void;
|
|
18
|
+
input(m: unknown): void;
|
|
19
|
+
dropdown(m: unknown): void;
|
|
20
|
+
toggle(m: unknown): void;
|
|
21
|
+
upload(m: unknown): void;
|
|
22
|
+
hover(m: unknown): void;
|
|
23
|
+
clear(m: unknown): void;
|
|
24
|
+
key(m: unknown): void;
|
|
25
|
+
/** Logs the password masked, never the value. */
|
|
26
|
+
password(text: string | null | undefined, label?: string): void;
|
|
27
|
+
navigate(m: unknown): void;
|
|
28
|
+
tab(m: unknown): void;
|
|
29
|
+
frame(m: unknown): void;
|
|
30
|
+
breadcrumb(m: unknown): void;
|
|
31
|
+
wait(m: unknown): void;
|
|
32
|
+
search(m: unknown): void;
|
|
33
|
+
result(m: unknown): void;
|
|
34
|
+
verifying(m: unknown): void;
|
|
35
|
+
success(m: unknown): void;
|
|
36
|
+
complete(m: unknown): void;
|
|
37
|
+
error(m: unknown): void;
|
|
38
|
+
failed(m: unknown): void;
|
|
39
|
+
timeout(m: unknown): void;
|
|
40
|
+
validation(m: unknown): void;
|
|
41
|
+
fallback(m: unknown): void;
|
|
42
|
+
skip(m: unknown): void;
|
|
43
|
+
grid(m: unknown): void;
|
|
44
|
+
/**
|
|
45
|
+
* `table("text")` logs a TABLE line. `table(row | rows, title)` renders an ASCII table under that title, and (with
|
|
46
|
+
* files.tables) writes its CSV and JSON files named `<NNN>-<title>`. The title is required; called without one
|
|
47
|
+
* (plain JS, older code), the table still renders, without a title row, and its files are named `untitled`, with
|
|
48
|
+
* a one-time warning.
|
|
49
|
+
*/
|
|
50
|
+
table(data: string): void;
|
|
51
|
+
table(data: Row | Row[] | null | undefined, title: string): void;
|
|
52
|
+
/** `title` is the console title row (none when undefined); `heading` names the CSV/JSON files. */
|
|
53
|
+
private tableInternal;
|
|
54
|
+
/** Aligned `key : value` lines. */
|
|
55
|
+
row(data: Row | null | undefined): void;
|
|
56
|
+
tree(heading: string, fieldsOrFirst?: Fields | unknown, ...rest: unknown[]): void;
|
|
57
|
+
/** `resolved("msg")` or `resolved("heading", fields | ...pairs)` as a SUCCESS tree. */
|
|
58
|
+
resolved(heading: string, fieldsOrFirst?: Fields | unknown, ...rest: unknown[]): void;
|
|
59
|
+
/**
|
|
60
|
+
* log("message") -> level-labelled line
|
|
61
|
+
* log(obj | array | map) -> table / indexed list
|
|
62
|
+
* log("heading", {k: v}) -> key/value tree
|
|
63
|
+
* log("heading", "k", v, ..) -> key/value tree from pairs
|
|
64
|
+
* log("heading", array|value)-> "heading: value" (arrays render as an indexed list)
|
|
65
|
+
*/
|
|
66
|
+
log(message: string): void;
|
|
67
|
+
log(obj: unknown): void;
|
|
68
|
+
log(heading: string, fields: Fields): void;
|
|
69
|
+
log(heading: string, ...pairsOrValue: unknown[]): void;
|
|
70
|
+
private toFields;
|
|
71
|
+
private logObject;
|
|
72
|
+
private logHeadingValue;
|
|
73
|
+
private logList;
|
|
74
|
+
private renderTable;
|
|
75
|
+
private treeInternal;
|
|
76
|
+
/** `action` picks the line's own color within its intent family; without it the intent's color is used. */
|
|
77
|
+
protected msg(intent: LogIntent, label: string, message: unknown, action?: LogAction): void;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
|