@ddd-ts-kit/pino 0.0.0-stage → 0.1.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/README.md CHANGED
@@ -1,3 +1,273 @@
1
- # Temporary Holding Version
1
+ # @ddd-ts-kit/pino
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The kernel `Logger` port on [pino](https://getpino.io): JSON lines on the standard output, the
4
+ correlation fields of the work in progress on every line, credentials redacted, a flush for the
5
+ shutdown. Nothing in `domain/` or `application/` imports this package, or logs anything: the
6
+ composition root binds the adapter, and infrastructure, presentation and the aspects write
7
+ through the port.
8
+
9
+ ```
10
+ npm i @ddd-ts-kit/pino pino
11
+ npm i -D pino-pretty # only for the pretty format
12
+ ```
13
+
14
+ Written against pino 10. `pino-pretty` 13 is an optional peer: it is loaded only when the
15
+ `pretty` format is asked for.
16
+
17
+ ## Composition root
18
+
19
+ ```ts
20
+ // platform/observability/create-logger.ts
21
+ import type { ExecutionScope, LogLevel } from '@ddd-ts-kit/kernel';
22
+ import { createPinoLogger, type PinoLogger } from '@ddd-ts-kit/pino';
23
+ import { traceLogFields } from '@ddd-ts-kit/tracing';
24
+
25
+ export interface LogSettings {
26
+ readonly level: LogLevel; // LOG_LEVEL
27
+ readonly format: 'json' | 'pretty'; // LOG_FORMAT
28
+ readonly service: string;
29
+ readonly environment: string;
30
+ readonly scrubMessages: boolean; // LOG_SCRUB_MESSAGES
31
+ }
32
+
33
+ export function createLogger(scope: ExecutionScope, settings: LogSettings): PinoLogger {
34
+ return createPinoLogger({ ...settings, fields: () => traceLogFields(scope) });
35
+ }
36
+ ```
37
+
38
+ ```ts
39
+ // main.ts
40
+ import { tracing } from '@/platform/tracing.js'; // first
41
+ import { AsyncLocalStorageExecutionScope } from '@ddd-ts-kit/kernel';
42
+ import { createApplication, kernelModule } from '@ddd-ts-kit/di';
43
+
44
+ const scope = new AsyncLocalStorageExecutionScope();
45
+ const logger = createLogger(scope, config.log);
46
+
47
+ const app = createApplication({
48
+ modules: [kernelModule({ executionScope: scope, logger }), ...contexts],
49
+ });
50
+
51
+ process.once('SIGTERM', () => void shutdown());
52
+
53
+ async function shutdown(): Promise<void> {
54
+ await app.stop(); // flushes the error reporter, then the logger, last
55
+ await tracing.shutdown();
56
+ }
57
+ ```
58
+
59
+ `init --logger pino` writes this `create-logger.ts` (it answers a `NoopLogger` when given no
60
+ settings, which is how the tools and the tests stay silent); `platform/lay-foundations.ts`
61
+ calls it once and `composeApplication` hands the logger to `kernelModule({ logger })`.
62
+
63
+ One line of the application, as it is written:
64
+
65
+ ```json
66
+ {"level":"info","time":"2026-03-01T10:00:00.000Z","service":"shop-api","environment":"production","correlationId":"9f2c","origin":"http","actorId":"user-1","tenantId":"acme","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7","context":"shipping","message":"order shipped"}
67
+ ```
68
+
69
+ **Correlation.** `fields` is read at each line that is written, through the pino `mixin`: no
70
+ call site passes an id. `traceLogFields(scope)` answers the trace and span ids inside a span,
71
+ and inside the execution scope the correlation id, the causation id, the origin, the actor and
72
+ the tenant. This package does not depend on the tracing package: any `() => LogFields` fits,
73
+ `() => logFieldsOf(scope.current())` included. A function that throws gives no field, never a
74
+ lost line. The fields of the line win over `fields`, which win over those of a child: pino
75
+ writes the bindings of a child first and what the mixin answers after them, so a key given
76
+ by both is written twice and a JSON parser reads the one of `fields`. `StdoutLogger` orders
77
+ them the same way; `@ddd-ts-kit/winston` does not (there a child wins over `fields`). Do not
78
+ bind in a child a key that `fields` answers.
79
+
80
+ **An instance of your own.** The project that already configures pino keeps doing so, and
81
+ takes the pieces it wants:
82
+
83
+ ```ts
84
+ import { CREDENTIAL_KEYS } from '@ddd-ts-kit/kernel';
85
+ import { pino } from 'pino';
86
+ import { PinoLogger, correlationMixin, credentialRedaction } from '@ddd-ts-kit/pino';
87
+
88
+ const instance = pino({
89
+ mixin: correlationMixin(() => traceLogFields(scope)),
90
+ redact: credentialRedaction([...CREDENTIAL_KEYS, 'iban']),
91
+ });
92
+
93
+ const logger = new PinoLogger(instance);
94
+ ```
95
+
96
+ `createPinoLogger` writes `level` by its name and the message under `message`, like the
97
+ `StdoutLogger` of the aspects package and like `@ddd-ts-kit/winston`: one dashboard reads the
98
+ three. An instance of your own keeps the keys you gave it (`msg` and a numeric level by default).
99
+
100
+ ## Development mode
101
+
102
+ ```ts
103
+ createPinoLogger({ level: 'debug', format: 'pretty', fields: () => traceLogFields(scope) });
104
+ ```
105
+
106
+ ```
107
+ [10:00:00.000] INFO: order shipped
108
+ service: "shop-api"
109
+ correlationId: "9f2c"
110
+ context: "shipping"
111
+ ```
112
+
113
+ The `pretty` format is the transport pino documents for `pino-pretty`: it runs in a worker
114
+ thread, so it takes a file descriptor or a path as `destination`, not a stream, and `flush()`
115
+ waits for the worker. For pretty lines on a stream of your own, build the instance on
116
+ `pino-pretty` used as a stream, `pino(options, pretty({ destination }))`, and wrap it in
117
+ `new PinoLogger(instance)`. Keep it out of production: choose the format from configuration
118
+ (`LOG_FORMAT=pretty` in `.env`, `json` everywhere else).
119
+
120
+ ## Privacy
121
+
122
+ Log lines are where personal data leaks: they are written everywhere, read by everyone and kept
123
+ for long. Three things are done in the adapter, so that no call site has to remember them. The
124
+ list of credential keys, the description of an error and the two markers (`CREDENTIAL_KEYS`,
125
+ `describeError`, `REDACTED`, `SCRUBBED_MESSAGE`) are those of the kernel, shared by every
126
+ logger of the port.
127
+
128
+ **Credentials are redacted** by pino's own `redact`, in the fields of a line, of a child and of
129
+ `fields` alike. The value of these keys is replaced by `[redacted]`, at the top of a line and
130
+ one level below (`headers.authorization`, `body.password`):
131
+
132
+ `password`, `authorization`, `cookie`, `set-cookie`, `token`, `secret`, `apiKey`, `api_key`,
133
+ `access_token`, `refresh_token`, `accessToken`, `refreshToken`, `client_secret`
134
+
135
+ `redact: ['iban', 'ssn']` adds to the list. Names are matched exactly, case included, and
136
+ nothing is looked for deeper than one level: log the part you mean, not a whole request.
137
+
138
+ **An error passed as a field** (`logger.error('payment failed', { error })`: the `LogValue` of
139
+ the port admits an `Error`) is written as `describeError` of the kernel describes it, the same
140
+ from every logger of the port: its class as `type`, its `code` when
141
+ it is a `DomainError`, its `message`, its own `stack`, then its `cause` the same way, up to
142
+ eight deep. Each error of a chain is written once: pino's standard serializer of the `err` key
143
+ would fold every cause into the message and the stack of the first, so the adapter turns it off
144
+ for the lines that go through the port. Errors are looked for among the fields of the line, not
145
+ inside nested objects.
146
+
147
+ **Messages of unexpected errors can be dropped.** The message of an error is the first place
148
+ where personal data shows up: a driver quotes the row it refused. The default keeps it, because
149
+ a log line that says `[message removed]` costs every investigation. With one option only the
150
+ messages the project wrote itself survive, those of its `DomainError`s; class, code, stack and
151
+ cause remain for the others, and the stack loses its first line, which repeats the message:
152
+
153
+ ```ts
154
+ createPinoLogger({ scrubMessages: true }); // or new PinoLogger(instance, { scrubMessages: true })
155
+ ```
156
+
157
+ This is the `scrubMessages` every logger of the port takes (`StdoutLogger`, pino, winston,
158
+ `InMemoryLogger`) and the one of `@ddd-ts-kit/sentry`, with the same rule, the same
159
+ `SCRUBBED_MESSAGE` and the same trade-off: turn it on when the logs leave your hands or when no
160
+ operator should read that data there. What the message of a log line itself says stays yours:
161
+ write `order shipped` and put the identifiers in fields.
162
+
163
+ The kit itself never hands an error to a logger: the `logged` aspect, `loggingMiddleware` and
164
+ the job scheduler write `errorType` and `errorCode` only (`identifyError` of the kernel), never
165
+ a message, whatever `scrubMessages` says, and the error goes to the `ErrorReporter`. The
166
+ description above is for the error your own code chooses to log:
167
+ `logger.error('payment failed', { error })`.
168
+
169
+ ## Levels
170
+
171
+ | Port | pino | |
172
+ |---|---|---|
173
+ | `debug` | `debug` (20) | |
174
+ | `info` | `info` (30) | the default threshold |
175
+ | `warn` | `warn` (40) | |
176
+ | `error` | `error` (50) | |
177
+
178
+ The port has no `trace` and no `fatal`: nothing written through it uses them. A line below the
179
+ threshold costs one comparison: its fields are not read, and `fields` is not called. The
180
+ threshold of an instance changed while running (`instance.level = 'debug'`) is followed by the
181
+ adapter and by its children. `isLevelEnabled(level)` answers that threshold: ask it before
182
+ building fields that cost.
183
+
184
+ `child(fields)` is a pino child: the fields are serialized once, when the child is created,
185
+ and cost nothing per line. A key bound twice (by a child and by its parent, by a child and by
186
+ `fields`, or by any of them and by the line) is written twice on the line, as pino does; a
187
+ JSON parser reads the last one, in this order: `service`, `environment` and `base`, the
188
+ children from the oldest to the closest, `fields`, the line. `level` and `time` are the
189
+ exception: a field of that name is dropped,
190
+ so that no field forges the header of a line.
191
+
192
+ ## Flush
193
+
194
+ `flush(): Promise<void>` resolves once what pino buffered was handed to its destination: the
195
+ worker of a transport, or the buffer of an asynchronous destination. It never rejects.
196
+ `app.stop()` calls it, last, after the modules stopped and the error reporter was flushed:
197
+ stopping logs too. Without the application of the di package, call it yourself at that place.
198
+
199
+ The port calls a flush once, at shutdown, and leaves what is logged afterwards unspecified.
200
+ Here the logger stays usable: a line logged after the flush is written like the others, and
201
+ with `asynchronous: true` it waits in the buffer for pino's exit hook.
202
+
203
+ ## Performance
204
+
205
+ By default every line is written to the standard output before the call returns. Nothing is
206
+ ever lost, and a slow reader of the standard output slows the application down.
207
+
208
+ `asynchronous: true` buffers 4 KiB and writes off the hot path (`pino.destination({ sync:
209
+ false })`), which is what makes pino fast under load. The price is what a dead process had not
210
+ written yet. `flush()` writes the buffer, and so does pino's own exit hook on `process.exit`
211
+ and on an uncaught exception. A signal that ends the process with no handler (`SIGKILL`, the
212
+ out-of-memory killer, a `SIGTERM` nobody listens to) loses up to 4 KiB of the most recent
213
+ lines, the ones that would have explained it; so does an exit in the first instants, before
214
+ the destination is open. Keep the default unless logging shows up in a profile.
215
+
216
+ A line costs one object copy of its fields (errors described, header keys dropped), then pino:
217
+ about 3 microseconds in all where `@ddd-ts-kit/winston` takes 7 (Node 24, a child, four
218
+ correlation fields, three fields, a sink that discards).
219
+ Redaction is compiled by pino: a lookup per credential key at the top of the line, and one
220
+ wildcard pass for the level below, whose censor looks at the name of each key. A wildcard path
221
+ per key would be the obvious way to write it and costs ten times more: measured on pino 10,
222
+ thirteen of them take a line from about one microsecond to about nine. Log calls never throw: fields that cannot be read or serialized
223
+ (a getter that throws) give the line without them, marked `logError: "unserializable fields"`.
224
+
225
+ ## Which one
226
+
227
+ Take `StdoutLogger` of the aspects package when JSON lines on the standard output are all you
228
+ need: no dependency, the same line shape. Take pino when logging volume matters, when the
229
+ framework already speaks pino (Fastify), or when you want its transports. Take
230
+ `@ddd-ts-kit/winston` when the team already runs winston transports and formats. The three
231
+ implement one port and are held by one contract suite: swapping is one line of the composition
232
+ root.
233
+
234
+ ## NestJS
235
+
236
+ Nest has its own `LoggerService`, used by the framework for its own messages and by
237
+ `new Logger(context)` in Nest classes. Application code of the kit never needs it: handlers and
238
+ adapters receive the kernel `Logger`. To send what Nest itself logs through the same instance,
239
+ hand it a bridge of a few lines; the kit ships none, since it would bind this package to Nest:
240
+
241
+ ```ts
242
+ const nest = logger.child({ context: 'nest' });
243
+ const bridge: LoggerService = {
244
+ log: (message: unknown) => nest.info(String(message)),
245
+ warn: (message: unknown) => nest.warn(String(message)),
246
+ error: (message: unknown) => nest.error(String(message)),
247
+ debug: (message: unknown) => nest.debug(String(message)),
248
+ };
249
+
250
+ const app = await NestFactory.create(AppModule, { logger: bridge });
251
+ ```
252
+
253
+ `nestjs-pino` is the alternative when Nest classes log a lot: give it the pino instance you
254
+ built, and wrap the same instance in `new PinoLogger(instance)` for the kit.
255
+
256
+ ## In a test
257
+
258
+ Nothing of this package: the test application binds `InMemoryLogger` of the kernel, and its
259
+ `entries` are data. To hold another adapter of the port to the same behaviour, run the contract:
260
+
261
+ ```ts
262
+ import { loggerContract } from '@ddd-ts-kit/testing/contracts';
263
+
264
+ loggerContract({ describe, it, expect, beforeEach }, {
265
+ name: 'PinoLogger',
266
+ createLogger: (setup) => { // { level, fields, scrubMessages }
267
+ const written: string[] = [];
268
+ const logger = createPinoLogger({ ...setup, destination: { write: (line) => written.push(line) } });
269
+
270
+ return { logger, lines: () => written.map((line) => lineOf(JSON.parse(line))) }; // { level, message, fields }
271
+ },
272
+ });
273
+ ```
@@ -0,0 +1,7 @@
1
+ import type { LogFields } from '@ddd-ts-kit/kernel';
2
+ /**
3
+ * A pino `mixin` reading the fields of the work in progress at each line that is written. A
4
+ * source that throws (no active span, no execution context) gives no field, never a lost line.
5
+ */
6
+ export declare function correlationMixin(fields: () => LogFields): () => LogFields;
7
+ //# sourceMappingURL=correlation-mixin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-mixin.d.ts","sourceRoot":"","sources":["../../src/correlation/correlation-mixin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,SAAS,GAAG,MAAM,SAAS,CASzE"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * A pino `mixin` reading the fields of the work in progress at each line that is written. A
3
+ * source that throws (no active span, no execution context) gives no field, never a lost line.
4
+ */
5
+ export function correlationMixin(fields) {
6
+ return () => {
7
+ try {
8
+ // A copy: pino merges the fields of the line into the object the mixin answers.
9
+ return { ...fields() };
10
+ }
11
+ catch {
12
+ return {};
13
+ }
14
+ };
15
+ }
16
+ //# sourceMappingURL=correlation-mixin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-mixin.js","sourceRoot":"","sources":["../../src/correlation/correlation-mixin.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,OAAO,GAAG,EAAE;QACV,IAAI,CAAC;YACH,gFAAgF;YAChF,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { type LogFields, type LogLevel } from '@ddd-ts-kit/kernel';
2
+ import { type DestinationStream } from 'pino';
3
+ import { PinoLogger, type PinoLoggerOptions } from './pino-logger.js';
4
+ export interface CreatePinoLoggerOptions extends PinoLoggerOptions {
5
+ /** Entries below it are not written. Default `info`. */
6
+ readonly level?: LogLevel;
7
+ /**
8
+ * `json`: one JSON object per line, what a container platform collects. `pretty`: lines for
9
+ * a human, through the `pino-pretty` transport, which must then be installed. Default `json`.
10
+ */
11
+ readonly format?: 'json' | 'pretty';
12
+ /** Written on every line as `service`. */
13
+ readonly service?: string;
14
+ /** Written on every line as `environment`. */
15
+ readonly environment?: string;
16
+ /** Added to every line next to `service` and `environment`: version, region. */
17
+ readonly base?: LogFields;
18
+ /**
19
+ * Read at each line that is written: correlation fields of the work in progress, such as
20
+ * `traceLogFields` of the tracing package or `logFieldsOf` of the current execution context.
21
+ */
22
+ readonly fields?: () => LogFields;
23
+ /** Field names hidden in addition to `CREDENTIAL_KEYS`, at the top of a line and one level below. */
24
+ readonly redact?: readonly string[];
25
+ /**
26
+ * Buffers the lines and writes them off the hot path. Default `false`: every line is
27
+ * written before the call returns. See "Performance" in the README for what a crash loses.
28
+ */
29
+ readonly asynchronous?: boolean;
30
+ /**
31
+ * A stream, a file descriptor or a path. Default: the standard output. The `pretty` format
32
+ * runs in a worker thread and takes a descriptor or a path only.
33
+ */
34
+ readonly destination?: DestinationStream | number | string;
35
+ }
36
+ /**
37
+ * A `PinoLogger` on a pino instance with the defaults of the kit: `time` in ISO 8601, `level`
38
+ * by its name, `message`, then the fields; credentials redacted; errors described once.
39
+ */
40
+ export declare function createPinoLogger(options?: CreatePinoLoggerOptions): PinoLogger;
41
+ //# sourceMappingURL=create-pino-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-pino-logger.d.ts","sourceRoot":"","sources":["../src/create-pino-logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAQ,KAAK,iBAAiB,EAAsB,MAAM,MAAM,CAAC;AAExE,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGtE,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACpC,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,SAAS,CAAC;IAClC,qGAAqG;IACrG,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;CAC5D;AAKD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,UAAU,CAOlF"}
@@ -0,0 +1,58 @@
1
+ import { CREDENTIAL_KEYS } from '@ddd-ts-kit/kernel';
2
+ import { pino } from 'pino';
3
+ import { correlationMixin } from './correlation/correlation-mixin.js';
4
+ import { PinoLogger } from './pino-logger.js';
5
+ import { credentialRedaction } from './redaction/credential-redaction.js';
6
+ const STANDARD_OUTPUT = 1;
7
+ const BUFFERED_BYTES = 4096;
8
+ /**
9
+ * A `PinoLogger` on a pino instance with the defaults of the kit: `time` in ISO 8601, `level`
10
+ * by its name, `message`, then the fields; credentials redacted; errors described once.
11
+ */
12
+ export function createPinoLogger(options = {}) {
13
+ const instance = pino(pinoOptions(options), options.format === 'pretty' ? prettyTransport(options) : destinationOf(options));
14
+ return new PinoLogger(instance, options.scrubMessages === undefined ? {} : { scrubMessages: options.scrubMessages });
15
+ }
16
+ function pinoOptions(options) {
17
+ return {
18
+ level: options.level ?? 'info',
19
+ messageKey: 'message',
20
+ timestamp: pino.stdTimeFunctions.isoTime,
21
+ base: baseFields(options),
22
+ formatters: { level: (label) => ({ level: label }) },
23
+ redact: credentialRedaction([...CREDENTIAL_KEYS, ...(options.redact ?? [])]),
24
+ ...(options.fields === undefined ? {} : { mixin: correlationMixin(options.fields) }),
25
+ };
26
+ }
27
+ function baseFields(options) {
28
+ return {
29
+ ...(options.service === undefined ? {} : { service: options.service }),
30
+ ...(options.environment === undefined ? {} : { environment: options.environment }),
31
+ ...options.base,
32
+ };
33
+ }
34
+ function prettyTransport(options) {
35
+ if (typeof options.destination === 'object') {
36
+ throw new TypeError('The pretty format writes to a file descriptor or a path: pino-pretty runs in a worker thread');
37
+ }
38
+ return pino.transport({
39
+ target: 'pino-pretty',
40
+ options: {
41
+ destination: options.destination ?? STANDARD_OUTPUT,
42
+ messageKey: 'message',
43
+ translateTime: 'SYS:HH:MM:ss.l',
44
+ sync: options.asynchronous !== true,
45
+ },
46
+ });
47
+ }
48
+ function destinationOf(options) {
49
+ if (typeof options.destination === 'object') {
50
+ return options.destination;
51
+ }
52
+ return pino.destination({
53
+ dest: options.destination ?? STANDARD_OUTPUT,
54
+ sync: options.asynchronous !== true,
55
+ ...(options.asynchronous === true ? { minLength: BUFFERED_BYTES } : {}),
56
+ });
57
+ }
58
+ //# sourceMappingURL=create-pino-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-pino-logger.js","sourceRoot":"","sources":["../src/create-pino-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type DescribeErrorOptions, type LogFields, type LogValue } from '@ddd-ts-kit/kernel';
2
+ /**
3
+ * The fields as pino receives them: errors described, and no key that would forge the header.
4
+ * pino writes `level` and `time` before the fields: a field of that name would be a second key
5
+ * of the line, and the last one is read.
6
+ */
7
+ export declare function lineFields(fields: LogFields, options: DescribeErrorOptions): Record<string, LogValue>;
8
+ //# sourceMappingURL=line-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-fields.d.ts","sourceRoot":"","sources":["../../src/fields/line-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnH;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAIrG"}
@@ -0,0 +1,11 @@
1
+ import { describeErrorFields } from '@ddd-ts-kit/kernel';
2
+ /**
3
+ * The fields as pino receives them: errors described, and no key that would forge the header.
4
+ * pino writes `level` and `time` before the fields: a field of that name would be a second key
5
+ * of the line, and the last one is read.
6
+ */
7
+ export function lineFields(fields, options) {
8
+ const { level: _level, time: _time, ...line } = describeErrorFields(fields, options);
9
+ return line;
10
+ }
11
+ //# sourceMappingURL=line-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-fields.js","sourceRoot":"","sources":["../../src/fields/line-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAA4D,MAAM,oBAAoB,CAAC;AAEnH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAiB,EAAE,OAA6B;IACzE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { correlationMixin } from './correlation/correlation-mixin.js';
2
+ export { createPinoLogger, type CreatePinoLoggerOptions } from './create-pino-logger.js';
3
+ export { PinoLogger, type PinoLoggerOptions } from './pino-logger.js';
4
+ export { credentialRedaction, type CredentialRedaction } from './redaction/credential-redaction.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,qCAAqC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { correlationMixin } from './correlation/correlation-mixin.js';
2
+ export { createPinoLogger } from './create-pino-logger.js';
3
+ export { PinoLogger } from './pino-logger.js';
4
+ export { credentialRedaction } from './redaction/credential-redaction.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAgC,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,UAAU,EAA0B,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAA4B,MAAM,qCAAqC,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type LogFields, type LogLevel, type Logger } from '@ddd-ts-kit/kernel';
2
+ import type { Logger as Pino } from 'pino';
3
+ export interface PinoLoggerOptions {
4
+ /**
5
+ * Writes `SCRUBBED_MESSAGE` for the message of every logged error that is not a
6
+ * `DomainError`. Default `false`: see "Privacy" in the README for the trade-off.
7
+ */
8
+ readonly scrubMessages?: boolean;
9
+ }
10
+ /**
11
+ * The `Logger` port on a pino instance: the levels of the port are those of pino, a child is
12
+ * a pino child, and what the instance was configured with (mixin, redaction, destination)
13
+ * applies to every line. `createPinoLogger` builds one with the defaults of the kit; build it
14
+ * yourself around an instance you configured.
15
+ */
16
+ export declare class PinoLogger implements Logger {
17
+ private readonly options;
18
+ private readonly pino;
19
+ constructor(pino: Pino, options?: PinoLoggerOptions);
20
+ debug(message: string, fields?: LogFields): void;
21
+ info(message: string, fields?: LogFields): void;
22
+ warn(message: string, fields?: LogFields): void;
23
+ error(message: string, fields?: LogFields): void;
24
+ child(fields: LogFields): PinoLogger;
25
+ /** The threshold of the instance, followed when it changes while running. */
26
+ isLevelEnabled(level: LogLevel): boolean;
27
+ /**
28
+ * Resolves once what pino buffered was handed to its destination. Never rejects, and the
29
+ * logger stays usable: an entry logged afterwards is written like the others.
30
+ */
31
+ flush(): Promise<void>;
32
+ private nativeChild;
33
+ private write;
34
+ private writeWithoutFields;
35
+ }
36
+ //# sourceMappingURL=pino-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pino-logger.d.ts","sourceRoot":"","sources":["../src/pino-logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAG3C,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC;AAKD;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,MAAM;IAKrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAE5B,YACE,IAAI,EAAE,IAAI,EACO,OAAO,GAAE,iBAAsB,EAGjD;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAE/C;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAE9C;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAE9C;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAE/C;IAED,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,CAMnC;IAED,6EAA6E;IAC7E,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAEvC;IAED;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAUrB;IAED,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,KAAK;IAYb,OAAO,CAAC,kBAAkB;CAO3B"}
@@ -0,0 +1,91 @@
1
+ import { UNWRITABLE_FIELDS } from '@ddd-ts-kit/kernel';
2
+ import { lineFields } from './fields/line-fields.js';
3
+ /** Children of an instance the adapter already prepared: they are adopted as they are. */
4
+ const adopted = new WeakSet();
5
+ /**
6
+ * The `Logger` port on a pino instance: the levels of the port are those of pino, a child is
7
+ * a pino child, and what the instance was configured with (mixin, redaction, destination)
8
+ * applies to every line. `createPinoLogger` builds one with the defaults of the kit; build it
9
+ * yourself around an instance you configured.
10
+ */
11
+ export class PinoLogger {
12
+ options;
13
+ pino;
14
+ constructor(pino, options = {}) {
15
+ this.options = options;
16
+ this.pino = adopted.has(pino) ? pino : describingErrorsItself(pino);
17
+ }
18
+ debug(message, fields) {
19
+ this.write('debug', message, fields);
20
+ }
21
+ info(message, fields) {
22
+ this.write('info', message, fields);
23
+ }
24
+ warn(message, fields) {
25
+ this.write('warn', message, fields);
26
+ }
27
+ error(message, fields) {
28
+ this.write('error', message, fields);
29
+ }
30
+ child(fields) {
31
+ const child = this.nativeChild(fields);
32
+ adopted.add(child);
33
+ return new PinoLogger(child, this.options);
34
+ }
35
+ /** The threshold of the instance, followed when it changes while running. */
36
+ isLevelEnabled(level) {
37
+ return this.pino.isLevelEnabled(level);
38
+ }
39
+ /**
40
+ * Resolves once what pino buffered was handed to its destination. Never rejects, and the
41
+ * logger stays usable: an entry logged afterwards is written like the others.
42
+ */
43
+ flush() {
44
+ return new Promise((resolve) => {
45
+ try {
46
+ this.pino.flush(() => {
47
+ resolve();
48
+ });
49
+ }
50
+ catch {
51
+ resolve();
52
+ }
53
+ });
54
+ }
55
+ nativeChild(fields) {
56
+ try {
57
+ return this.pino.child(lineFields(fields, this.options));
58
+ }
59
+ catch {
60
+ return this.pino.child(UNWRITABLE_FIELDS);
61
+ }
62
+ }
63
+ write(level, message, fields = {}) {
64
+ if (!this.isLevelEnabled(level)) {
65
+ return;
66
+ }
67
+ try {
68
+ this.pino[level](lineFields(fields, this.options), message);
69
+ }
70
+ catch {
71
+ this.writeWithoutFields(level, message);
72
+ }
73
+ }
74
+ writeWithoutFields(level, message) {
75
+ try {
76
+ this.pino[level](UNWRITABLE_FIELDS, message);
77
+ }
78
+ catch {
79
+ return;
80
+ }
81
+ }
82
+ }
83
+ /**
84
+ * The adapter describes errors before pino sees them. Left in place, the standard serializer
85
+ * of the `err` key would take that description for an error and describe it a second time,
86
+ * folding the causes into one message and one stack.
87
+ */
88
+ function describingErrorsItself(pino) {
89
+ return pino.child({}, { serializers: { err: (description) => description } });
90
+ }
91
+ //# sourceMappingURL=pino-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pino-logger.js","sourceRoot":"","sources":["../src/pino-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /** A value for the `redact` option of pino. */
2
+ export interface CredentialRedaction {
3
+ readonly paths: string[];
4
+ censor(value: unknown, path: readonly string[]): unknown;
5
+ }
6
+ /**
7
+ * The pino `redact` option hiding the given keys at the top of a line and one level below, in
8
+ * the fields of an entry, of a child and of the mixin alike. Names are matched exactly, case
9
+ * included. The level below is one wildcard path whose censor looks at the name of the key:
10
+ * a wildcard path per key would cost pino as many passes over each line.
11
+ */
12
+ export declare function credentialRedaction(keys?: readonly string[]): CredentialRedaction;
13
+ //# sourceMappingURL=credential-redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-redaction.d.ts","sourceRoot":"","sources":["../../src/redaction/credential-redaction.ts"],"names":[],"mappings":"AAEA,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;CAC1D;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,SAAS,MAAM,EAAoB,GAAG,mBAAmB,CAOlG"}
@@ -0,0 +1,16 @@
1
+ import { CREDENTIAL_KEYS, REDACTED } from '@ddd-ts-kit/kernel';
2
+ const ONE_LEVEL_BELOW = '*.*';
3
+ /**
4
+ * The pino `redact` option hiding the given keys at the top of a line and one level below, in
5
+ * the fields of an entry, of a child and of the mixin alike. Names are matched exactly, case
6
+ * included. The level below is one wildcard path whose censor looks at the name of the key:
7
+ * a wildcard path per key would cost pino as many passes over each line.
8
+ */
9
+ export function credentialRedaction(keys = CREDENTIAL_KEYS) {
10
+ const hidden = new Set(keys);
11
+ return {
12
+ paths: [...[...hidden].map((key) => `["${key}"]`), ONE_LEVEL_BELOW],
13
+ censor: (value, path) => (hidden.has(path.at(-1) ?? '') ? REDACTED : value),
14
+ };
15
+ }
16
+ //# sourceMappingURL=credential-redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-redaction.js","sourceRoot":"","sources":["../../src/redaction/credential-redaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAQ/D,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAI,GAAsB,eAAe;IAC3E,MAAM,MAAM,GAAwB,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAElD,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,eAAe,CAAC;QACnE,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;KAC5E,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "@ddd-ts-kit/pino",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Adapter of the kernel Logger port on pino, with trace and execution correlation on every line.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/gbourgeat/ddd-ts-kit.git",
9
+ "directory": "packages/pino"
10
+ },
11
+ "homepage": "https://github.com/gbourgeat/ddd-ts-kit/tree/main/packages/pino#readme",
12
+ "bugs": "https://github.com/gbourgeat/ddd-ts-kit/issues",
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "provenance": true
16
+ },
17
+ "type": "module",
18
+ "sideEffects": false,
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "dependencies": {
29
+ "@ddd-ts-kit/kernel": "0.1.1"
30
+ },
31
+ "devDependencies": {
32
+ "@ddd-ts-kit/testing": "0.1.1",
33
+ "pino": "^10.4.0",
34
+ "pino-pretty": "^13.2.0"
35
+ },
36
+ "peerDependencies": {
37
+ "pino": "^10.4.0",
38
+ "pino-pretty": "^13.2.0"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "pino-pretty": {
42
+ "optional": true
43
+ }
44
+ }
45
+ }