@bymax-one/nest-logger 1.2.6 → 1.2.9
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/CHANGELOG.md +616 -2
- package/README.md +71 -5
- package/dist/server/index.cjs +366 -55
- package/dist/server/index.d.cts +149 -12
- package/dist/server/index.d.ts +149 -12
- package/dist/server/index.mjs +366 -55
- package/package.json +3 -2
package/dist/server/index.d.cts
CHANGED
|
@@ -69,12 +69,55 @@ interface ILogDestination {
|
|
|
69
69
|
*
|
|
70
70
|
* @param payload — Newline-terminated JSON entry, UTF-8 encoded.
|
|
71
71
|
*/
|
|
72
|
-
write(payload: string): void |
|
|
72
|
+
write(payload: string): void | PromiseLike<void>;
|
|
73
73
|
/**
|
|
74
74
|
* Optional lifecycle hook — called once during NestJS module init.
|
|
75
75
|
* Use for opening connections, allocating buffers, scheduling flushers.
|
|
76
76
|
*/
|
|
77
|
-
onInit?(): void |
|
|
77
|
+
onInit?(): void | PromiseLike<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Optional lifecycle hook — called once after EVERY destination's `onInit`
|
|
80
|
+
* has settled, successfully or not, and before the bootstrap entry is emitted.
|
|
81
|
+
*
|
|
82
|
+
* Only useful to a destination that holds entries written before its own
|
|
83
|
+
* `onInit` ran: until this point it cannot know what became of them. The
|
|
84
|
+
* fan-out hands each entry to every registered destination whose level accepts
|
|
85
|
+
* it, so a held copy may be a SECOND copy.
|
|
86
|
+
*
|
|
87
|
+
* **This is a deduplication signal, not a proof — and the difference is the
|
|
88
|
+
* whole contract.** A held copy may be a second copy, so emitting it duplicates
|
|
89
|
+
* a line and dropping it may lose one. The flag says which risk is smaller, as
|
|
90
|
+
* far as this library can see; it does not say the entry is safe.
|
|
91
|
+
*
|
|
92
|
+
* The library's own destinations act on it by discarding when it is `true` and
|
|
93
|
+
* emitting otherwise, because a duplicated boot line is a smaller harm than a
|
|
94
|
+
* lost one. **A destination that cannot tolerate ANY loss should emit
|
|
95
|
+
* regardless** — see the accounting limits on the flag below.
|
|
96
|
+
*
|
|
97
|
+
* Called on failed destinations too, which is the point: the one that could not
|
|
98
|
+
* initialize is exactly the one still holding entries.
|
|
99
|
+
*
|
|
100
|
+
* @param status.heldEntriesDeliveredElsewhere - Whether another live sink
|
|
101
|
+
* accepted everything this destination accepted, as far as this library can
|
|
102
|
+
* see. `true` requires that sink to be not this one, initialized, at or below
|
|
103
|
+
* this level, with no write failure and no write still in flight; anything
|
|
104
|
+
* less certain is `false`.
|
|
105
|
+
*
|
|
106
|
+
* **What it cannot see:** a write still QUEUED inside the `Writable` adapter,
|
|
107
|
+
* behind a slow async sink that has not been called yet. So `true` can precede
|
|
108
|
+
* a queued write that later fails, and there is no flag that distinguishes
|
|
109
|
+
* that case — which is exactly why this is a tradeoff rather than a
|
|
110
|
+
* guarantee. It normally arrives, being queued rather than lost.
|
|
111
|
+
*
|
|
112
|
+
* @returns Nothing, or a promise the library AWAITS. Returning one is
|
|
113
|
+
* supported deliberately: TypeScript accepts an `async` implementation where
|
|
114
|
+
* a void-returning member is declared, so a hook that was not awaited would
|
|
115
|
+
* reject into nothing and let the bootstrap entry be emitted before the
|
|
116
|
+
* buffer had been resolved.
|
|
117
|
+
*/
|
|
118
|
+
onRegistryReady?(status: {
|
|
119
|
+
readonly heldEntriesDeliveredElsewhere: boolean;
|
|
120
|
+
}): void | PromiseLike<void>;
|
|
78
121
|
/**
|
|
79
122
|
* Optional lifecycle hook — called during NestJS `onApplicationShutdown`.
|
|
80
123
|
* MUST flush any pending writes and close resources.
|
|
@@ -82,7 +125,7 @@ interface ILogDestination {
|
|
|
82
125
|
* The library awaits this — graceful shutdown blocks until all destinations
|
|
83
126
|
* return.
|
|
84
127
|
*/
|
|
85
|
-
onShutdown?(): void |
|
|
128
|
+
onShutdown?(): void | PromiseLike<void>;
|
|
86
129
|
}
|
|
87
130
|
|
|
88
131
|
/**
|
|
@@ -636,10 +679,30 @@ declare class PinoLoggerService implements LoggerService, OnApplicationShutdown
|
|
|
636
679
|
private readonly redact;
|
|
637
680
|
private context?;
|
|
638
681
|
/**
|
|
682
|
+
* **A hand-built instance is NOT this library's behaviour.** Constructing
|
|
683
|
+
* `new PinoLoggerService(pino({...}, sink))` directly works in the sense of not
|
|
684
|
+
* throwing, and the parameter default below exists for exactly that — but the
|
|
685
|
+
* Pino instance you built has none of the wiring `buildPinoInstance` installs,
|
|
686
|
+
* and the omissions are silent:
|
|
687
|
+
*
|
|
688
|
+
* - **no `err` serializer**, so an `Error` is serialized by Pino's default.
|
|
689
|
+
* The `cause` chain disappears ENTIRELY — no marker, no warning, and a
|
|
690
|
+
* `cause` that reads as "the field was never set";
|
|
691
|
+
* - **no name-based redaction** of serializer output or child bindings;
|
|
692
|
+
* - **no trace-context mixin**, so `requestId` / `tenantId` / OTel ids are
|
|
693
|
+
* absent;
|
|
694
|
+
* - **no size bound**, so nothing is truncated.
|
|
695
|
+
*
|
|
696
|
+
* That matters most for tests, which is the use this doc used to invite without
|
|
697
|
+
* qualification: a consumer wrote one to check whether a `cause` carried its
|
|
698
|
+
* `code`, measured absence, and nearly filed it against this library. The
|
|
699
|
+
* absence was their harness. For a faithful harness, boot the module (or use
|
|
700
|
+
* `BymaxLoggerModule.forRoot` in a testing module) rather than hand-building.
|
|
701
|
+
*
|
|
639
702
|
* @param pino - The wrapped Pino instance.
|
|
640
703
|
* @param redact - The DEFAULT-coverage redactor, applied to `child()` bindings.
|
|
641
|
-
* Defaults to the identity so a hand-built instance
|
|
642
|
-
*
|
|
704
|
+
* Defaults to the identity so a hand-built instance still works; the module
|
|
705
|
+
* always injects the configured one.
|
|
643
706
|
*/
|
|
644
707
|
constructor(pino: Logger, redact?: Redactor);
|
|
645
708
|
/**
|
|
@@ -899,7 +962,7 @@ declare class DefaultStdoutDestination implements ILogDestination {
|
|
|
899
962
|
* // One line per entry, with the fields a project repeats on every line hidden.
|
|
900
963
|
* const view: PrettyViewOptions = {
|
|
901
964
|
* singleLine: true,
|
|
902
|
-
* ignore: 'pid,hostname,service,deployment,event
|
|
965
|
+
* ignore: 'pid,hostname,service,deployment,event\\.name'
|
|
903
966
|
* }
|
|
904
967
|
*/
|
|
905
968
|
interface PrettyViewOptions {
|
|
@@ -914,19 +977,60 @@ interface PrettyViewOptions {
|
|
|
914
977
|
* what a real sink receives is untouched. Extend rather than replace when the
|
|
915
978
|
* goal is quieter output — the default already hides the noisiest fields.
|
|
916
979
|
* Default: `'pid,hostname,service'`.
|
|
980
|
+
*
|
|
981
|
+
* **A dot means "nested path", so a field name CONTAINING a dot has to escape
|
|
982
|
+
* it.** This library emits `event.name` as a literal top-level key, so the
|
|
983
|
+
* obvious spelling silently hides nothing — `pino-pretty` looks for an `event`
|
|
984
|
+
* object with a `name` inside and finds neither. Measured on one entry, only
|
|
985
|
+
* the option changing:
|
|
986
|
+
*
|
|
987
|
+
* ```
|
|
988
|
+
* ignore: '…,event.name' → INFO: msg {"logKey":"X","event.name":"x"} ← still there
|
|
989
|
+
* ignore: '…,event\\.name' → INFO: msg {"logKey":"X"} ← hidden
|
|
990
|
+
* ```
|
|
991
|
+
*
|
|
992
|
+
* In a TypeScript string literal that is `'event\\.name'` — one real backslash
|
|
993
|
+
* reaching `pino-pretty`. Nested objects (`service`, `deployment`) need no
|
|
994
|
+
* escape; they really are paths.
|
|
917
995
|
*/
|
|
918
996
|
ignore?: string;
|
|
919
997
|
/**
|
|
920
|
-
* Render only the message line, hiding the record entirely.
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
*
|
|
998
|
+
* Render only the message line, hiding the record entirely. Display-only, and
|
|
999
|
+
* scoped to THIS destination: a field hidden here is still delivered in full to
|
|
1000
|
+
* every other destination registered alongside it.
|
|
1001
|
+
*
|
|
1002
|
+
* When pretty is the ONLY destination, that scope makes it total — `destinations`
|
|
1003
|
+
* replaces the default stdout sink, so there is no JSON copy behind the
|
|
1004
|
+
* rendering and a hidden field, `logKey` included, is not visible anywhere. That
|
|
1005
|
+
* is the point of the option rather than a caveat; use `messageFormat` to pull a
|
|
1006
|
+
* specific field back into the line. Default: `false`.
|
|
925
1007
|
*/
|
|
926
1008
|
hideObject?: boolean;
|
|
927
1009
|
/**
|
|
928
1010
|
* Template for the message line, e.g. `'[{context}] {msg}'`. The way to keep a
|
|
929
1011
|
* chosen field visible when `hideObject` is on.
|
|
1012
|
+
*
|
|
1013
|
+
* **Every placeholder EXCEPT `{msg}` is interpolated raw, and that reopens
|
|
1014
|
+
* terminal log forging.** This library normalizes line separators and control
|
|
1015
|
+
* characters in `msg` and in the stack — not in metadata, because escaping data
|
|
1016
|
+
* would mean rewriting what you asked to be logged. `pino-pretty` substitutes
|
|
1017
|
+
* whatever the field holds, so a newline in an interpolated field splits one
|
|
1018
|
+
* entry into two, and the second reads like a genuine record. Measured, with a
|
|
1019
|
+
* newline in `context`:
|
|
1020
|
+
*
|
|
1021
|
+
* ```
|
|
1022
|
+
* lines produced by ONE entry: 2
|
|
1023
|
+
* 1: "[10:35:14.484] INFO: [Auth"
|
|
1024
|
+
* 2: "[10:00:00.000] INFO: FORGED admin promoted] real entry …"
|
|
1025
|
+
* ```
|
|
1026
|
+
*
|
|
1027
|
+
* So: interpolate only fields whose values your own code sets. Never a field
|
|
1028
|
+
* carrying user input — `{tenantId}`, `{userId}`, a header, a query value. If
|
|
1029
|
+
* you need one of those visible, leave it in the record instead of the format
|
|
1030
|
+
* string. That closes THIS path — the raw placeholder — and no more: a metadata
|
|
1031
|
+
* value is not safe terminal text either, because `JSON.stringify` escapes only
|
|
1032
|
+
* C0 and emits DEL, the C1 range (U+0085 NEL included), U+2028 and U+2029
|
|
1033
|
+
* verbatim. Only `msg` and the stack carry the one-entry-one-line guarantee.
|
|
930
1034
|
*/
|
|
931
1035
|
messageFormat?: string;
|
|
932
1036
|
/** Timestamp format, or `false` to leave it raw. Default: `'SYS:HH:MM:ss.l'`. */
|
|
@@ -949,7 +1053,7 @@ interface PrettyViewOptions {
|
|
|
949
1053
|
*
|
|
950
1054
|
* // One line per entry, with this project's repeated fields hidden.
|
|
951
1055
|
* new PrettyDevDestination({
|
|
952
|
-
* view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event
|
|
1056
|
+
* view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event\\.name' }
|
|
953
1057
|
* })
|
|
954
1058
|
*
|
|
955
1059
|
* // Message-only, with the context pulled back into the line.
|
|
@@ -1031,6 +1135,39 @@ declare class PrettyDevDestination implements ILogDestination {
|
|
|
1031
1135
|
* @param payload — Newline-terminated JSON entry, UTF-8 encoded.
|
|
1032
1136
|
*/
|
|
1033
1137
|
write(payload: string): void;
|
|
1138
|
+
/**
|
|
1139
|
+
* Resolve anything still held, now that the registry knows what became of it.
|
|
1140
|
+
*
|
|
1141
|
+
* **Discard only where another sink is believed to have taken the same entries;
|
|
1142
|
+
* emit everything else.** Losing a boot entry is not an acceptable outcome, and
|
|
1143
|
+
* every richer policy tried here had a losing branch: trusting "a sink survived"
|
|
1144
|
+
* lost entries to a sink at a higher level, trusting a level lost them to a sink
|
|
1145
|
+
* that was itself the asker, then to one whose writes were throwing, then to one
|
|
1146
|
+
* whose write had not settled yet. Each of those is now folded into the single
|
|
1147
|
+
* signal handed in — and where it is uncertain, it says `false` and this drains.
|
|
1148
|
+
*
|
|
1149
|
+
* That signal is not a proof, and this hook does not treat it as one. It cannot
|
|
1150
|
+
* see an entry still queued inside the `Writable` adapter, because the adapter
|
|
1151
|
+
* has not called `destination.write()` for it yet. Discarding on it is a bet
|
|
1152
|
+
* that a duplicated boot line costs less than a lost one — which is the trade
|
|
1153
|
+
* this destination accepts, and which a destination that cannot lose anything
|
|
1154
|
+
* should decline by ignoring the flag and always emitting.
|
|
1155
|
+
*
|
|
1156
|
+
* The cost is stated rather than hidden: when nothing survived, every holding
|
|
1157
|
+
* destination drains, so N of them produce N copies of the boot entries. A
|
|
1158
|
+
* duplicated line in an already-degraded boot is a smaller harm than a lost one,
|
|
1159
|
+
* and it is loud rather than silent.
|
|
1160
|
+
*
|
|
1161
|
+
* A no-op once {@link onInit} succeeded — the buffer was flushed through the
|
|
1162
|
+
* transform there and is already empty.
|
|
1163
|
+
*
|
|
1164
|
+
* @param status.heldEntriesDeliveredElsewhere - Another live sink appears to
|
|
1165
|
+
* have taken everything this one took. A deduplication signal, not a proof —
|
|
1166
|
+
* see `ILogDestination.onRegistryReady` for what it cannot see.
|
|
1167
|
+
*/
|
|
1168
|
+
onRegistryReady(status: {
|
|
1169
|
+
readonly heldEntriesDeliveredElsewhere: boolean;
|
|
1170
|
+
}): void;
|
|
1034
1171
|
/**
|
|
1035
1172
|
* Hand every buffered entry to `emit`, in arrival order, and empty the buffer.
|
|
1036
1173
|
*
|
package/dist/server/index.d.ts
CHANGED
|
@@ -69,12 +69,55 @@ interface ILogDestination {
|
|
|
69
69
|
*
|
|
70
70
|
* @param payload — Newline-terminated JSON entry, UTF-8 encoded.
|
|
71
71
|
*/
|
|
72
|
-
write(payload: string): void |
|
|
72
|
+
write(payload: string): void | PromiseLike<void>;
|
|
73
73
|
/**
|
|
74
74
|
* Optional lifecycle hook — called once during NestJS module init.
|
|
75
75
|
* Use for opening connections, allocating buffers, scheduling flushers.
|
|
76
76
|
*/
|
|
77
|
-
onInit?(): void |
|
|
77
|
+
onInit?(): void | PromiseLike<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Optional lifecycle hook — called once after EVERY destination's `onInit`
|
|
80
|
+
* has settled, successfully or not, and before the bootstrap entry is emitted.
|
|
81
|
+
*
|
|
82
|
+
* Only useful to a destination that holds entries written before its own
|
|
83
|
+
* `onInit` ran: until this point it cannot know what became of them. The
|
|
84
|
+
* fan-out hands each entry to every registered destination whose level accepts
|
|
85
|
+
* it, so a held copy may be a SECOND copy.
|
|
86
|
+
*
|
|
87
|
+
* **This is a deduplication signal, not a proof — and the difference is the
|
|
88
|
+
* whole contract.** A held copy may be a second copy, so emitting it duplicates
|
|
89
|
+
* a line and dropping it may lose one. The flag says which risk is smaller, as
|
|
90
|
+
* far as this library can see; it does not say the entry is safe.
|
|
91
|
+
*
|
|
92
|
+
* The library's own destinations act on it by discarding when it is `true` and
|
|
93
|
+
* emitting otherwise, because a duplicated boot line is a smaller harm than a
|
|
94
|
+
* lost one. **A destination that cannot tolerate ANY loss should emit
|
|
95
|
+
* regardless** — see the accounting limits on the flag below.
|
|
96
|
+
*
|
|
97
|
+
* Called on failed destinations too, which is the point: the one that could not
|
|
98
|
+
* initialize is exactly the one still holding entries.
|
|
99
|
+
*
|
|
100
|
+
* @param status.heldEntriesDeliveredElsewhere - Whether another live sink
|
|
101
|
+
* accepted everything this destination accepted, as far as this library can
|
|
102
|
+
* see. `true` requires that sink to be not this one, initialized, at or below
|
|
103
|
+
* this level, with no write failure and no write still in flight; anything
|
|
104
|
+
* less certain is `false`.
|
|
105
|
+
*
|
|
106
|
+
* **What it cannot see:** a write still QUEUED inside the `Writable` adapter,
|
|
107
|
+
* behind a slow async sink that has not been called yet. So `true` can precede
|
|
108
|
+
* a queued write that later fails, and there is no flag that distinguishes
|
|
109
|
+
* that case — which is exactly why this is a tradeoff rather than a
|
|
110
|
+
* guarantee. It normally arrives, being queued rather than lost.
|
|
111
|
+
*
|
|
112
|
+
* @returns Nothing, or a promise the library AWAITS. Returning one is
|
|
113
|
+
* supported deliberately: TypeScript accepts an `async` implementation where
|
|
114
|
+
* a void-returning member is declared, so a hook that was not awaited would
|
|
115
|
+
* reject into nothing and let the bootstrap entry be emitted before the
|
|
116
|
+
* buffer had been resolved.
|
|
117
|
+
*/
|
|
118
|
+
onRegistryReady?(status: {
|
|
119
|
+
readonly heldEntriesDeliveredElsewhere: boolean;
|
|
120
|
+
}): void | PromiseLike<void>;
|
|
78
121
|
/**
|
|
79
122
|
* Optional lifecycle hook — called during NestJS `onApplicationShutdown`.
|
|
80
123
|
* MUST flush any pending writes and close resources.
|
|
@@ -82,7 +125,7 @@ interface ILogDestination {
|
|
|
82
125
|
* The library awaits this — graceful shutdown blocks until all destinations
|
|
83
126
|
* return.
|
|
84
127
|
*/
|
|
85
|
-
onShutdown?(): void |
|
|
128
|
+
onShutdown?(): void | PromiseLike<void>;
|
|
86
129
|
}
|
|
87
130
|
|
|
88
131
|
/**
|
|
@@ -636,10 +679,30 @@ declare class PinoLoggerService implements LoggerService, OnApplicationShutdown
|
|
|
636
679
|
private readonly redact;
|
|
637
680
|
private context?;
|
|
638
681
|
/**
|
|
682
|
+
* **A hand-built instance is NOT this library's behaviour.** Constructing
|
|
683
|
+
* `new PinoLoggerService(pino({...}, sink))` directly works in the sense of not
|
|
684
|
+
* throwing, and the parameter default below exists for exactly that — but the
|
|
685
|
+
* Pino instance you built has none of the wiring `buildPinoInstance` installs,
|
|
686
|
+
* and the omissions are silent:
|
|
687
|
+
*
|
|
688
|
+
* - **no `err` serializer**, so an `Error` is serialized by Pino's default.
|
|
689
|
+
* The `cause` chain disappears ENTIRELY — no marker, no warning, and a
|
|
690
|
+
* `cause` that reads as "the field was never set";
|
|
691
|
+
* - **no name-based redaction** of serializer output or child bindings;
|
|
692
|
+
* - **no trace-context mixin**, so `requestId` / `tenantId` / OTel ids are
|
|
693
|
+
* absent;
|
|
694
|
+
* - **no size bound**, so nothing is truncated.
|
|
695
|
+
*
|
|
696
|
+
* That matters most for tests, which is the use this doc used to invite without
|
|
697
|
+
* qualification: a consumer wrote one to check whether a `cause` carried its
|
|
698
|
+
* `code`, measured absence, and nearly filed it against this library. The
|
|
699
|
+
* absence was their harness. For a faithful harness, boot the module (or use
|
|
700
|
+
* `BymaxLoggerModule.forRoot` in a testing module) rather than hand-building.
|
|
701
|
+
*
|
|
639
702
|
* @param pino - The wrapped Pino instance.
|
|
640
703
|
* @param redact - The DEFAULT-coverage redactor, applied to `child()` bindings.
|
|
641
|
-
* Defaults to the identity so a hand-built instance
|
|
642
|
-
*
|
|
704
|
+
* Defaults to the identity so a hand-built instance still works; the module
|
|
705
|
+
* always injects the configured one.
|
|
643
706
|
*/
|
|
644
707
|
constructor(pino: Logger, redact?: Redactor);
|
|
645
708
|
/**
|
|
@@ -899,7 +962,7 @@ declare class DefaultStdoutDestination implements ILogDestination {
|
|
|
899
962
|
* // One line per entry, with the fields a project repeats on every line hidden.
|
|
900
963
|
* const view: PrettyViewOptions = {
|
|
901
964
|
* singleLine: true,
|
|
902
|
-
* ignore: 'pid,hostname,service,deployment,event
|
|
965
|
+
* ignore: 'pid,hostname,service,deployment,event\\.name'
|
|
903
966
|
* }
|
|
904
967
|
*/
|
|
905
968
|
interface PrettyViewOptions {
|
|
@@ -914,19 +977,60 @@ interface PrettyViewOptions {
|
|
|
914
977
|
* what a real sink receives is untouched. Extend rather than replace when the
|
|
915
978
|
* goal is quieter output — the default already hides the noisiest fields.
|
|
916
979
|
* Default: `'pid,hostname,service'`.
|
|
980
|
+
*
|
|
981
|
+
* **A dot means "nested path", so a field name CONTAINING a dot has to escape
|
|
982
|
+
* it.** This library emits `event.name` as a literal top-level key, so the
|
|
983
|
+
* obvious spelling silently hides nothing — `pino-pretty` looks for an `event`
|
|
984
|
+
* object with a `name` inside and finds neither. Measured on one entry, only
|
|
985
|
+
* the option changing:
|
|
986
|
+
*
|
|
987
|
+
* ```
|
|
988
|
+
* ignore: '…,event.name' → INFO: msg {"logKey":"X","event.name":"x"} ← still there
|
|
989
|
+
* ignore: '…,event\\.name' → INFO: msg {"logKey":"X"} ← hidden
|
|
990
|
+
* ```
|
|
991
|
+
*
|
|
992
|
+
* In a TypeScript string literal that is `'event\\.name'` — one real backslash
|
|
993
|
+
* reaching `pino-pretty`. Nested objects (`service`, `deployment`) need no
|
|
994
|
+
* escape; they really are paths.
|
|
917
995
|
*/
|
|
918
996
|
ignore?: string;
|
|
919
997
|
/**
|
|
920
|
-
* Render only the message line, hiding the record entirely.
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
*
|
|
998
|
+
* Render only the message line, hiding the record entirely. Display-only, and
|
|
999
|
+
* scoped to THIS destination: a field hidden here is still delivered in full to
|
|
1000
|
+
* every other destination registered alongside it.
|
|
1001
|
+
*
|
|
1002
|
+
* When pretty is the ONLY destination, that scope makes it total — `destinations`
|
|
1003
|
+
* replaces the default stdout sink, so there is no JSON copy behind the
|
|
1004
|
+
* rendering and a hidden field, `logKey` included, is not visible anywhere. That
|
|
1005
|
+
* is the point of the option rather than a caveat; use `messageFormat` to pull a
|
|
1006
|
+
* specific field back into the line. Default: `false`.
|
|
925
1007
|
*/
|
|
926
1008
|
hideObject?: boolean;
|
|
927
1009
|
/**
|
|
928
1010
|
* Template for the message line, e.g. `'[{context}] {msg}'`. The way to keep a
|
|
929
1011
|
* chosen field visible when `hideObject` is on.
|
|
1012
|
+
*
|
|
1013
|
+
* **Every placeholder EXCEPT `{msg}` is interpolated raw, and that reopens
|
|
1014
|
+
* terminal log forging.** This library normalizes line separators and control
|
|
1015
|
+
* characters in `msg` and in the stack — not in metadata, because escaping data
|
|
1016
|
+
* would mean rewriting what you asked to be logged. `pino-pretty` substitutes
|
|
1017
|
+
* whatever the field holds, so a newline in an interpolated field splits one
|
|
1018
|
+
* entry into two, and the second reads like a genuine record. Measured, with a
|
|
1019
|
+
* newline in `context`:
|
|
1020
|
+
*
|
|
1021
|
+
* ```
|
|
1022
|
+
* lines produced by ONE entry: 2
|
|
1023
|
+
* 1: "[10:35:14.484] INFO: [Auth"
|
|
1024
|
+
* 2: "[10:00:00.000] INFO: FORGED admin promoted] real entry …"
|
|
1025
|
+
* ```
|
|
1026
|
+
*
|
|
1027
|
+
* So: interpolate only fields whose values your own code sets. Never a field
|
|
1028
|
+
* carrying user input — `{tenantId}`, `{userId}`, a header, a query value. If
|
|
1029
|
+
* you need one of those visible, leave it in the record instead of the format
|
|
1030
|
+
* string. That closes THIS path — the raw placeholder — and no more: a metadata
|
|
1031
|
+
* value is not safe terminal text either, because `JSON.stringify` escapes only
|
|
1032
|
+
* C0 and emits DEL, the C1 range (U+0085 NEL included), U+2028 and U+2029
|
|
1033
|
+
* verbatim. Only `msg` and the stack carry the one-entry-one-line guarantee.
|
|
930
1034
|
*/
|
|
931
1035
|
messageFormat?: string;
|
|
932
1036
|
/** Timestamp format, or `false` to leave it raw. Default: `'SYS:HH:MM:ss.l'`. */
|
|
@@ -949,7 +1053,7 @@ interface PrettyViewOptions {
|
|
|
949
1053
|
*
|
|
950
1054
|
* // One line per entry, with this project's repeated fields hidden.
|
|
951
1055
|
* new PrettyDevDestination({
|
|
952
|
-
* view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event
|
|
1056
|
+
* view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event\\.name' }
|
|
953
1057
|
* })
|
|
954
1058
|
*
|
|
955
1059
|
* // Message-only, with the context pulled back into the line.
|
|
@@ -1031,6 +1135,39 @@ declare class PrettyDevDestination implements ILogDestination {
|
|
|
1031
1135
|
* @param payload — Newline-terminated JSON entry, UTF-8 encoded.
|
|
1032
1136
|
*/
|
|
1033
1137
|
write(payload: string): void;
|
|
1138
|
+
/**
|
|
1139
|
+
* Resolve anything still held, now that the registry knows what became of it.
|
|
1140
|
+
*
|
|
1141
|
+
* **Discard only where another sink is believed to have taken the same entries;
|
|
1142
|
+
* emit everything else.** Losing a boot entry is not an acceptable outcome, and
|
|
1143
|
+
* every richer policy tried here had a losing branch: trusting "a sink survived"
|
|
1144
|
+
* lost entries to a sink at a higher level, trusting a level lost them to a sink
|
|
1145
|
+
* that was itself the asker, then to one whose writes were throwing, then to one
|
|
1146
|
+
* whose write had not settled yet. Each of those is now folded into the single
|
|
1147
|
+
* signal handed in — and where it is uncertain, it says `false` and this drains.
|
|
1148
|
+
*
|
|
1149
|
+
* That signal is not a proof, and this hook does not treat it as one. It cannot
|
|
1150
|
+
* see an entry still queued inside the `Writable` adapter, because the adapter
|
|
1151
|
+
* has not called `destination.write()` for it yet. Discarding on it is a bet
|
|
1152
|
+
* that a duplicated boot line costs less than a lost one — which is the trade
|
|
1153
|
+
* this destination accepts, and which a destination that cannot lose anything
|
|
1154
|
+
* should decline by ignoring the flag and always emitting.
|
|
1155
|
+
*
|
|
1156
|
+
* The cost is stated rather than hidden: when nothing survived, every holding
|
|
1157
|
+
* destination drains, so N of them produce N copies of the boot entries. A
|
|
1158
|
+
* duplicated line in an already-degraded boot is a smaller harm than a lost one,
|
|
1159
|
+
* and it is loud rather than silent.
|
|
1160
|
+
*
|
|
1161
|
+
* A no-op once {@link onInit} succeeded — the buffer was flushed through the
|
|
1162
|
+
* transform there and is already empty.
|
|
1163
|
+
*
|
|
1164
|
+
* @param status.heldEntriesDeliveredElsewhere - Another live sink appears to
|
|
1165
|
+
* have taken everything this one took. A deduplication signal, not a proof —
|
|
1166
|
+
* see `ILogDestination.onRegistryReady` for what it cannot see.
|
|
1167
|
+
*/
|
|
1168
|
+
onRegistryReady(status: {
|
|
1169
|
+
readonly heldEntriesDeliveredElsewhere: boolean;
|
|
1170
|
+
}): void;
|
|
1034
1171
|
/**
|
|
1035
1172
|
* Hand every buffered entry to `emit`, in arrival order, and empty the buffer.
|
|
1036
1173
|
*
|