@optique/logtape 1.2.0-dev.2322 → 1.2.0-dev.2329
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/README.md +105 -3
- package/dist/index.cjs +132 -48
- package/dist/index.d.cts +93 -2
- package/dist/index.d.ts +93 -2
- package/dist/index.js +133 -50
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -70,6 +70,42 @@ Features:
|
|
|
70
70
|
`"fatal"`
|
|
71
71
|
- Provides suggestions for shell completion
|
|
72
72
|
|
|
73
|
+
### `textFormatter()`
|
|
74
|
+
|
|
75
|
+
A value parser for LogTape text formatters. Parses `"jsonl"`, `"logfmt"`,
|
|
76
|
+
`"color"`, and `"plain"` into LogTape formatter functions.
|
|
77
|
+
|
|
78
|
+
~~~~ typescript
|
|
79
|
+
import { textFormatter } from "@optique/logtape";
|
|
80
|
+
import { object, option, parse } from "@optique/core";
|
|
81
|
+
|
|
82
|
+
const parser = object({
|
|
83
|
+
formatter: option("--log-format", textFormatter()),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const result = parse(parser, ["--log-format=logfmt"]);
|
|
87
|
+
// result.value.formatter is LogTape's logfmtFormatter
|
|
88
|
+
~~~~
|
|
89
|
+
|
|
90
|
+
Formats:
|
|
91
|
+
|
|
92
|
+
`"jsonl"`
|
|
93
|
+
: [JSON Lines][LogTape JSON Lines formatter] output
|
|
94
|
+
|
|
95
|
+
`"logfmt"`
|
|
96
|
+
: [logfmt][LogTape logfmt formatter] key-value output
|
|
97
|
+
|
|
98
|
+
`"color"`
|
|
99
|
+
: [ANSI-colored][LogTape ANSI color formatter] console output
|
|
100
|
+
|
|
101
|
+
`"plain"`
|
|
102
|
+
: [LogTape's default text][LogTape default text formatter] output
|
|
103
|
+
|
|
104
|
+
[LogTape JSON Lines formatter]: https://logtape.org/manual/formatters#json-lines-formatter
|
|
105
|
+
[LogTape logfmt formatter]: https://logtape.org/manual/formatters#logfmt-formatter
|
|
106
|
+
[LogTape ANSI color formatter]: https://logtape.org/manual/formatters#ansi-color-formatter
|
|
107
|
+
[LogTape default text formatter]: https://logtape.org/manual/formatters#default-text-formatter
|
|
108
|
+
|
|
73
109
|
### `verbosity()`
|
|
74
110
|
|
|
75
111
|
A parser for accumulating `-v` flags to determine log level.
|
|
@@ -152,6 +188,37 @@ const result2 = parse(parser, ["--log-output=/var/log/app.log"]);
|
|
|
152
188
|
const sink = await createSink(result1.value.output);
|
|
153
189
|
~~~~
|
|
154
190
|
|
|
191
|
+
Use `formatter` to add a text formatter option and wire it through the
|
|
192
|
+
resulting `LogOutput`:
|
|
193
|
+
|
|
194
|
+
~~~~ typescript
|
|
195
|
+
import { logOutput } from "@optique/logtape";
|
|
196
|
+
import { object, parse } from "@optique/core";
|
|
197
|
+
|
|
198
|
+
const parser = object({
|
|
199
|
+
output: logOutput({ formatter: "--log-format" }),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const result = parse(parser, ["--log-format=logfmt"]);
|
|
203
|
+
// result.value.output is a console LogOutput with logfmtFormatter
|
|
204
|
+
~~~~
|
|
205
|
+
|
|
206
|
+
You can also pass a fixed LogTape text formatter. In that case no additional
|
|
207
|
+
command-line option is added:
|
|
208
|
+
|
|
209
|
+
~~~~ typescript
|
|
210
|
+
import { logfmtFormatter } from "@logtape/logtape";
|
|
211
|
+
import { logOutput } from "@optique/logtape";
|
|
212
|
+
import { object, parse } from "@optique/core";
|
|
213
|
+
|
|
214
|
+
const parser = object({
|
|
215
|
+
output: logOutput({ formatter: logfmtFormatter }),
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const result = parse(parser, ["--log-output=/var/log/app.log"]);
|
|
219
|
+
// result.value.output is a file LogOutput with logfmtFormatter
|
|
220
|
+
~~~~
|
|
221
|
+
|
|
155
222
|
### `loggingOptions()`
|
|
156
223
|
|
|
157
224
|
A preset that combines log level and log output options into a single group.
|
|
@@ -206,9 +273,21 @@ Common options:
|
|
|
206
273
|
|
|
207
274
|
- `output.enabled`: Whether to enable log output option (default: `true`)
|
|
208
275
|
- `output.long`: Long option name for output (default: `"--log-output"`)
|
|
276
|
+
- `formatter`: Text formatter or long option name for output format
|
|
209
277
|
- `groupLabel`: Label for option group in help text (default:
|
|
210
278
|
`"Logging options"`)
|
|
211
279
|
|
|
280
|
+
Set `formatter` at the top level when using the preset:
|
|
281
|
+
|
|
282
|
+
~~~~ typescript
|
|
283
|
+
const parser = object({
|
|
284
|
+
logging: loggingOptions({
|
|
285
|
+
level: "option",
|
|
286
|
+
formatter: "--log-format",
|
|
287
|
+
}),
|
|
288
|
+
});
|
|
289
|
+
~~~~
|
|
290
|
+
|
|
212
291
|
### `createLoggingConfig()`
|
|
213
292
|
|
|
214
293
|
Converts parsed logging options into a LogTape configuration object.
|
|
@@ -240,6 +319,7 @@ if (result.success) {
|
|
|
240
319
|
Creates a console sink with configurable stream selection.
|
|
241
320
|
|
|
242
321
|
~~~~ typescript
|
|
322
|
+
import { logfmtFormatter } from "@logtape/logtape";
|
|
243
323
|
import { createConsoleSink } from "@optique/logtape";
|
|
244
324
|
|
|
245
325
|
// Write to stderr (default)
|
|
@@ -253,6 +333,20 @@ const sink3 = createConsoleSink({
|
|
|
253
333
|
streamResolver: (level) =>
|
|
254
334
|
level === "error" || level === "fatal" ? "stderr" : "stdout",
|
|
255
335
|
});
|
|
336
|
+
|
|
337
|
+
// Structured logfmt output
|
|
338
|
+
const sink4 = createConsoleSink({
|
|
339
|
+
formatter: logfmtFormatter,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Custom console formatting with multiple console arguments
|
|
343
|
+
const sink5 = createConsoleSink({
|
|
344
|
+
formatter: (record) => [
|
|
345
|
+
"%s %o",
|
|
346
|
+
record.level.toUpperCase(),
|
|
347
|
+
record.properties,
|
|
348
|
+
],
|
|
349
|
+
});
|
|
256
350
|
~~~~
|
|
257
351
|
|
|
258
352
|
### `createSink()`
|
|
@@ -260,13 +354,21 @@ const sink3 = createConsoleSink({
|
|
|
260
354
|
Creates a LogTape sink from a `LogOutput` value.
|
|
261
355
|
|
|
262
356
|
~~~~ typescript
|
|
357
|
+
import { logfmtFormatter } from "@logtape/logtape";
|
|
263
358
|
import { createSink, type LogOutput } from "@optique/logtape";
|
|
264
359
|
|
|
265
|
-
// Console sink
|
|
266
|
-
const consoleSink = await createSink({
|
|
360
|
+
// Console sink with a formatter selected by logOutput()
|
|
361
|
+
const consoleSink = await createSink({
|
|
362
|
+
type: "console",
|
|
363
|
+
formatter: logfmtFormatter,
|
|
364
|
+
});
|
|
267
365
|
|
|
268
366
|
// File sink (requires @logtape/file package)
|
|
269
|
-
const fileSink = await createSink({
|
|
367
|
+
const fileSink = await createSink({
|
|
368
|
+
type: "file",
|
|
369
|
+
path: "/var/log/app.log",
|
|
370
|
+
formatter: logfmtFormatter,
|
|
371
|
+
});
|
|
270
372
|
~~~~
|
|
271
373
|
|
|
272
374
|
> [!NOTE]
|
package/dist/index.cjs
CHANGED
|
@@ -22,12 +22,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
24
|
const __optique_core_valueparser = __toESM(require("@optique/core/valueparser"));
|
|
25
|
+
const __logtape_logtape = __toESM(require("@logtape/logtape"));
|
|
25
26
|
const __optique_core_primitives = __toESM(require("@optique/core/primitives"));
|
|
26
27
|
const __optique_core_modifiers = __toESM(require("@optique/core/modifiers"));
|
|
27
28
|
const __optique_core_message = __toESM(require("@optique/core/message"));
|
|
28
29
|
const node_path = __toESM(require("node:path"));
|
|
29
|
-
const __optique_core_nonempty = __toESM(require("@optique/core/nonempty"));
|
|
30
30
|
const __optique_core_constructs = __toESM(require("@optique/core/constructs"));
|
|
31
|
+
const __optique_core_nonempty = __toESM(require("@optique/core/nonempty"));
|
|
31
32
|
|
|
32
33
|
//#region src/loglevel.ts
|
|
33
34
|
/**
|
|
@@ -92,6 +93,38 @@ function logLevel(options = {}) {
|
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/textformatter.ts
|
|
98
|
+
const textFormatters = {
|
|
99
|
+
jsonl: __logtape_logtape.jsonLinesFormatter,
|
|
100
|
+
logfmt: __logtape_logtape.logfmtFormatter,
|
|
101
|
+
color: __logtape_logtape.ansiColorFormatter,
|
|
102
|
+
plain: __logtape_logtape.defaultTextFormatter
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Creates a {@link ValueParser} for LogTape text formatters.
|
|
106
|
+
*
|
|
107
|
+
* This parser accepts `"jsonl"`, `"logfmt"`, `"color"`, and `"plain"` and
|
|
108
|
+
* maps them to LogTape's `jsonLinesFormatter`, `logfmtFormatter`,
|
|
109
|
+
* `ansiColorFormatter`, and `defaultTextFormatter` respectively.
|
|
110
|
+
*
|
|
111
|
+
* @returns A {@link ValueParser} that converts formatter names to
|
|
112
|
+
* LogTape text formatter functions.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* import { option } from "@optique/core";
|
|
117
|
+
* import { textFormatter } from "@optique/logtape";
|
|
118
|
+
*
|
|
119
|
+
* const parser = option("--log-format", textFormatter());
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @since 1.2.0
|
|
123
|
+
*/
|
|
124
|
+
function textFormatter() {
|
|
125
|
+
return (0, __optique_core_valueparser.biject)(textFormatters);
|
|
126
|
+
}
|
|
127
|
+
|
|
95
128
|
//#endregion
|
|
96
129
|
//#region src/verbosity.ts
|
|
97
130
|
/**
|
|
@@ -306,9 +339,41 @@ function logOutput(options = {}) {
|
|
|
306
339
|
const description = options.description ?? __optique_core_message.message`Log output destination. Use ${"-"} for console.`;
|
|
307
340
|
if (options.short) {
|
|
308
341
|
const short = options.short;
|
|
309
|
-
|
|
342
|
+
const outputParser$1 = (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)(short, long, valueParser, { description }));
|
|
343
|
+
return withFormatter(outputParser$1, options.formatter);
|
|
310
344
|
}
|
|
311
|
-
|
|
345
|
+
const outputParser = (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)(long, valueParser, { description }));
|
|
346
|
+
return withFormatter(outputParser, options.formatter);
|
|
347
|
+
}
|
|
348
|
+
function withFormatter(outputParser, formatter) {
|
|
349
|
+
if (formatter == null) return outputParser;
|
|
350
|
+
if (typeof formatter !== "string") return outputParser.map((output) => output == null ? void 0 : {
|
|
351
|
+
...output,
|
|
352
|
+
formatter
|
|
353
|
+
});
|
|
354
|
+
const formatterParser = createTextFormatterOption(formatter);
|
|
355
|
+
return (0, __optique_core_constructs.object)({
|
|
356
|
+
output: outputParser,
|
|
357
|
+
formatter: formatterParser
|
|
358
|
+
}).map(({ output, formatter: formatter$1 }) => {
|
|
359
|
+
if (formatter$1 == null) return output;
|
|
360
|
+
return {
|
|
361
|
+
...output ?? { type: "console" },
|
|
362
|
+
formatter: formatter$1
|
|
363
|
+
};
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Creates an optional parser for a text formatter option.
|
|
368
|
+
*
|
|
369
|
+
* @param long The long option name for selecting the formatter.
|
|
370
|
+
* @returns A parser that produces the selected {@link TextFormatter}, or
|
|
371
|
+
* `undefined` when the option is not present.
|
|
372
|
+
* @throws {TypeError} If `long` is not a valid option name.
|
|
373
|
+
* @since 1.2.0
|
|
374
|
+
*/
|
|
375
|
+
function createTextFormatterOption(long) {
|
|
376
|
+
return (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)(long, textFormatter(), { description: __optique_core_message.message`Log output format.` }));
|
|
312
377
|
}
|
|
313
378
|
/**
|
|
314
379
|
* Creates a console sink with configurable stream selection.
|
|
@@ -346,6 +411,7 @@ function logOutput(options = {}) {
|
|
|
346
411
|
function createConsoleSink(options = {}) {
|
|
347
412
|
const streamResolver = options.streamResolver;
|
|
348
413
|
const defaultStream = options.stream ?? "stderr";
|
|
414
|
+
const formatter = options.formatter ?? defaultConsoleFormatter;
|
|
349
415
|
const invalidStreamError = (value) => {
|
|
350
416
|
let repr;
|
|
351
417
|
if (typeof value === "string") repr = JSON.stringify(value);
|
|
@@ -361,22 +427,30 @@ function createConsoleSink(options = {}) {
|
|
|
361
427
|
return (record) => {
|
|
362
428
|
const stream = streamResolver ? streamResolver(record.level) : defaultStream;
|
|
363
429
|
if (stream !== "stdout" && stream !== "stderr") throw invalidStreamError(stream);
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (typeof part === "string") messageParts.push(part);
|
|
368
|
-
else messageParts.push(String(part));
|
|
369
|
-
}
|
|
370
|
-
const formattedMessage = messageParts.join("");
|
|
371
|
-
const ts = record.timestamp;
|
|
372
|
-
const timestamp = new Date(ts != null && !Number.isNaN(ts) ? ts : Date.now()).toISOString();
|
|
373
|
-
const category = record.category.join(".");
|
|
374
|
-
const level = record.level.toUpperCase().padEnd(7);
|
|
375
|
-
const line = `${timestamp} [${level}] ${category}: ${formattedMessage}`;
|
|
376
|
-
if (stream === "stderr") console.error(line);
|
|
377
|
-
else console.log(line);
|
|
430
|
+
const args = toConsoleArgs(formatter(record));
|
|
431
|
+
if (stream === "stderr") console.error(...args);
|
|
432
|
+
else console.log(...args);
|
|
378
433
|
};
|
|
379
434
|
}
|
|
435
|
+
function toConsoleArgs(value) {
|
|
436
|
+
if (typeof value === "string") return [value.replace(/\r?\n$/, "")];
|
|
437
|
+
if (Array.isArray(value)) return value;
|
|
438
|
+
return value == null ? [] : [value];
|
|
439
|
+
}
|
|
440
|
+
function defaultConsoleFormatter(record) {
|
|
441
|
+
const messageParts = [];
|
|
442
|
+
for (let i = 0; i < record.message.length; i++) {
|
|
443
|
+
const part = record.message[i];
|
|
444
|
+
if (typeof part === "string") messageParts.push(part);
|
|
445
|
+
else messageParts.push(String(part));
|
|
446
|
+
}
|
|
447
|
+
const formattedMessage = messageParts.join("");
|
|
448
|
+
const ts = record.timestamp;
|
|
449
|
+
const timestamp = new Date(ts != null && !Number.isNaN(ts) ? ts : Date.now()).toISOString();
|
|
450
|
+
const category = record.category.join(".");
|
|
451
|
+
const level = record.level.toUpperCase().padEnd(7);
|
|
452
|
+
return `${timestamp} [${level}] ${category}: ${formattedMessage}`;
|
|
453
|
+
}
|
|
380
454
|
/**
|
|
381
455
|
* Creates a sink from a {@link LogOutput} destination.
|
|
382
456
|
*
|
|
@@ -409,7 +483,10 @@ function createConsoleSink(options = {}) {
|
|
|
409
483
|
* @since 0.8.0
|
|
410
484
|
*/
|
|
411
485
|
async function createSink(output, consoleSinkOptions = {}) {
|
|
412
|
-
if (output.type === "console") return createConsoleSink(
|
|
486
|
+
if (output.type === "console") return createConsoleSink({
|
|
487
|
+
...consoleSinkOptions,
|
|
488
|
+
formatter: consoleSinkOptions.formatter ?? output.formatter
|
|
489
|
+
});
|
|
413
490
|
let getFileSink;
|
|
414
491
|
try {
|
|
415
492
|
({getFileSink} = await import("@logtape/file"));
|
|
@@ -421,7 +498,7 @@ async function createSink(output, consoleSinkOptions = {}) {
|
|
|
421
498
|
|
|
422
499
|
Original error: ${e}`);
|
|
423
500
|
}
|
|
424
|
-
return getFileSink(output.path);
|
|
501
|
+
return getFileSink(output.path, output.formatter == null ? void 0 : { formatter: output.formatter });
|
|
425
502
|
}
|
|
426
503
|
|
|
427
504
|
//#endregion
|
|
@@ -482,6 +559,7 @@ function loggingOptions(config) {
|
|
|
482
559
|
const groupLabel = config.groupLabel ?? "Logging options";
|
|
483
560
|
const outputEnabled = config.output?.enabled !== false;
|
|
484
561
|
const outputLong = config.output?.long ?? "--log-output";
|
|
562
|
+
const outputFormatter = config.formatter;
|
|
485
563
|
let levelParser;
|
|
486
564
|
switch (config.level) {
|
|
487
565
|
case "option": {
|
|
@@ -513,35 +591,40 @@ function loggingOptions(config) {
|
|
|
513
591
|
}
|
|
514
592
|
default: throw new TypeError(`Unsupported level configuration: ${String(config.level)}. Expected "option", "verbosity", or "debug".`);
|
|
515
593
|
}
|
|
516
|
-
const defaultOutput =
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
594
|
+
const defaultOutput = typeof outputFormatter === "function" ? {
|
|
595
|
+
type: "console",
|
|
596
|
+
formatter: outputFormatter
|
|
597
|
+
} : { type: "console" };
|
|
598
|
+
let outputParser;
|
|
599
|
+
if (outputEnabled) outputParser = (0, __optique_core_modifiers.withDefault)(logOutput({
|
|
600
|
+
long: outputLong,
|
|
601
|
+
formatter: outputFormatter
|
|
602
|
+
}), defaultOutput);
|
|
603
|
+
else if (typeof outputFormatter === "string") outputParser = createTextFormatterOption(outputFormatter).map((formatter) => formatter == null ? defaultOutput : {
|
|
604
|
+
type: "console",
|
|
605
|
+
formatter
|
|
606
|
+
});
|
|
607
|
+
else outputParser = {
|
|
608
|
+
mode: "sync",
|
|
609
|
+
$valueType: [],
|
|
610
|
+
$stateType: [],
|
|
611
|
+
priority: 0,
|
|
612
|
+
usage: [],
|
|
613
|
+
leadingNames: /* @__PURE__ */ new Set(),
|
|
614
|
+
acceptingAnyToken: false,
|
|
615
|
+
initialState: void 0,
|
|
616
|
+
parse: (context) => ({
|
|
617
|
+
success: true,
|
|
618
|
+
next: context,
|
|
619
|
+
consumed: []
|
|
620
|
+
}),
|
|
621
|
+
complete: () => ({
|
|
622
|
+
success: true,
|
|
623
|
+
value: defaultOutput
|
|
624
|
+
}),
|
|
625
|
+
*suggest() {},
|
|
626
|
+
getDocFragments: () => ({ fragments: [] })
|
|
627
|
+
};
|
|
545
628
|
const innerParser = (0, __optique_core_constructs.object)({
|
|
546
629
|
logLevel: levelParser,
|
|
547
630
|
logOutput: outputParser
|
|
@@ -620,4 +703,5 @@ exports.debug = debug;
|
|
|
620
703
|
exports.logLevel = logLevel;
|
|
621
704
|
exports.logOutput = logOutput;
|
|
622
705
|
exports.loggingOptions = loggingOptions;
|
|
706
|
+
exports.textFormatter = textFormatter;
|
|
623
707
|
exports.verbosity = verbosity;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Config, LogLevel, LogLevel as LogLevel$1, LogRecord, Sink, Sink as Sink$1 } from "@logtape/logtape";
|
|
1
|
+
import { Config, ConsoleFormatter, LogLevel, LogLevel as LogLevel$1, LogRecord, Sink, Sink as Sink$1, TextFormatter } from "@logtape/logtape";
|
|
2
2
|
import { NonEmptyString, ValueParser } from "@optique/core/valueparser";
|
|
3
3
|
import { Message } from "@optique/core/message";
|
|
4
4
|
import { FluentParser } from "@optique/core/fluent";
|
|
@@ -73,6 +73,34 @@ interface LogLevelOptions {
|
|
|
73
73
|
*/
|
|
74
74
|
declare function logLevel(options?: LogLevelOptions): ValueParser<"sync", LogLevel$1>;
|
|
75
75
|
//#endregion
|
|
76
|
+
//#region src/textformatter.d.ts
|
|
77
|
+
/**
|
|
78
|
+
* The names accepted by {@link textFormatter}.
|
|
79
|
+
* @since 1.2.0
|
|
80
|
+
*/
|
|
81
|
+
type TextFormatterName = "jsonl" | "logfmt" | "color" | "plain";
|
|
82
|
+
/**
|
|
83
|
+
* Creates a {@link ValueParser} for LogTape text formatters.
|
|
84
|
+
*
|
|
85
|
+
* This parser accepts `"jsonl"`, `"logfmt"`, `"color"`, and `"plain"` and
|
|
86
|
+
* maps them to LogTape's `jsonLinesFormatter`, `logfmtFormatter`,
|
|
87
|
+
* `ansiColorFormatter`, and `defaultTextFormatter` respectively.
|
|
88
|
+
*
|
|
89
|
+
* @returns A {@link ValueParser} that converts formatter names to
|
|
90
|
+
* LogTape text formatter functions.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* import { option } from "@optique/core";
|
|
95
|
+
* import { textFormatter } from "@optique/logtape";
|
|
96
|
+
*
|
|
97
|
+
* const parser = option("--log-format", textFormatter());
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @since 1.2.0
|
|
101
|
+
*/
|
|
102
|
+
declare function textFormatter(): ValueParser<"sync", TextFormatter>;
|
|
103
|
+
//#endregion
|
|
76
104
|
//#region src/verbosity.d.ts
|
|
77
105
|
/**
|
|
78
106
|
* Options for creating a verbosity parser.
|
|
@@ -229,9 +257,11 @@ declare function debug(options?: DebugOptions): FluentParser<"sync", LogLevel$1,
|
|
|
229
257
|
*/
|
|
230
258
|
type LogOutput = {
|
|
231
259
|
readonly type: "console";
|
|
260
|
+
readonly formatter?: TextFormatter;
|
|
232
261
|
} | {
|
|
233
262
|
readonly type: "file";
|
|
234
263
|
readonly path: string;
|
|
264
|
+
readonly formatter?: TextFormatter;
|
|
235
265
|
};
|
|
236
266
|
/**
|
|
237
267
|
* Options for configuring console sink creation.
|
|
@@ -258,6 +288,16 @@ interface ConsoleSinkOptions {
|
|
|
258
288
|
* ```
|
|
259
289
|
*/
|
|
260
290
|
readonly streamResolver?: (level: LogLevel$1) => "stdout" | "stderr";
|
|
291
|
+
/**
|
|
292
|
+
* A formatter for converting log records to console output.
|
|
293
|
+
* Text formatters return one string argument, while console formatters
|
|
294
|
+
* return the full argument list passed to the selected console method.
|
|
295
|
+
*
|
|
296
|
+
* If omitted, records are formatted as
|
|
297
|
+
* `ISO_TIMESTAMP [LEVEL] category: message`.
|
|
298
|
+
* @since 1.2.0
|
|
299
|
+
*/
|
|
300
|
+
readonly formatter?: TextFormatter | ConsoleFormatter;
|
|
261
301
|
}
|
|
262
302
|
/**
|
|
263
303
|
* Options for creating a log output parser.
|
|
@@ -282,6 +322,26 @@ interface LogOutputOptions {
|
|
|
282
322
|
* Description to show in help text.
|
|
283
323
|
*/
|
|
284
324
|
readonly description?: Message;
|
|
325
|
+
/**
|
|
326
|
+
* Text formatter to apply to the selected log output, or a long option name
|
|
327
|
+
* for selecting the text formatter from the command line.
|
|
328
|
+
*
|
|
329
|
+
* When a string is specified, this adds an option that accepts `"jsonl"`,
|
|
330
|
+
* `"logfmt"`, `"color"`, and `"plain"` and stores the selected formatter in
|
|
331
|
+
* the resulting {@link LogOutput}. If the formatter option is specified
|
|
332
|
+
* without a log output option, the output defaults to console.
|
|
333
|
+
*
|
|
334
|
+
* When a formatter function is specified, it is applied to the resulting
|
|
335
|
+
* {@link LogOutput} only when the log output option itself is present.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* logOutput({ formatter: "--log-format" })
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* @since 1.2.0
|
|
343
|
+
*/
|
|
344
|
+
readonly formatter?: string | TextFormatter;
|
|
285
345
|
/**
|
|
286
346
|
* Custom error messages.
|
|
287
347
|
*/
|
|
@@ -318,6 +378,16 @@ interface LogOutputOptions {
|
|
|
318
378
|
* @since 0.8.0
|
|
319
379
|
*/
|
|
320
380
|
declare function logOutput(options?: LogOutputOptions): FluentParser<"sync", LogOutput | undefined, unknown>;
|
|
381
|
+
/**
|
|
382
|
+
* Creates an optional parser for a text formatter option.
|
|
383
|
+
*
|
|
384
|
+
* @param long The long option name for selecting the formatter.
|
|
385
|
+
* @returns A parser that produces the selected {@link TextFormatter}, or
|
|
386
|
+
* `undefined` when the option is not present.
|
|
387
|
+
* @throws {TypeError} If `long` is not a valid option name.
|
|
388
|
+
* @since 1.2.0
|
|
389
|
+
*/
|
|
390
|
+
|
|
321
391
|
/**
|
|
322
392
|
* Creates a console sink with configurable stream selection.
|
|
323
393
|
*
|
|
@@ -444,6 +514,13 @@ interface LoggingOptionsWithLevel {
|
|
|
444
514
|
* Configuration for log output option.
|
|
445
515
|
*/
|
|
446
516
|
readonly output?: LogOutputConfig;
|
|
517
|
+
/**
|
|
518
|
+
* Text formatter to apply to the generated sink, or a long option name for
|
|
519
|
+
* selecting the text formatter from the command line.
|
|
520
|
+
*
|
|
521
|
+
* @since 1.2.0
|
|
522
|
+
*/
|
|
523
|
+
readonly formatter?: string | TextFormatter;
|
|
447
524
|
/**
|
|
448
525
|
* Label for the option group in help text.
|
|
449
526
|
* @default `"Logging options"`
|
|
@@ -478,6 +555,13 @@ interface LoggingOptionsWithVerbosity {
|
|
|
478
555
|
* Configuration for log output option.
|
|
479
556
|
*/
|
|
480
557
|
readonly output?: LogOutputConfig;
|
|
558
|
+
/**
|
|
559
|
+
* Text formatter to apply to the generated sink, or a long option name for
|
|
560
|
+
* selecting the text formatter from the command line.
|
|
561
|
+
*
|
|
562
|
+
* @since 1.2.0
|
|
563
|
+
*/
|
|
564
|
+
readonly formatter?: string | TextFormatter;
|
|
481
565
|
/**
|
|
482
566
|
* Label for the option group in help text.
|
|
483
567
|
* @default `"Logging options"`
|
|
@@ -517,6 +601,13 @@ interface LoggingOptionsWithDebug {
|
|
|
517
601
|
* Configuration for log output option.
|
|
518
602
|
*/
|
|
519
603
|
readonly output?: LogOutputConfig;
|
|
604
|
+
/**
|
|
605
|
+
* Text formatter to apply to the generated sink, or a long option name for
|
|
606
|
+
* selecting the text formatter from the command line.
|
|
607
|
+
*
|
|
608
|
+
* @since 1.2.0
|
|
609
|
+
*/
|
|
610
|
+
readonly formatter?: string | TextFormatter;
|
|
520
611
|
/**
|
|
521
612
|
* Label for the option group in help text.
|
|
522
613
|
* @default `"Logging options"`
|
|
@@ -637,4 +728,4 @@ declare function loggingOptions(config: LoggingOptionsConfig): FluentParser<"syn
|
|
|
637
728
|
*/
|
|
638
729
|
declare function createLoggingConfig(options: LoggingOptionsResult, consoleSinkOptions?: ConsoleSinkOptions, additionalConfig?: Partial<Config<string, string>>): Promise<Config<string, string>>;
|
|
639
730
|
//#endregion
|
|
640
|
-
export { type ConsoleSinkOptions, type DebugOptions, LOG_LEVELS, type LogLevel, type LogLevelOptions, type LogOutput, type LogOutputConfig, type LogOutputOptions, type LogRecord, type LoggingOptionsConfig, type LoggingOptionsResult, type LoggingOptionsWithDebug, type LoggingOptionsWithLevel, type LoggingOptionsWithVerbosity, type Sink, type VerbosityOptions, createConsoleSink, createLoggingConfig, createSink, debug, logLevel, logOutput, loggingOptions, verbosity };
|
|
731
|
+
export { type ConsoleSinkOptions, type DebugOptions, LOG_LEVELS, type LogLevel, type LogLevelOptions, type LogOutput, type LogOutputConfig, type LogOutputOptions, type LogRecord, type LoggingOptionsConfig, type LoggingOptionsResult, type LoggingOptionsWithDebug, type LoggingOptionsWithLevel, type LoggingOptionsWithVerbosity, type Sink, type TextFormatterName, type VerbosityOptions, createConsoleSink, createLoggingConfig, createSink, debug, logLevel, logOutput, loggingOptions, textFormatter, verbosity };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NonEmptyString, ValueParser } from "@optique/core/valueparser";
|
|
2
|
+
import { Config, ConsoleFormatter, LogLevel, LogLevel as LogLevel$1, LogRecord, Sink, Sink as Sink$1, TextFormatter } from "@logtape/logtape";
|
|
2
3
|
import { Message } from "@optique/core/message";
|
|
3
|
-
import { Config, LogLevel, LogLevel as LogLevel$1, LogRecord, Sink, Sink as Sink$1 } from "@logtape/logtape";
|
|
4
4
|
import { FluentParser } from "@optique/core/fluent";
|
|
5
5
|
|
|
6
6
|
//#region src/loglevel.d.ts
|
|
@@ -73,6 +73,34 @@ interface LogLevelOptions {
|
|
|
73
73
|
*/
|
|
74
74
|
declare function logLevel(options?: LogLevelOptions): ValueParser<"sync", LogLevel$1>;
|
|
75
75
|
//#endregion
|
|
76
|
+
//#region src/textformatter.d.ts
|
|
77
|
+
/**
|
|
78
|
+
* The names accepted by {@link textFormatter}.
|
|
79
|
+
* @since 1.2.0
|
|
80
|
+
*/
|
|
81
|
+
type TextFormatterName = "jsonl" | "logfmt" | "color" | "plain";
|
|
82
|
+
/**
|
|
83
|
+
* Creates a {@link ValueParser} for LogTape text formatters.
|
|
84
|
+
*
|
|
85
|
+
* This parser accepts `"jsonl"`, `"logfmt"`, `"color"`, and `"plain"` and
|
|
86
|
+
* maps them to LogTape's `jsonLinesFormatter`, `logfmtFormatter`,
|
|
87
|
+
* `ansiColorFormatter`, and `defaultTextFormatter` respectively.
|
|
88
|
+
*
|
|
89
|
+
* @returns A {@link ValueParser} that converts formatter names to
|
|
90
|
+
* LogTape text formatter functions.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* import { option } from "@optique/core";
|
|
95
|
+
* import { textFormatter } from "@optique/logtape";
|
|
96
|
+
*
|
|
97
|
+
* const parser = option("--log-format", textFormatter());
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @since 1.2.0
|
|
101
|
+
*/
|
|
102
|
+
declare function textFormatter(): ValueParser<"sync", TextFormatter>;
|
|
103
|
+
//#endregion
|
|
76
104
|
//#region src/verbosity.d.ts
|
|
77
105
|
/**
|
|
78
106
|
* Options for creating a verbosity parser.
|
|
@@ -229,9 +257,11 @@ declare function debug(options?: DebugOptions): FluentParser<"sync", LogLevel$1,
|
|
|
229
257
|
*/
|
|
230
258
|
type LogOutput = {
|
|
231
259
|
readonly type: "console";
|
|
260
|
+
readonly formatter?: TextFormatter;
|
|
232
261
|
} | {
|
|
233
262
|
readonly type: "file";
|
|
234
263
|
readonly path: string;
|
|
264
|
+
readonly formatter?: TextFormatter;
|
|
235
265
|
};
|
|
236
266
|
/**
|
|
237
267
|
* Options for configuring console sink creation.
|
|
@@ -258,6 +288,16 @@ interface ConsoleSinkOptions {
|
|
|
258
288
|
* ```
|
|
259
289
|
*/
|
|
260
290
|
readonly streamResolver?: (level: LogLevel$1) => "stdout" | "stderr";
|
|
291
|
+
/**
|
|
292
|
+
* A formatter for converting log records to console output.
|
|
293
|
+
* Text formatters return one string argument, while console formatters
|
|
294
|
+
* return the full argument list passed to the selected console method.
|
|
295
|
+
*
|
|
296
|
+
* If omitted, records are formatted as
|
|
297
|
+
* `ISO_TIMESTAMP [LEVEL] category: message`.
|
|
298
|
+
* @since 1.2.0
|
|
299
|
+
*/
|
|
300
|
+
readonly formatter?: TextFormatter | ConsoleFormatter;
|
|
261
301
|
}
|
|
262
302
|
/**
|
|
263
303
|
* Options for creating a log output parser.
|
|
@@ -282,6 +322,26 @@ interface LogOutputOptions {
|
|
|
282
322
|
* Description to show in help text.
|
|
283
323
|
*/
|
|
284
324
|
readonly description?: Message;
|
|
325
|
+
/**
|
|
326
|
+
* Text formatter to apply to the selected log output, or a long option name
|
|
327
|
+
* for selecting the text formatter from the command line.
|
|
328
|
+
*
|
|
329
|
+
* When a string is specified, this adds an option that accepts `"jsonl"`,
|
|
330
|
+
* `"logfmt"`, `"color"`, and `"plain"` and stores the selected formatter in
|
|
331
|
+
* the resulting {@link LogOutput}. If the formatter option is specified
|
|
332
|
+
* without a log output option, the output defaults to console.
|
|
333
|
+
*
|
|
334
|
+
* When a formatter function is specified, it is applied to the resulting
|
|
335
|
+
* {@link LogOutput} only when the log output option itself is present.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* logOutput({ formatter: "--log-format" })
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* @since 1.2.0
|
|
343
|
+
*/
|
|
344
|
+
readonly formatter?: string | TextFormatter;
|
|
285
345
|
/**
|
|
286
346
|
* Custom error messages.
|
|
287
347
|
*/
|
|
@@ -318,6 +378,16 @@ interface LogOutputOptions {
|
|
|
318
378
|
* @since 0.8.0
|
|
319
379
|
*/
|
|
320
380
|
declare function logOutput(options?: LogOutputOptions): FluentParser<"sync", LogOutput | undefined, unknown>;
|
|
381
|
+
/**
|
|
382
|
+
* Creates an optional parser for a text formatter option.
|
|
383
|
+
*
|
|
384
|
+
* @param long The long option name for selecting the formatter.
|
|
385
|
+
* @returns A parser that produces the selected {@link TextFormatter}, or
|
|
386
|
+
* `undefined` when the option is not present.
|
|
387
|
+
* @throws {TypeError} If `long` is not a valid option name.
|
|
388
|
+
* @since 1.2.0
|
|
389
|
+
*/
|
|
390
|
+
|
|
321
391
|
/**
|
|
322
392
|
* Creates a console sink with configurable stream selection.
|
|
323
393
|
*
|
|
@@ -444,6 +514,13 @@ interface LoggingOptionsWithLevel {
|
|
|
444
514
|
* Configuration for log output option.
|
|
445
515
|
*/
|
|
446
516
|
readonly output?: LogOutputConfig;
|
|
517
|
+
/**
|
|
518
|
+
* Text formatter to apply to the generated sink, or a long option name for
|
|
519
|
+
* selecting the text formatter from the command line.
|
|
520
|
+
*
|
|
521
|
+
* @since 1.2.0
|
|
522
|
+
*/
|
|
523
|
+
readonly formatter?: string | TextFormatter;
|
|
447
524
|
/**
|
|
448
525
|
* Label for the option group in help text.
|
|
449
526
|
* @default `"Logging options"`
|
|
@@ -478,6 +555,13 @@ interface LoggingOptionsWithVerbosity {
|
|
|
478
555
|
* Configuration for log output option.
|
|
479
556
|
*/
|
|
480
557
|
readonly output?: LogOutputConfig;
|
|
558
|
+
/**
|
|
559
|
+
* Text formatter to apply to the generated sink, or a long option name for
|
|
560
|
+
* selecting the text formatter from the command line.
|
|
561
|
+
*
|
|
562
|
+
* @since 1.2.0
|
|
563
|
+
*/
|
|
564
|
+
readonly formatter?: string | TextFormatter;
|
|
481
565
|
/**
|
|
482
566
|
* Label for the option group in help text.
|
|
483
567
|
* @default `"Logging options"`
|
|
@@ -517,6 +601,13 @@ interface LoggingOptionsWithDebug {
|
|
|
517
601
|
* Configuration for log output option.
|
|
518
602
|
*/
|
|
519
603
|
readonly output?: LogOutputConfig;
|
|
604
|
+
/**
|
|
605
|
+
* Text formatter to apply to the generated sink, or a long option name for
|
|
606
|
+
* selecting the text formatter from the command line.
|
|
607
|
+
*
|
|
608
|
+
* @since 1.2.0
|
|
609
|
+
*/
|
|
610
|
+
readonly formatter?: string | TextFormatter;
|
|
520
611
|
/**
|
|
521
612
|
* Label for the option group in help text.
|
|
522
613
|
* @default `"Logging options"`
|
|
@@ -637,4 +728,4 @@ declare function loggingOptions(config: LoggingOptionsConfig): FluentParser<"syn
|
|
|
637
728
|
*/
|
|
638
729
|
declare function createLoggingConfig(options: LoggingOptionsResult, consoleSinkOptions?: ConsoleSinkOptions, additionalConfig?: Partial<Config<string, string>>): Promise<Config<string, string>>;
|
|
639
730
|
//#endregion
|
|
640
|
-
export { type ConsoleSinkOptions, type DebugOptions, LOG_LEVELS, type LogLevel, type LogLevelOptions, type LogOutput, type LogOutputConfig, type LogOutputOptions, type LogRecord, type LoggingOptionsConfig, type LoggingOptionsResult, type LoggingOptionsWithDebug, type LoggingOptionsWithLevel, type LoggingOptionsWithVerbosity, type Sink, type VerbosityOptions, createConsoleSink, createLoggingConfig, createSink, debug, logLevel, logOutput, loggingOptions, verbosity };
|
|
731
|
+
export { type ConsoleSinkOptions, type DebugOptions, LOG_LEVELS, type LogLevel, type LogLevelOptions, type LogOutput, type LogOutputConfig, type LogOutputOptions, type LogRecord, type LoggingOptionsConfig, type LoggingOptionsResult, type LoggingOptionsWithDebug, type LoggingOptionsWithLevel, type LoggingOptionsWithVerbosity, type Sink, type TextFormatterName, type VerbosityOptions, createConsoleSink, createLoggingConfig, createSink, debug, logLevel, logOutput, loggingOptions, textFormatter, verbosity };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { choice } from "@optique/core/valueparser";
|
|
1
|
+
import { biject, choice } from "@optique/core/valueparser";
|
|
2
|
+
import { ansiColorFormatter, defaultTextFormatter, jsonLinesFormatter, logfmtFormatter } from "@logtape/logtape";
|
|
2
3
|
import { flag, option } from "@optique/core/primitives";
|
|
3
4
|
import { map, multiple, optional, withDefault } from "@optique/core/modifiers";
|
|
4
5
|
import { message } from "@optique/core/message";
|
|
5
6
|
import { basename } from "node:path";
|
|
6
|
-
import { ensureNonEmptyString } from "@optique/core/nonempty";
|
|
7
7
|
import { group, object } from "@optique/core/constructs";
|
|
8
|
+
import { ensureNonEmptyString } from "@optique/core/nonempty";
|
|
8
9
|
|
|
9
10
|
//#region src/loglevel.ts
|
|
10
11
|
/**
|
|
@@ -69,6 +70,38 @@ function logLevel(options = {}) {
|
|
|
69
70
|
});
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/textformatter.ts
|
|
75
|
+
const textFormatters = {
|
|
76
|
+
jsonl: jsonLinesFormatter,
|
|
77
|
+
logfmt: logfmtFormatter,
|
|
78
|
+
color: ansiColorFormatter,
|
|
79
|
+
plain: defaultTextFormatter
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Creates a {@link ValueParser} for LogTape text formatters.
|
|
83
|
+
*
|
|
84
|
+
* This parser accepts `"jsonl"`, `"logfmt"`, `"color"`, and `"plain"` and
|
|
85
|
+
* maps them to LogTape's `jsonLinesFormatter`, `logfmtFormatter`,
|
|
86
|
+
* `ansiColorFormatter`, and `defaultTextFormatter` respectively.
|
|
87
|
+
*
|
|
88
|
+
* @returns A {@link ValueParser} that converts formatter names to
|
|
89
|
+
* LogTape text formatter functions.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* import { option } from "@optique/core";
|
|
94
|
+
* import { textFormatter } from "@optique/logtape";
|
|
95
|
+
*
|
|
96
|
+
* const parser = option("--log-format", textFormatter());
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @since 1.2.0
|
|
100
|
+
*/
|
|
101
|
+
function textFormatter() {
|
|
102
|
+
return biject(textFormatters);
|
|
103
|
+
}
|
|
104
|
+
|
|
72
105
|
//#endregion
|
|
73
106
|
//#region src/verbosity.ts
|
|
74
107
|
/**
|
|
@@ -283,9 +316,41 @@ function logOutput(options = {}) {
|
|
|
283
316
|
const description = options.description ?? message`Log output destination. Use ${"-"} for console.`;
|
|
284
317
|
if (options.short) {
|
|
285
318
|
const short = options.short;
|
|
286
|
-
|
|
319
|
+
const outputParser$1 = optional(option(short, long, valueParser, { description }));
|
|
320
|
+
return withFormatter(outputParser$1, options.formatter);
|
|
287
321
|
}
|
|
288
|
-
|
|
322
|
+
const outputParser = optional(option(long, valueParser, { description }));
|
|
323
|
+
return withFormatter(outputParser, options.formatter);
|
|
324
|
+
}
|
|
325
|
+
function withFormatter(outputParser, formatter) {
|
|
326
|
+
if (formatter == null) return outputParser;
|
|
327
|
+
if (typeof formatter !== "string") return outputParser.map((output) => output == null ? void 0 : {
|
|
328
|
+
...output,
|
|
329
|
+
formatter
|
|
330
|
+
});
|
|
331
|
+
const formatterParser = createTextFormatterOption(formatter);
|
|
332
|
+
return object({
|
|
333
|
+
output: outputParser,
|
|
334
|
+
formatter: formatterParser
|
|
335
|
+
}).map(({ output, formatter: formatter$1 }) => {
|
|
336
|
+
if (formatter$1 == null) return output;
|
|
337
|
+
return {
|
|
338
|
+
...output ?? { type: "console" },
|
|
339
|
+
formatter: formatter$1
|
|
340
|
+
};
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Creates an optional parser for a text formatter option.
|
|
345
|
+
*
|
|
346
|
+
* @param long The long option name for selecting the formatter.
|
|
347
|
+
* @returns A parser that produces the selected {@link TextFormatter}, or
|
|
348
|
+
* `undefined` when the option is not present.
|
|
349
|
+
* @throws {TypeError} If `long` is not a valid option name.
|
|
350
|
+
* @since 1.2.0
|
|
351
|
+
*/
|
|
352
|
+
function createTextFormatterOption(long) {
|
|
353
|
+
return optional(option(long, textFormatter(), { description: message`Log output format.` }));
|
|
289
354
|
}
|
|
290
355
|
/**
|
|
291
356
|
* Creates a console sink with configurable stream selection.
|
|
@@ -323,6 +388,7 @@ function logOutput(options = {}) {
|
|
|
323
388
|
function createConsoleSink(options = {}) {
|
|
324
389
|
const streamResolver = options.streamResolver;
|
|
325
390
|
const defaultStream = options.stream ?? "stderr";
|
|
391
|
+
const formatter = options.formatter ?? defaultConsoleFormatter;
|
|
326
392
|
const invalidStreamError = (value) => {
|
|
327
393
|
let repr;
|
|
328
394
|
if (typeof value === "string") repr = JSON.stringify(value);
|
|
@@ -338,22 +404,30 @@ function createConsoleSink(options = {}) {
|
|
|
338
404
|
return (record) => {
|
|
339
405
|
const stream = streamResolver ? streamResolver(record.level) : defaultStream;
|
|
340
406
|
if (stream !== "stdout" && stream !== "stderr") throw invalidStreamError(stream);
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (typeof part === "string") messageParts.push(part);
|
|
345
|
-
else messageParts.push(String(part));
|
|
346
|
-
}
|
|
347
|
-
const formattedMessage = messageParts.join("");
|
|
348
|
-
const ts = record.timestamp;
|
|
349
|
-
const timestamp = new Date(ts != null && !Number.isNaN(ts) ? ts : Date.now()).toISOString();
|
|
350
|
-
const category = record.category.join(".");
|
|
351
|
-
const level = record.level.toUpperCase().padEnd(7);
|
|
352
|
-
const line = `${timestamp} [${level}] ${category}: ${formattedMessage}`;
|
|
353
|
-
if (stream === "stderr") console.error(line);
|
|
354
|
-
else console.log(line);
|
|
407
|
+
const args = toConsoleArgs(formatter(record));
|
|
408
|
+
if (stream === "stderr") console.error(...args);
|
|
409
|
+
else console.log(...args);
|
|
355
410
|
};
|
|
356
411
|
}
|
|
412
|
+
function toConsoleArgs(value) {
|
|
413
|
+
if (typeof value === "string") return [value.replace(/\r?\n$/, "")];
|
|
414
|
+
if (Array.isArray(value)) return value;
|
|
415
|
+
return value == null ? [] : [value];
|
|
416
|
+
}
|
|
417
|
+
function defaultConsoleFormatter(record) {
|
|
418
|
+
const messageParts = [];
|
|
419
|
+
for (let i = 0; i < record.message.length; i++) {
|
|
420
|
+
const part = record.message[i];
|
|
421
|
+
if (typeof part === "string") messageParts.push(part);
|
|
422
|
+
else messageParts.push(String(part));
|
|
423
|
+
}
|
|
424
|
+
const formattedMessage = messageParts.join("");
|
|
425
|
+
const ts = record.timestamp;
|
|
426
|
+
const timestamp = new Date(ts != null && !Number.isNaN(ts) ? ts : Date.now()).toISOString();
|
|
427
|
+
const category = record.category.join(".");
|
|
428
|
+
const level = record.level.toUpperCase().padEnd(7);
|
|
429
|
+
return `${timestamp} [${level}] ${category}: ${formattedMessage}`;
|
|
430
|
+
}
|
|
357
431
|
/**
|
|
358
432
|
* Creates a sink from a {@link LogOutput} destination.
|
|
359
433
|
*
|
|
@@ -386,7 +460,10 @@ function createConsoleSink(options = {}) {
|
|
|
386
460
|
* @since 0.8.0
|
|
387
461
|
*/
|
|
388
462
|
async function createSink(output, consoleSinkOptions = {}) {
|
|
389
|
-
if (output.type === "console") return createConsoleSink(
|
|
463
|
+
if (output.type === "console") return createConsoleSink({
|
|
464
|
+
...consoleSinkOptions,
|
|
465
|
+
formatter: consoleSinkOptions.formatter ?? output.formatter
|
|
466
|
+
});
|
|
390
467
|
let getFileSink;
|
|
391
468
|
try {
|
|
392
469
|
({getFileSink} = await import("@logtape/file"));
|
|
@@ -398,7 +475,7 @@ async function createSink(output, consoleSinkOptions = {}) {
|
|
|
398
475
|
|
|
399
476
|
Original error: ${e}`);
|
|
400
477
|
}
|
|
401
|
-
return getFileSink(output.path);
|
|
478
|
+
return getFileSink(output.path, output.formatter == null ? void 0 : { formatter: output.formatter });
|
|
402
479
|
}
|
|
403
480
|
|
|
404
481
|
//#endregion
|
|
@@ -459,6 +536,7 @@ function loggingOptions(config) {
|
|
|
459
536
|
const groupLabel = config.groupLabel ?? "Logging options";
|
|
460
537
|
const outputEnabled = config.output?.enabled !== false;
|
|
461
538
|
const outputLong = config.output?.long ?? "--log-output";
|
|
539
|
+
const outputFormatter = config.formatter;
|
|
462
540
|
let levelParser;
|
|
463
541
|
switch (config.level) {
|
|
464
542
|
case "option": {
|
|
@@ -490,35 +568,40 @@ function loggingOptions(config) {
|
|
|
490
568
|
}
|
|
491
569
|
default: throw new TypeError(`Unsupported level configuration: ${String(config.level)}. Expected "option", "verbosity", or "debug".`);
|
|
492
570
|
}
|
|
493
|
-
const defaultOutput =
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
571
|
+
const defaultOutput = typeof outputFormatter === "function" ? {
|
|
572
|
+
type: "console",
|
|
573
|
+
formatter: outputFormatter
|
|
574
|
+
} : { type: "console" };
|
|
575
|
+
let outputParser;
|
|
576
|
+
if (outputEnabled) outputParser = withDefault(logOutput({
|
|
577
|
+
long: outputLong,
|
|
578
|
+
formatter: outputFormatter
|
|
579
|
+
}), defaultOutput);
|
|
580
|
+
else if (typeof outputFormatter === "string") outputParser = createTextFormatterOption(outputFormatter).map((formatter) => formatter == null ? defaultOutput : {
|
|
581
|
+
type: "console",
|
|
582
|
+
formatter
|
|
583
|
+
});
|
|
584
|
+
else outputParser = {
|
|
585
|
+
mode: "sync",
|
|
586
|
+
$valueType: [],
|
|
587
|
+
$stateType: [],
|
|
588
|
+
priority: 0,
|
|
589
|
+
usage: [],
|
|
590
|
+
leadingNames: /* @__PURE__ */ new Set(),
|
|
591
|
+
acceptingAnyToken: false,
|
|
592
|
+
initialState: void 0,
|
|
593
|
+
parse: (context) => ({
|
|
594
|
+
success: true,
|
|
595
|
+
next: context,
|
|
596
|
+
consumed: []
|
|
597
|
+
}),
|
|
598
|
+
complete: () => ({
|
|
599
|
+
success: true,
|
|
600
|
+
value: defaultOutput
|
|
601
|
+
}),
|
|
602
|
+
*suggest() {},
|
|
603
|
+
getDocFragments: () => ({ fragments: [] })
|
|
604
|
+
};
|
|
522
605
|
const innerParser = object({
|
|
523
606
|
logLevel: levelParser,
|
|
524
607
|
logOutput: outputParser
|
|
@@ -589,4 +672,4 @@ async function createLoggingConfig(options, consoleSinkOptions = {}, additionalC
|
|
|
589
672
|
}
|
|
590
673
|
|
|
591
674
|
//#endregion
|
|
592
|
-
export { LOG_LEVELS, createConsoleSink, createLoggingConfig, createSink, debug, logLevel, logOutput, loggingOptions, verbosity };
|
|
675
|
+
export { LOG_LEVELS, createConsoleSink, createLoggingConfig, createSink, debug, logLevel, logOutput, loggingOptions, textFormatter, verbosity };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/logtape",
|
|
3
|
-
"version": "1.2.0-dev.
|
|
3
|
+
"version": "1.2.0-dev.2329",
|
|
4
4
|
"description": "LogTape logging integration for Optique CLI parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
},
|
|
61
61
|
"sideEffects": false,
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@logtape/file": "^2.
|
|
64
|
-
"@logtape/logtape": "^2.
|
|
63
|
+
"@logtape/file": "^2.2.2",
|
|
64
|
+
"@logtape/logtape": "^2.2.2"
|
|
65
65
|
},
|
|
66
66
|
"peerDependenciesMeta": {
|
|
67
67
|
"@logtape/file": {
|
|
@@ -69,11 +69,11 @@
|
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@optique/core": "1.2.0-dev.
|
|
72
|
+
"@optique/core": "1.2.0-dev.2329+7836254a"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@logtape/file": "^2.
|
|
76
|
-
"@logtape/logtape": "^2.
|
|
75
|
+
"@logtape/file": "^2.2.2",
|
|
76
|
+
"@logtape/logtape": "^2.2.2",
|
|
77
77
|
"@types/node": "^24.0.0",
|
|
78
78
|
"tsdown": "^0.13.0",
|
|
79
79
|
"typescript": "^5.8.3"
|