@bymax-one/nest-logger 1.1.0 → 1.2.0

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.
@@ -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;
@@ -30,15 +30,31 @@ interface ServiceMetadata {
30
30
  /**
31
31
  * Shape of a single log entry as serialized to JSON output.
32
32
  *
33
- * Used by destinations and downstream parsers (Datadog, Loki, Elastic).
33
+ * Used by destinations and downstream parsers (Loki, Elastic, Datadog).
34
34
  * The trailing index signature `[key: string]: unknown` covers arbitrary
35
35
  * structured fields injected by application logs.
36
+ *
37
+ * `level` and `time` describe what the library ACTUALLY writes. Before `1.2.0`
38
+ * they were declared `number`, which the runtime never produced: the Pino
39
+ * instance is built with `formatters.level` returning the string label and a
40
+ * `timestamp` function emitting an ISO 8601 string. A destination written
41
+ * against the old declaration type-checked and then failed at runtime — the
42
+ * README's own Loki example called `BigInt(entry.time)` on an ISO string, which
43
+ * throws. See `log-entry-contract.e2e-spec.ts`, which asserts the declaration
44
+ * against a real serialized record so the two can never drift again.
36
45
  */
37
46
  interface LogEntry {
38
- /** Pino numeric level (30 = info, 50 = error, etc.). */
39
- level: number;
40
- /** ISO 8601 UTC timestamp string OR epoch milliseconds (numeric). */
41
- time: string | number;
47
+ /**
48
+ * Severity as the Pino string label (`'info'`, `'error'`, …) — NOT the numeric
49
+ * code. Convert with `PINO_LEVEL_NUMBERS` when a numeric column is needed.
50
+ */
51
+ level: LogLevel;
52
+ /**
53
+ * ISO 8601 UTC timestamp string, e.g. `'2026-08-12T09:25:46.520Z'`. Parse with
54
+ * `Date.parse(entry.time)` for epoch milliseconds. A consumer-supplied
55
+ * `timestamp` option may change the format, but never the type.
56
+ */
57
+ time: string;
42
58
  /** Human-readable message. */
43
59
  msg: string;
44
60
  /** Convention key — `MODULE_ACTION_RESULT` format. */
@@ -92,6 +108,12 @@ declare const LOG_KEYS_CONVENTION_REGEX: RegExp;
92
108
  *
93
109
  * Consumer apps SHOULD NOT use these names for application-level events
94
110
  * to avoid collision in log aggregation queries (Datadog, Loki, Elastic).
111
+ *
112
+ * Every key here is emitted by some code path, EXCEPT the ones listed in
113
+ * {@link RESERVED_LOG_KEYS_NOT_EMITTED}, which are reserved-only and carry the
114
+ * reason they stay that way. `reserved-log-keys.constants.spec.ts` enforces the
115
+ * split, so a key can never again be declared, documented as a signal, and then
116
+ * silently never written.
95
117
  */
96
118
  declare const RESERVED_LOG_KEYS: Readonly<{
97
119
  readonly LOGGER_BOOTSTRAP_OK: "LOGGER_BOOTSTRAP_OK";
@@ -103,6 +125,7 @@ declare const RESERVED_LOG_KEYS: Readonly<{
103
125
  readonly HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR";
104
126
  readonly HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR";
105
127
  readonly HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED";
128
+ readonly HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED";
106
129
  readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
107
130
  readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
108
131
  readonly METHOD_EXECUTION: "METHOD_EXECUTION";
@@ -110,6 +133,25 @@ declare const RESERVED_LOG_KEYS: Readonly<{
110
133
  readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
111
134
  readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
112
135
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
136
+ readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
137
+ }>;
138
+ /**
139
+ * Keys that are reserved but intentionally never emitted, each with the reason.
140
+ *
141
+ * A name in this map is claimed so no application event can take it, but the
142
+ * library commits to not writing it. Anything NOT listed here must be reachable
143
+ * from some code path — the spec asserts both directions.
144
+ */
145
+ declare const RESERVED_LOG_KEYS_NOT_EMITTED: Readonly<{
146
+ /**
147
+ * Superseded before it was ever used. The request lifecycle terminates in one
148
+ * of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
149
+ * each carrying the same `duration` a generic "completed" entry would. Emitting
150
+ * it as well would double the terminal access-log volume to say nothing new.
151
+ * It stays claimed so an application cannot repurpose a name that reads like a
152
+ * library event.
153
+ */
154
+ readonly HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys";
113
155
  }>;
114
156
  /**
115
157
  * Strongly-typed union of every reserved log key value, derived from
@@ -117,4 +159,4 @@ declare const RESERVED_LOG_KEYS: Readonly<{
117
159
  */
118
160
  type ReservedLogKey = (typeof RESERVED_LOG_KEYS)[keyof typeof RESERVED_LOG_KEYS];
119
161
 
120
- export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, type ReservedLogKey, type ServiceMetadata };
162
+ export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ServiceMetadata };
@@ -30,15 +30,31 @@ interface ServiceMetadata {
30
30
  /**
31
31
  * Shape of a single log entry as serialized to JSON output.
32
32
  *
33
- * Used by destinations and downstream parsers (Datadog, Loki, Elastic).
33
+ * Used by destinations and downstream parsers (Loki, Elastic, Datadog).
34
34
  * The trailing index signature `[key: string]: unknown` covers arbitrary
35
35
  * structured fields injected by application logs.
36
+ *
37
+ * `level` and `time` describe what the library ACTUALLY writes. Before `1.2.0`
38
+ * they were declared `number`, which the runtime never produced: the Pino
39
+ * instance is built with `formatters.level` returning the string label and a
40
+ * `timestamp` function emitting an ISO 8601 string. A destination written
41
+ * against the old declaration type-checked and then failed at runtime — the
42
+ * README's own Loki example called `BigInt(entry.time)` on an ISO string, which
43
+ * throws. See `log-entry-contract.e2e-spec.ts`, which asserts the declaration
44
+ * against a real serialized record so the two can never drift again.
36
45
  */
37
46
  interface LogEntry {
38
- /** Pino numeric level (30 = info, 50 = error, etc.). */
39
- level: number;
40
- /** ISO 8601 UTC timestamp string OR epoch milliseconds (numeric). */
41
- time: string | number;
47
+ /**
48
+ * Severity as the Pino string label (`'info'`, `'error'`, …) — NOT the numeric
49
+ * code. Convert with `PINO_LEVEL_NUMBERS` when a numeric column is needed.
50
+ */
51
+ level: LogLevel;
52
+ /**
53
+ * ISO 8601 UTC timestamp string, e.g. `'2026-08-12T09:25:46.520Z'`. Parse with
54
+ * `Date.parse(entry.time)` for epoch milliseconds. A consumer-supplied
55
+ * `timestamp` option may change the format, but never the type.
56
+ */
57
+ time: string;
42
58
  /** Human-readable message. */
43
59
  msg: string;
44
60
  /** Convention key — `MODULE_ACTION_RESULT` format. */
@@ -92,6 +108,12 @@ declare const LOG_KEYS_CONVENTION_REGEX: RegExp;
92
108
  *
93
109
  * Consumer apps SHOULD NOT use these names for application-level events
94
110
  * to avoid collision in log aggregation queries (Datadog, Loki, Elastic).
111
+ *
112
+ * Every key here is emitted by some code path, EXCEPT the ones listed in
113
+ * {@link RESERVED_LOG_KEYS_NOT_EMITTED}, which are reserved-only and carry the
114
+ * reason they stay that way. `reserved-log-keys.constants.spec.ts` enforces the
115
+ * split, so a key can never again be declared, documented as a signal, and then
116
+ * silently never written.
95
117
  */
96
118
  declare const RESERVED_LOG_KEYS: Readonly<{
97
119
  readonly LOGGER_BOOTSTRAP_OK: "LOGGER_BOOTSTRAP_OK";
@@ -103,6 +125,7 @@ declare const RESERVED_LOG_KEYS: Readonly<{
103
125
  readonly HTTP_REQUEST_CLIENT_ERROR: "HTTP_REQUEST_CLIENT_ERROR";
104
126
  readonly HTTP_REQUEST_SERVER_ERROR: "HTTP_REQUEST_SERVER_ERROR";
105
127
  readonly HTTP_REQUEST_COMPLETED: "HTTP_REQUEST_COMPLETED";
128
+ readonly HTTP_REQUEST_ABORTED: "HTTP_REQUEST_ABORTED";
106
129
  readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
107
130
  readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
108
131
  readonly METHOD_EXECUTION: "METHOD_EXECUTION";
@@ -110,6 +133,25 @@ declare const RESERVED_LOG_KEYS: Readonly<{
110
133
  readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
111
134
  readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
112
135
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
136
+ readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
137
+ }>;
138
+ /**
139
+ * Keys that are reserved but intentionally never emitted, each with the reason.
140
+ *
141
+ * A name in this map is claimed so no application event can take it, but the
142
+ * library commits to not writing it. Anything NOT listed here must be reachable
143
+ * from some code path — the spec asserts both directions.
144
+ */
145
+ declare const RESERVED_LOG_KEYS_NOT_EMITTED: Readonly<{
146
+ /**
147
+ * Superseded before it was ever used. The request lifecycle terminates in one
148
+ * of `HTTP_REQUEST_SUCCESS` / `_REDIRECT` / `_CLIENT_ERROR` / `_SERVER_ERROR`,
149
+ * each carrying the same `duration` a generic "completed" entry would. Emitting
150
+ * it as well would double the terminal access-log volume to say nothing new.
151
+ * It stays claimed so an application cannot repurpose a name that reads like a
152
+ * library event.
153
+ */
154
+ readonly HTTP_REQUEST_COMPLETED: "reserved: superseded by the four status-specific terminal keys";
113
155
  }>;
114
156
  /**
115
157
  * Strongly-typed union of every reserved log key value, derived from
@@ -117,4 +159,4 @@ declare const RESERVED_LOG_KEYS: Readonly<{
117
159
  */
118
160
  type ReservedLogKey = (typeof RESERVED_LOG_KEYS)[keyof typeof RESERVED_LOG_KEYS];
119
161
 
120
- export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, type ReservedLogKey, type ServiceMetadata };
162
+ export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ServiceMetadata };
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-logger",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Structured JSON logging for NestJS based on Pino 10, with optional OpenTelemetry correlation.",
5
5
  "author": "Bymax One <support@bymax.one>",
6
6
  "license": "MIT",