@bymax-one/nest-logger 1.1.0 → 1.2.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/CHANGELOG.md +446 -1
- package/README.md +381 -88
- package/dist/server/index.cjs +891 -145
- package/dist/server/index.d.cts +361 -51
- package/dist/server/index.d.ts +361 -51
- package/dist/server/index.mjs +896 -150
- package/dist/shared/index.cjs +15 -1
- package/dist/shared/index.d.cts +149 -8
- package/dist/shared/index.d.ts +149 -8
- package/dist/shared/index.mjs +15 -2
- package/package.json +1 -1
package/dist/shared/index.cjs
CHANGED
|
@@ -14,14 +14,28 @@ var RESERVED_LOG_KEYS = Object.freeze({
|
|
|
14
14
|
HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR",
|
|
15
15
|
HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR",
|
|
16
16
|
HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED",
|
|
17
|
+
HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED",
|
|
17
18
|
HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
|
|
18
19
|
HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
|
|
19
20
|
METHOD_EXECUTION: "METHOD_EXECUTION",
|
|
20
21
|
METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
|
|
21
22
|
LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
|
|
22
23
|
LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
|
|
23
|
-
LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED"
|
|
24
|
+
LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
|
|
25
|
+
LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
|
|
26
|
+
});
|
|
27
|
+
var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
|
|
28
|
+
/**
|
|
29
|
+
* Superseded before it was ever used. The request lifecycle terminates in one
|
|
30
|
+
* of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
|
|
31
|
+
* each carrying the same `duration` a generic "completed" entry would. Emitting
|
|
32
|
+
* it as well would double the terminal access-log volume to say nothing new.
|
|
33
|
+
* It stays claimed so an application cannot repurpose a name that reads like a
|
|
34
|
+
* library event.
|
|
35
|
+
*/
|
|
36
|
+
HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys"
|
|
24
37
|
});
|
|
25
38
|
|
|
26
39
|
exports.LOG_KEYS_CONVENTION_REGEX = LOG_KEYS_CONVENTION_REGEX;
|
|
27
40
|
exports.RESERVED_LOG_KEYS = RESERVED_LOG_KEYS;
|
|
41
|
+
exports.RESERVED_LOG_KEYS_NOT_EMITTED = RESERVED_LOG_KEYS_NOT_EMITTED;
|
package/dist/shared/index.d.cts
CHANGED
|
@@ -25,26 +25,141 @@ interface ServiceMetadata {
|
|
|
25
25
|
readonly name: string;
|
|
26
26
|
/** OTel attribute `service.version` — semver, commit SHA, or build tag. */
|
|
27
27
|
readonly version: string;
|
|
28
|
+
/**
|
|
29
|
+
* OTel attribute `service.namespace` (**Stable**) — the group the service
|
|
30
|
+
* belongs to, e.g. a team, a bounded context or a tenant of the platform.
|
|
31
|
+
* Two services may share a `name` as long as their namespaces differ.
|
|
32
|
+
*/
|
|
33
|
+
readonly namespace?: string;
|
|
34
|
+
/**
|
|
35
|
+
* OTel attribute `service.instance.id` (**Stable**) — identifies ONE running
|
|
36
|
+
* instance, so the triplet (namespace, name, instanceId) is globally unique.
|
|
37
|
+
*
|
|
38
|
+
* The library never generates this. A value minted here would be the logger's
|
|
39
|
+
* rather than the OpenTelemetry Resource's, so logs and traces would disagree
|
|
40
|
+
* about which instance served a request, and it would change on every restart
|
|
41
|
+
* while looking authoritative. Supply it from the platform — the Kubernetes
|
|
42
|
+
* pod UID, the ECS task ARN, the VM instance id — or through
|
|
43
|
+
* `OTEL_RESOURCE_ATTRIBUTES`, which is the same source the SDK reads.
|
|
44
|
+
*
|
|
45
|
+
* Treat it as HIGH cardinality: fine as a log field, not as a metric label.
|
|
46
|
+
*/
|
|
47
|
+
readonly instanceId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* OTel attribute `deployment.environment.name` (**Stable**) — `production`,
|
|
50
|
+
* `staging`, and so on. Falls back to `NODE_ENV` when omitted.
|
|
51
|
+
*
|
|
52
|
+
* The older `deployment.environment` spelling is **Deprecated** in the
|
|
53
|
+
* semantic conventions and is never emitted.
|
|
54
|
+
*/
|
|
55
|
+
readonly environment?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Service identity after precedence has been applied.
|
|
59
|
+
*
|
|
60
|
+
* Distinct from {@link ServiceMetadata} because the optional fields here mean
|
|
61
|
+
* "resolved to nothing" rather than "not configured": every source — options,
|
|
62
|
+
* `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES`, `NODE_ENV` — has already been
|
|
63
|
+
* consulted, and a field still absent will not appear on any entry.
|
|
64
|
+
*/
|
|
65
|
+
interface ResolvedServiceMetadata {
|
|
66
|
+
/** `service.name`, always present. */
|
|
67
|
+
name: string;
|
|
68
|
+
/** `service.version`, always present. */
|
|
69
|
+
version: string;
|
|
70
|
+
/** `service.namespace`, when any source supplied one. */
|
|
71
|
+
namespace?: string;
|
|
72
|
+
/** `service.instance.id`, when any source supplied one. */
|
|
73
|
+
instanceId?: string;
|
|
74
|
+
/** `deployment.environment.name`, when any source supplied one. */
|
|
75
|
+
environment?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The `service` block as it appears in an EMITTED record, under the default
|
|
79
|
+
* `resourceFormat: 'nested'`.
|
|
80
|
+
*
|
|
81
|
+
* Distinct from {@link ServiceMetadata} on purpose, and the distinction is the
|
|
82
|
+
* kind of defect this library has already been bitten by once: a published type
|
|
83
|
+
* that describes something the runtime never emits. `ServiceMetadata` is what a
|
|
84
|
+
* consumer CONFIGURES — flat option names like `instanceId` and `environment`.
|
|
85
|
+
* What comes out is the flattened OTel attribute path: `service.instance.id`
|
|
86
|
+
* nests as `service: { instance: { id } }`, and the environment is not under
|
|
87
|
+
* `service` at all, it is `deployment.environment.name`. Typing the emitted
|
|
88
|
+
* record with the configuration interface would advertise `entry.service.instanceId`
|
|
89
|
+
* to every consumer, and that property does not exist on any entry.
|
|
90
|
+
*
|
|
91
|
+
* Under `resourceFormat: 'flat'` these values appear as dotted top-level keys
|
|
92
|
+
* (`"service.instance.id"`), which {@link LogEntry}'s index signature already
|
|
93
|
+
* admits — a flat record simply has no `service` object.
|
|
94
|
+
*/
|
|
95
|
+
interface EmittedServiceResource {
|
|
96
|
+
/** OTel `service.name`. */
|
|
97
|
+
readonly name: string;
|
|
98
|
+
/** OTel `service.version`. */
|
|
99
|
+
readonly version: string;
|
|
100
|
+
/** OTel `service.namespace`, when resolved. */
|
|
101
|
+
readonly namespace?: string;
|
|
102
|
+
/** OTel `service.instance.id`, nested as the attribute path spells it. */
|
|
103
|
+
readonly instance?: {
|
|
104
|
+
readonly id: string;
|
|
105
|
+
};
|
|
106
|
+
/** Consumer-supplied extras carried through from the `service` option. */
|
|
107
|
+
readonly [key: string]: unknown;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The `deployment` block as it appears in an EMITTED record under
|
|
111
|
+
* `resourceFormat: 'nested'`, carrying `deployment.environment.name`.
|
|
112
|
+
*
|
|
113
|
+
* Absent entirely when no source resolved an environment. The deprecated
|
|
114
|
+
* `deployment.environment` spelling is never emitted.
|
|
115
|
+
*/
|
|
116
|
+
interface EmittedDeploymentResource {
|
|
117
|
+
/** OTel `deployment.environment.name`, flattened from its attribute path. */
|
|
118
|
+
readonly environment: {
|
|
119
|
+
readonly name: string;
|
|
120
|
+
};
|
|
28
121
|
}
|
|
29
122
|
|
|
30
123
|
/**
|
|
31
124
|
* Shape of a single log entry as serialized to JSON output.
|
|
32
125
|
*
|
|
33
|
-
* Used by destinations and downstream parsers (
|
|
126
|
+
* Used by destinations and downstream parsers (Loki, Elastic, Datadog).
|
|
34
127
|
* The trailing index signature `[key: string]: unknown` covers arbitrary
|
|
35
128
|
* structured fields injected by application logs.
|
|
129
|
+
*
|
|
130
|
+
* `level` and `time` describe what the library ACTUALLY writes. Before `1.2.0`
|
|
131
|
+
* they were declared `number`, which the runtime never produced: the Pino
|
|
132
|
+
* instance is built with `formatters.level` returning the string label and a
|
|
133
|
+
* `timestamp` function emitting an ISO 8601 string. A destination written
|
|
134
|
+
* against the old declaration type-checked and then failed at runtime — the
|
|
135
|
+
* README's own Loki example called `BigInt(entry.time)` on an ISO string, which
|
|
136
|
+
* throws. See `log-entry-contract.e2e-spec.ts`, which asserts the declaration
|
|
137
|
+
* against a real serialized record so the two can never drift again.
|
|
36
138
|
*/
|
|
37
139
|
interface LogEntry {
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Severity as the Pino string label (`'info'`, `'error'`, …) — NOT the numeric
|
|
142
|
+
* code. Convert with `PINO_LEVEL_NUMBERS` when a numeric column is needed.
|
|
143
|
+
*/
|
|
144
|
+
level: LogLevel;
|
|
145
|
+
/**
|
|
146
|
+
* ISO 8601 UTC timestamp string, e.g. `'2026-08-12T09:25:46.520Z'`. Parse with
|
|
147
|
+
* `Date.parse(entry.time)` for epoch milliseconds. A consumer-supplied
|
|
148
|
+
* `timestamp` option may change the format, but never the type.
|
|
149
|
+
*/
|
|
150
|
+
time: string;
|
|
42
151
|
/** Human-readable message. */
|
|
43
152
|
msg: string;
|
|
44
153
|
/** Convention key — `MODULE_ACTION_RESULT` format. */
|
|
45
154
|
logKey?: string;
|
|
46
|
-
/**
|
|
47
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Service identity as EMITTED — see {@link EmittedServiceResource}. Not the
|
|
157
|
+
* configuration shape: `service.instance.id` nests, and the environment lives
|
|
158
|
+
* under `deployment`, not here.
|
|
159
|
+
*/
|
|
160
|
+
service?: EmittedServiceResource;
|
|
161
|
+
/** Deployment identity as emitted — see {@link EmittedDeploymentResource}. */
|
|
162
|
+
deployment?: EmittedDeploymentResource;
|
|
48
163
|
/** Optional NestJS context (typically the emitting class name). */
|
|
49
164
|
context?: string;
|
|
50
165
|
/** Optional correlation IDs propagated via AsyncLocalStorage. */
|
|
@@ -92,6 +207,12 @@ declare const LOG_KEYS_CONVENTION_REGEX: RegExp;
|
|
|
92
207
|
*
|
|
93
208
|
* Consumer apps SHOULD NOT use these names for application-level events
|
|
94
209
|
* to avoid collision in log aggregation queries (Datadog, Loki, Elastic).
|
|
210
|
+
*
|
|
211
|
+
* Every key here is emitted by some code path, EXCEPT the ones listed in
|
|
212
|
+
* {@link RESERVED_LOG_KEYS_NOT_EMITTED}, which are reserved-only and carry the
|
|
213
|
+
* reason they stay that way. `reserved-log-keys.constants.spec.ts` enforces the
|
|
214
|
+
* split, so a key can never again be declared, documented as a signal, and then
|
|
215
|
+
* silently never written.
|
|
95
216
|
*/
|
|
96
217
|
declare const RESERVED_LOG_KEYS: Readonly<{
|
|
97
218
|
readonly LOGGER_BOOTSTRAP_OK: "LOGGER_BOOTSTRAP_OK";
|
|
@@ -103,6 +224,7 @@ declare const RESERVED_LOG_KEYS: Readonly<{
|
|
|
103
224
|
readonly HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR";
|
|
104
225
|
readonly HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR";
|
|
105
226
|
readonly HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED";
|
|
227
|
+
readonly HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED";
|
|
106
228
|
readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
|
|
107
229
|
readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
|
|
108
230
|
readonly METHOD_EXECUTION: "METHOD_EXECUTION";
|
|
@@ -110,6 +232,25 @@ declare const RESERVED_LOG_KEYS: Readonly<{
|
|
|
110
232
|
readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
|
|
111
233
|
readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
|
|
112
234
|
readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
|
|
235
|
+
readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
|
|
236
|
+
}>;
|
|
237
|
+
/**
|
|
238
|
+
* Keys that are reserved but intentionally never emitted, each with the reason.
|
|
239
|
+
*
|
|
240
|
+
* A name in this map is claimed so no application event can take it, but the
|
|
241
|
+
* library commits to not writing it. Anything NOT listed here must be reachable
|
|
242
|
+
* from some code path — the spec asserts both directions.
|
|
243
|
+
*/
|
|
244
|
+
declare const RESERVED_LOG_KEYS_NOT_EMITTED: Readonly<{
|
|
245
|
+
/**
|
|
246
|
+
* Superseded before it was ever used. The request lifecycle terminates in one
|
|
247
|
+
* of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
|
|
248
|
+
* each carrying the same `duration` a generic "completed" entry would. Emitting
|
|
249
|
+
* it as well would double the terminal access-log volume to say nothing new.
|
|
250
|
+
* It stays claimed so an application cannot repurpose a name that reads like a
|
|
251
|
+
* library event.
|
|
252
|
+
*/
|
|
253
|
+
readonly HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys";
|
|
113
254
|
}>;
|
|
114
255
|
/**
|
|
115
256
|
* Strongly-typed union of every reserved log key value, derived from
|
|
@@ -117,4 +258,4 @@ declare const RESERVED_LOG_KEYS: Readonly<{
|
|
|
117
258
|
*/
|
|
118
259
|
type ReservedLogKey = (typeof RESERVED_LOG_KEYS)[keyof typeof RESERVED_LOG_KEYS];
|
|
119
260
|
|
|
120
|
-
export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, type ReservedLogKey, type ServiceMetadata };
|
|
261
|
+
export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ResolvedServiceMetadata, type ServiceMetadata };
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -25,26 +25,141 @@ interface ServiceMetadata {
|
|
|
25
25
|
readonly name: string;
|
|
26
26
|
/** OTel attribute `service.version` — semver, commit SHA, or build tag. */
|
|
27
27
|
readonly version: string;
|
|
28
|
+
/**
|
|
29
|
+
* OTel attribute `service.namespace` (**Stable**) — the group the service
|
|
30
|
+
* belongs to, e.g. a team, a bounded context or a tenant of the platform.
|
|
31
|
+
* Two services may share a `name` as long as their namespaces differ.
|
|
32
|
+
*/
|
|
33
|
+
readonly namespace?: string;
|
|
34
|
+
/**
|
|
35
|
+
* OTel attribute `service.instance.id` (**Stable**) — identifies ONE running
|
|
36
|
+
* instance, so the triplet (namespace, name, instanceId) is globally unique.
|
|
37
|
+
*
|
|
38
|
+
* The library never generates this. A value minted here would be the logger's
|
|
39
|
+
* rather than the OpenTelemetry Resource's, so logs and traces would disagree
|
|
40
|
+
* about which instance served a request, and it would change on every restart
|
|
41
|
+
* while looking authoritative. Supply it from the platform — the Kubernetes
|
|
42
|
+
* pod UID, the ECS task ARN, the VM instance id — or through
|
|
43
|
+
* `OTEL_RESOURCE_ATTRIBUTES`, which is the same source the SDK reads.
|
|
44
|
+
*
|
|
45
|
+
* Treat it as HIGH cardinality: fine as a log field, not as a metric label.
|
|
46
|
+
*/
|
|
47
|
+
readonly instanceId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* OTel attribute `deployment.environment.name` (**Stable**) — `production`,
|
|
50
|
+
* `staging`, and so on. Falls back to `NODE_ENV` when omitted.
|
|
51
|
+
*
|
|
52
|
+
* The older `deployment.environment` spelling is **Deprecated** in the
|
|
53
|
+
* semantic conventions and is never emitted.
|
|
54
|
+
*/
|
|
55
|
+
readonly environment?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Service identity after precedence has been applied.
|
|
59
|
+
*
|
|
60
|
+
* Distinct from {@link ServiceMetadata} because the optional fields here mean
|
|
61
|
+
* "resolved to nothing" rather than "not configured": every source — options,
|
|
62
|
+
* `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES`, `NODE_ENV` — has already been
|
|
63
|
+
* consulted, and a field still absent will not appear on any entry.
|
|
64
|
+
*/
|
|
65
|
+
interface ResolvedServiceMetadata {
|
|
66
|
+
/** `service.name`, always present. */
|
|
67
|
+
name: string;
|
|
68
|
+
/** `service.version`, always present. */
|
|
69
|
+
version: string;
|
|
70
|
+
/** `service.namespace`, when any source supplied one. */
|
|
71
|
+
namespace?: string;
|
|
72
|
+
/** `service.instance.id`, when any source supplied one. */
|
|
73
|
+
instanceId?: string;
|
|
74
|
+
/** `deployment.environment.name`, when any source supplied one. */
|
|
75
|
+
environment?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The `service` block as it appears in an EMITTED record, under the default
|
|
79
|
+
* `resourceFormat: 'nested'`.
|
|
80
|
+
*
|
|
81
|
+
* Distinct from {@link ServiceMetadata} on purpose, and the distinction is the
|
|
82
|
+
* kind of defect this library has already been bitten by once: a published type
|
|
83
|
+
* that describes something the runtime never emits. `ServiceMetadata` is what a
|
|
84
|
+
* consumer CONFIGURES — flat option names like `instanceId` and `environment`.
|
|
85
|
+
* What comes out is the flattened OTel attribute path: `service.instance.id`
|
|
86
|
+
* nests as `service: { instance: { id } }`, and the environment is not under
|
|
87
|
+
* `service` at all, it is `deployment.environment.name`. Typing the emitted
|
|
88
|
+
* record with the configuration interface would advertise `entry.service.instanceId`
|
|
89
|
+
* to every consumer, and that property does not exist on any entry.
|
|
90
|
+
*
|
|
91
|
+
* Under `resourceFormat: 'flat'` these values appear as dotted top-level keys
|
|
92
|
+
* (`"service.instance.id"`), which {@link LogEntry}'s index signature already
|
|
93
|
+
* admits — a flat record simply has no `service` object.
|
|
94
|
+
*/
|
|
95
|
+
interface EmittedServiceResource {
|
|
96
|
+
/** OTel `service.name`. */
|
|
97
|
+
readonly name: string;
|
|
98
|
+
/** OTel `service.version`. */
|
|
99
|
+
readonly version: string;
|
|
100
|
+
/** OTel `service.namespace`, when resolved. */
|
|
101
|
+
readonly namespace?: string;
|
|
102
|
+
/** OTel `service.instance.id`, nested as the attribute path spells it. */
|
|
103
|
+
readonly instance?: {
|
|
104
|
+
readonly id: string;
|
|
105
|
+
};
|
|
106
|
+
/** Consumer-supplied extras carried through from the `service` option. */
|
|
107
|
+
readonly [key: string]: unknown;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The `deployment` block as it appears in an EMITTED record under
|
|
111
|
+
* `resourceFormat: 'nested'`, carrying `deployment.environment.name`.
|
|
112
|
+
*
|
|
113
|
+
* Absent entirely when no source resolved an environment. The deprecated
|
|
114
|
+
* `deployment.environment` spelling is never emitted.
|
|
115
|
+
*/
|
|
116
|
+
interface EmittedDeploymentResource {
|
|
117
|
+
/** OTel `deployment.environment.name`, flattened from its attribute path. */
|
|
118
|
+
readonly environment: {
|
|
119
|
+
readonly name: string;
|
|
120
|
+
};
|
|
28
121
|
}
|
|
29
122
|
|
|
30
123
|
/**
|
|
31
124
|
* Shape of a single log entry as serialized to JSON output.
|
|
32
125
|
*
|
|
33
|
-
* Used by destinations and downstream parsers (
|
|
126
|
+
* Used by destinations and downstream parsers (Loki, Elastic, Datadog).
|
|
34
127
|
* The trailing index signature `[key: string]: unknown` covers arbitrary
|
|
35
128
|
* structured fields injected by application logs.
|
|
129
|
+
*
|
|
130
|
+
* `level` and `time` describe what the library ACTUALLY writes. Before `1.2.0`
|
|
131
|
+
* they were declared `number`, which the runtime never produced: the Pino
|
|
132
|
+
* instance is built with `formatters.level` returning the string label and a
|
|
133
|
+
* `timestamp` function emitting an ISO 8601 string. A destination written
|
|
134
|
+
* against the old declaration type-checked and then failed at runtime — the
|
|
135
|
+
* README's own Loki example called `BigInt(entry.time)` on an ISO string, which
|
|
136
|
+
* throws. See `log-entry-contract.e2e-spec.ts`, which asserts the declaration
|
|
137
|
+
* against a real serialized record so the two can never drift again.
|
|
36
138
|
*/
|
|
37
139
|
interface LogEntry {
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Severity as the Pino string label (`'info'`, `'error'`, …) — NOT the numeric
|
|
142
|
+
* code. Convert with `PINO_LEVEL_NUMBERS` when a numeric column is needed.
|
|
143
|
+
*/
|
|
144
|
+
level: LogLevel;
|
|
145
|
+
/**
|
|
146
|
+
* ISO 8601 UTC timestamp string, e.g. `'2026-08-12T09:25:46.520Z'`. Parse with
|
|
147
|
+
* `Date.parse(entry.time)` for epoch milliseconds. A consumer-supplied
|
|
148
|
+
* `timestamp` option may change the format, but never the type.
|
|
149
|
+
*/
|
|
150
|
+
time: string;
|
|
42
151
|
/** Human-readable message. */
|
|
43
152
|
msg: string;
|
|
44
153
|
/** Convention key — `MODULE_ACTION_RESULT` format. */
|
|
45
154
|
logKey?: string;
|
|
46
|
-
/**
|
|
47
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Service identity as EMITTED — see {@link EmittedServiceResource}. Not the
|
|
157
|
+
* configuration shape: `service.instance.id` nests, and the environment lives
|
|
158
|
+
* under `deployment`, not here.
|
|
159
|
+
*/
|
|
160
|
+
service?: EmittedServiceResource;
|
|
161
|
+
/** Deployment identity as emitted — see {@link EmittedDeploymentResource}. */
|
|
162
|
+
deployment?: EmittedDeploymentResource;
|
|
48
163
|
/** Optional NestJS context (typically the emitting class name). */
|
|
49
164
|
context?: string;
|
|
50
165
|
/** Optional correlation IDs propagated via AsyncLocalStorage. */
|
|
@@ -92,6 +207,12 @@ declare const LOG_KEYS_CONVENTION_REGEX: RegExp;
|
|
|
92
207
|
*
|
|
93
208
|
* Consumer apps SHOULD NOT use these names for application-level events
|
|
94
209
|
* to avoid collision in log aggregation queries (Datadog, Loki, Elastic).
|
|
210
|
+
*
|
|
211
|
+
* Every key here is emitted by some code path, EXCEPT the ones listed in
|
|
212
|
+
* {@link RESERVED_LOG_KEYS_NOT_EMITTED}, which are reserved-only and carry the
|
|
213
|
+
* reason they stay that way. `reserved-log-keys.constants.spec.ts` enforces the
|
|
214
|
+
* split, so a key can never again be declared, documented as a signal, and then
|
|
215
|
+
* silently never written.
|
|
95
216
|
*/
|
|
96
217
|
declare const RESERVED_LOG_KEYS: Readonly<{
|
|
97
218
|
readonly LOGGER_BOOTSTRAP_OK: "LOGGER_BOOTSTRAP_OK";
|
|
@@ -103,6 +224,7 @@ declare const RESERVED_LOG_KEYS: Readonly<{
|
|
|
103
224
|
readonly HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR";
|
|
104
225
|
readonly HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR";
|
|
105
226
|
readonly HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED";
|
|
227
|
+
readonly HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED";
|
|
106
228
|
readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
|
|
107
229
|
readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
|
|
108
230
|
readonly METHOD_EXECUTION: "METHOD_EXECUTION";
|
|
@@ -110,6 +232,25 @@ declare const RESERVED_LOG_KEYS: Readonly<{
|
|
|
110
232
|
readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
|
|
111
233
|
readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
|
|
112
234
|
readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
|
|
235
|
+
readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
|
|
236
|
+
}>;
|
|
237
|
+
/**
|
|
238
|
+
* Keys that are reserved but intentionally never emitted, each with the reason.
|
|
239
|
+
*
|
|
240
|
+
* A name in this map is claimed so no application event can take it, but the
|
|
241
|
+
* library commits to not writing it. Anything NOT listed here must be reachable
|
|
242
|
+
* from some code path — the spec asserts both directions.
|
|
243
|
+
*/
|
|
244
|
+
declare const RESERVED_LOG_KEYS_NOT_EMITTED: Readonly<{
|
|
245
|
+
/**
|
|
246
|
+
* Superseded before it was ever used. The request lifecycle terminates in one
|
|
247
|
+
* of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
|
|
248
|
+
* each carrying the same `duration` a generic "completed" entry would. Emitting
|
|
249
|
+
* it as well would double the terminal access-log volume to say nothing new.
|
|
250
|
+
* It stays claimed so an application cannot repurpose a name that reads like a
|
|
251
|
+
* library event.
|
|
252
|
+
*/
|
|
253
|
+
readonly HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys";
|
|
113
254
|
}>;
|
|
114
255
|
/**
|
|
115
256
|
* Strongly-typed union of every reserved log key value, derived from
|
|
@@ -117,4 +258,4 @@ declare const RESERVED_LOG_KEYS: Readonly<{
|
|
|
117
258
|
*/
|
|
118
259
|
type ReservedLogKey = (typeof RESERVED_LOG_KEYS)[keyof typeof RESERVED_LOG_KEYS];
|
|
119
260
|
|
|
120
|
-
export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, type ReservedLogKey, type ServiceMetadata };
|
|
261
|
+
export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ResolvedServiceMetadata, type ServiceMetadata };
|
package/dist/shared/index.mjs
CHANGED
|
@@ -12,13 +12,26 @@ var RESERVED_LOG_KEYS = Object.freeze({
|
|
|
12
12
|
HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR",
|
|
13
13
|
HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR",
|
|
14
14
|
HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED",
|
|
15
|
+
HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED",
|
|
15
16
|
HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
|
|
16
17
|
HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
|
|
17
18
|
METHOD_EXECUTION: "METHOD_EXECUTION",
|
|
18
19
|
METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
|
|
19
20
|
LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
|
|
20
21
|
LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
|
|
21
|
-
LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED"
|
|
22
|
+
LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
|
|
23
|
+
LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
|
|
24
|
+
});
|
|
25
|
+
var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
|
|
26
|
+
/**
|
|
27
|
+
* Superseded before it was ever used. The request lifecycle terminates in one
|
|
28
|
+
* of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
|
|
29
|
+
* each carrying the same `duration` a generic "completed" entry would. Emitting
|
|
30
|
+
* it as well would double the terminal access-log volume to say nothing new.
|
|
31
|
+
* It stays claimed so an application cannot repurpose a name that reads like a
|
|
32
|
+
* library event.
|
|
33
|
+
*/
|
|
34
|
+
HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys"
|
|
22
35
|
});
|
|
23
36
|
|
|
24
|
-
export { LOG_KEYS_CONVENTION_REGEX, RESERVED_LOG_KEYS };
|
|
37
|
+
export { LOG_KEYS_CONVENTION_REGEX, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED };
|
package/package.json
CHANGED