@bymax-one/nest-logger 1.4.5 → 1.4.6

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 CHANGED
@@ -11,6 +11,63 @@ heading here.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.4.6] - 2026-11-01
15
+
16
+ ### Fixed
17
+
18
+ Five places swallowed a failed side effect with no trace. Each now leaves one.
19
+
20
+ - **A destination failure whose cause cannot be read is no longer dropped.** When a sink's `onInit`,
21
+ `onRegistryReady` or `write` failed with a value that has no text form (a null-prototype object, a
22
+ throwing `toString`, an `Error` with throwing `name` or `message` getters), the `stderr` line was not
23
+ written at all and the sink stopped receiving entries unannounced. The line is now written with
24
+ `err: { type: 'UnknownError', message: 'unreadable value' }`.
25
+ - **`PinoUnexpectedErrorSink` announces a report it had to drop.** When logging the report threw, or
26
+ the report could not be read, the `HTTP_UNEXPECTED_ERROR` entry, the only record of an unhandled
27
+ exception, vanished silently. One `HTTP_UNEXPECTED_ERROR_DROPPED` line now goes to `stderr`, outside
28
+ the sink set that may be what failed. The response is unaffected.
29
+ - **`PrettyDevDestination` reports the real failure.** Every failure of `import('pino-pretty')` or of
30
+ `build()` was rethrown as "pino-pretty is not installed" with the original error discarded. Only a
31
+ failure to resolve `pino-pretty` itself keeps that message; anything else throws
32
+ `[PrettyDevDestination] pino-pretty failed to start: <message>`, and the original error is the
33
+ `cause` in both cases.
34
+ - **An error node says when its own fields are missing.** When an error's own properties could not be
35
+ read (a Proxy whose `ownKeys` throws, a getter that throws), none was copied and nothing said so. The
36
+ node now carries `_errorFieldsIncomplete: true`.
37
+ - **A broken `@opentelemetry/api` install is reported once.** Every failure to load it was folded into
38
+ "not installed", so correlation could be off with no sign. A missing module stays silent, as
39
+ designed; one that is installed but throws while loading, or exports no usable `trace` namespace, writes one
40
+ `LOGGER_OTEL_API_BROKEN` line to `stderr`.
41
+
42
+ #### Apply to a derived backend
43
+
44
+ Nothing to change in code. What can differ at run time:
45
+
46
+ - `stderr` can carry two lines it never carried: `HTTP_UNEXPECTED_ERROR_DROPPED` and
47
+ `LOGGER_OTEL_API_BROKEN`, both NDJSON like the destination-failure lines. Add them to whatever
48
+ alerts on the library's `stderr` codes. `RESERVED_LOG_KEYS` gains these two keys, so an application
49
+ event must not reuse them.
50
+ - A host that already logs an event under `HTTP_UNEXPECTED_ERROR_DROPPED` or `LOGGER_OTEL_API_BROKEN`
51
+ sees no change in that entry: nothing is renamed, rejected or dropped, and its `event.name` is
52
+ derived from the key as for any other (`http.unexpected.error.dropped`, `logger.otel.api.broken`).
53
+ What changes is that, where stdout and stderr reach the same place, an alert or filter on either
54
+ key now matches the library's `stderr` line and the host's own entries alike. Rename the host event.
55
+ - `LOGGER_DESTINATION_INIT_FAILED`, `LOGGER_DESTINATION_WRITE_FAILED` and the hook-failure line now
56
+ appear for failures that were silent before. A deployment that saw none was either healthy or
57
+ losing entries without knowing.
58
+ - Code that matches the text "pino-pretty is not installed" on a `PrettyDevDestination` init error now
59
+ matches only a genuine resolution failure; match `failed to start` for the rest, or read `cause`.
60
+ - Log processing that reads error nodes can meet `_errorFieldsIncomplete: true`, on an error whose own
61
+ fields could not be read.
62
+
63
+ ### Tests
64
+
65
+ - A failure whose cause cannot be read, a dropped unexpected-error report, a `pino-pretty` failure of
66
+ each kind, an error whose own fields cannot be enumerated and a broken `@opentelemetry/api` each have
67
+ a failing-first spec. The fixtures that simulated a missing `pino-pretty` or `@opentelemetry/api` now
68
+ carry the resolution code Node attaches to the real error, because the code is what tells an absent
69
+ module from a broken one.
70
+
14
71
  ## [1.4.5] - 2026-11-01
15
72
 
16
73
  ### Documentation
@@ -2219,7 +2276,8 @@ published `dist/` is identical — no runtime behaviour changes for consumers.
2219
2276
  - Professional CI suite: `ci.yml`, `bench.yml`, `codeql.yml`, `scorecard.yml`,
2220
2277
  `release.yml`, Dependabot, and issue templates
2221
2278
 
2222
- [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.4.5...HEAD
2279
+ [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.4.6...HEAD
2280
+ [1.4.6]: https://github.com/bymaxone/nest-logger/compare/v1.4.5...v1.4.6
2223
2281
  [1.4.5]: https://github.com/bymaxone/nest-logger/compare/v1.4.4...v1.4.5
2224
2282
  [1.4.4]: https://github.com/bymaxone/nest-logger/compare/v1.4.3...v1.4.4
2225
2283
  [1.4.3]: https://github.com/bymaxone/nest-logger/compare/v1.4.2...v1.4.3
package/README.md CHANGED
@@ -179,7 +179,7 @@ pnpm add @opentelemetry/api @opentelemetry/sdk-node
179
179
  > packaging.
180
180
 
181
181
  > [!NOTE]
182
- > `@opentelemetry/api` is resolved lazily when the Pino instance is built. When it is absent the trace mixin silently steps aside — the logger never fails to start, and never warns, over an optional peer.
182
+ > `@opentelemetry/api` is resolved lazily when the Pino instance is built. When it is absent the trace mixin silently steps aside — the logger never fails to start, and never warns, over an optional peer. A copy that is installed but broken is different: it is reported once on `stderr` as `LOGGER_OTEL_API_BROKEN`, because correlation would otherwise be off with no sign.
183
183
 
184
184
  > [!NOTE]
185
185
  > The published declarations depend on no HTTP framework's types. The HTTP interceptor, the exception filter and the request-id middleware are typed by structural contracts (`LoggableRequest`, `LoggableResponse`, `NextHandler`) that an Express request and response satisfy as-is, so nothing extra is needed even when you compile with `skipLibCheck: false`. The emitted `.d.ts` imports only `@nestjs/common`, `pino` and `rxjs`.
@@ -727,6 +727,8 @@ any other serializer output.
727
727
  An error's own enumerable properties (`code`, `statusCode`, domain fields) are carried through, as
728
728
  Pino's standard serializer did.
729
729
 
730
+ When those properties cannot be read (a Proxy whose `ownKeys` throws, or a getter that throws), none of them is copied and the error node carries `_errorFieldsIncomplete: true`, so an entry without its `code` is never mistaken for a complete one.
731
+
730
732
  ### 7. Context propagation with `LogContextService`
731
733
 
732
734
  ```typescript
@@ -843,7 +845,7 @@ function assertValidLogKey(key: string) {
843
845
 
844
846
  The following keys are used internally by the library — do not reuse them in application code:
845
847
 
846
- `LOGGER_BOOTSTRAP_OK` · `LOGGER_BOOTSTRAP_WARNING` · `LOGGER_SHUTDOWN_OK` · `HTTP_REQUEST_START` · `HTTP_REQUEST_SUCCESS` · `HTTP_REQUEST_REDIRECT` · `HTTP_REQUEST_CLIENT_ERROR` · `HTTP_REQUEST_SERVER_ERROR` · `HTTP_REQUEST_ABORTED` · `HTTP_REQUEST_COMPLETED` · `HTTP_EXCEPTION_HANDLED` · `HTTP_EXCEPTION_UNHANDLED` · `HTTP_UNEXPECTED_ERROR` · `METHOD_EXECUTION` · `METHOD_SLOW_EXECUTION` · `LOGGER_DESTINATION_INIT_FAILED` · `LOGGER_DESTINATION_WRITE_FAILED` · `LOGGER_ENTRY_TRUNCATED` · `LOGGER_REDACTION_FAILED`
848
+ `LOGGER_BOOTSTRAP_OK` · `LOGGER_BOOTSTRAP_WARNING` · `LOGGER_SHUTDOWN_OK` · `HTTP_REQUEST_START` · `HTTP_REQUEST_SUCCESS` · `HTTP_REQUEST_REDIRECT` · `HTTP_REQUEST_CLIENT_ERROR` · `HTTP_REQUEST_SERVER_ERROR` · `HTTP_REQUEST_ABORTED` · `HTTP_REQUEST_COMPLETED` · `HTTP_EXCEPTION_HANDLED` · `HTTP_EXCEPTION_UNHANDLED` · `HTTP_UNEXPECTED_ERROR` · `HTTP_UNEXPECTED_ERROR_DROPPED` · `METHOD_EXECUTION` · `METHOD_SLOW_EXECUTION` · `LOGGER_DESTINATION_INIT_FAILED` · `LOGGER_DESTINATION_WRITE_FAILED` · `LOGGER_ENTRY_TRUNCATED` · `LOGGER_REDACTION_FAILED` · `LOGGER_OTEL_API_BROKEN`
847
849
 
848
850
  All reserved keys are exported as the `RESERVED_LOG_KEYS` constant from `@bymax-one/nest-logger/shared`.
849
851
 
@@ -1579,22 +1581,25 @@ Two kinds of failure, and they surface differently. A **thrown `Error`** carries
1579
1581
  | `[BymaxLoggerModule] options.` | `forRoot` / `forRootAsync`, at module setup | any option fails validation: a missing `service`, a `level` outside the set, a bad type | Fix the option the message names; it prints the path and what it received |
1580
1582
  | `[BymaxLoggerModule] useNestLogger(app) called but` | `BymaxLoggerModule.useNestLogger` | the module was never imported into the application | Import `BymaxLoggerModule` before calling it |
1581
1583
  | `[BymaxLoggerModule] applyAccessLog(app) called but` | `applyAccessLog` | the module was never imported into the application | Import `BymaxLoggerModule` before calling it |
1582
- | `[PrettyDevDestination] pino-pretty is not installed` | `PrettyDevDestination.onInit` | the destination is registered and the optional peer is missing | Install `pino-pretty` or drop the destination |
1584
+ | `[PrettyDevDestination] pino-pretty is not installed` | `PrettyDevDestination.onInit` | the destination is registered and resolving `pino-pretty` itself fails | Install `pino-pretty` or drop the destination |
1585
+ | `[PrettyDevDestination] pino-pretty failed to start` | `PrettyDevDestination.onInit` | `pino-pretty` is found but importing it or building the transform throws | Read the message and the error's `cause`: it is the real failure |
1583
1586
  | `[PrettyDevDestination] refused in production` | `PrettyDevDestination.onInit` | `NODE_ENV` is exactly `production` | Use `DefaultStdoutDestination` in production |
1584
1587
  | `[LogContextService] set() called outside run() scope` | `LogContextService.set` | called with no active `run()` | Wrap the work in `logContext.run({ ... }, () => ...)` |
1585
1588
  | `[LogContextService] Refusing to set unsafe context key` | `LogContextService.set` | the key is `__proto__`, `constructor` or `prototype` | Use an ordinary key |
1586
1589
 
1587
- The two `PrettyDevDestination` errors are thrown inside `onInit`, which the registry contains: the boot continues and the failure is reported as `LOGGER_DESTINATION_INIT_FAILED` below.
1590
+ The `PrettyDevDestination` errors are thrown inside `onInit`, which the registry contains: the boot continues and the failure is reported as `LOGGER_DESTINATION_INIT_FAILED` below.
1588
1591
 
1589
1592
  ### Log keys
1590
1593
 
1591
- | Code | Surfaces as | When | Action |
1592
- | --------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
1593
- | `LOGGER_DESTINATION_INIT_FAILED` | NDJSON line on `stderr` | `destination.onInit()` throws or rejects | Sink is removed from the write fan-out and shutdown; boot continues |
1594
- | `LOGGER_DESTINATION_WRITE_FAILED` | NDJSON line on `stderr` | `destination.write()` throws or rejects | Entry dropped for that destination; others continue |
1595
- | `LOGGER_BOOTSTRAP_WARNING` | log entry with `reason: 'OTEL_API_UNAVAILABLE'` | `otel.shouldAutoInjectTraceContext` is on and `@opentelemetry/api` cannot be resolved | Install `@opentelemetry/api`, or turn the option off; until then `traceId` and `spanId` are absent |
1596
- | `LOGGER_ENTRY_TRUNCATED` | `_logKey` in the envelope | a serialized field exceeds `maxEntrySizeBytes` | Reduce the payload or raise the ceiling |
1597
- | `LOGGER_REDACTION_FAILED` | `_logKey` in the envelope, with `_redactionFailed: true` | a record cannot be walked by the redactor (a throwing getter, a hostile proxy) | The record is dropped whole, never partly emitted; the message and ambient context stay. Find the value that broke the walk |
1594
+ | Code | Surfaces as | When | Action |
1595
+ | --------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
1596
+ | `LOGGER_DESTINATION_INIT_FAILED` | NDJSON line on `stderr` | `destination.onInit()` throws or rejects | Sink is removed from the write fan-out and shutdown; boot continues |
1597
+ | `LOGGER_DESTINATION_WRITE_FAILED` | NDJSON line on `stderr` | `destination.write()` throws or rejects | Entry dropped for that destination; others continue |
1598
+ | `HTTP_UNEXPECTED_ERROR_DROPPED` | NDJSON line on `stderr` | `PinoUnexpectedErrorSink` could not log a report (the logger threw, or the report could not be read) | The report is dropped; the line names why. The response is unaffected |
1599
+ | `LOGGER_OTEL_API_BROKEN` | NDJSON line on `stderr`, once | `@opentelemetry/api` is installed but throws while loading, or exports no usable `trace` namespace | Reinstall it, or turn `otel.shouldAutoInjectTraceContext` off; until then `traceId` and `spanId` are absent |
1600
+ | `LOGGER_BOOTSTRAP_WARNING` | log entry with `reason: 'OTEL_API_UNAVAILABLE'` | `otel.shouldAutoInjectTraceContext` is on and `@opentelemetry/api` cannot be resolved | Install `@opentelemetry/api`, or turn the option off; until then `traceId` and `spanId` are absent |
1601
+ | `LOGGER_ENTRY_TRUNCATED` | `_logKey` in the envelope | a serialized field exceeds `maxEntrySizeBytes` | Reduce the payload or raise the ceiling |
1602
+ | `LOGGER_REDACTION_FAILED` | `_logKey` in the envelope, with `_redactionFailed: true` | a record cannot be walked by the redactor (a throwing getter, a hostile proxy) | The record is dropped whole, never partly emitted; the message and ambient context stay. Find the value that broke the walk |
1598
1603
 
1599
1604
  ---
1600
1605
 
@@ -325,12 +325,14 @@ var RESERVED_LOG_KEYS = Object.freeze({
325
325
  HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
326
326
  HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
327
327
  HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR",
328
+ HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED",
328
329
  METHOD_EXECUTION: "METHOD_EXECUTION",
329
330
  METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
330
331
  LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
331
332
  LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
332
333
  LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
333
- LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
334
+ LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED",
335
+ LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN"
334
336
  });
335
337
  var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
336
338
  /**
@@ -429,6 +431,7 @@ function assignOwnErrorFields(target, source) {
429
431
  }
430
432
  }
431
433
  } catch {
434
+ Reflect.defineProperty(target, "_errorFieldsIncomplete", { value: true, enumerable: true });
432
435
  }
433
436
  }
434
437
  function toSanitizedChild(value, seen, depth2, maxDepth) {
@@ -1210,17 +1213,114 @@ var DEFAULT_REDACT_PATHS = [
1210
1213
  ...REDACT_COMMON_FIELDS.flatMap((field) => depth(field)),
1211
1214
  ...REDACT_ABSOLUTE_PATHS
1212
1215
  ];
1216
+
1217
+ // src/server/utils/report-destination-failure.util.ts
1218
+ function reportDestinationFailure(logKey, name, cause, msg) {
1219
+ writeStderrSafely(
1220
+ JSON.stringify({
1221
+ level: "error",
1222
+ logKey,
1223
+ destination: toSingleLineMessage(name),
1224
+ err: describeCause(cause),
1225
+ msg: toSingleLineMessage(msg)
1226
+ }) + "\n"
1227
+ );
1228
+ }
1229
+ var UNREADABLE_CAUSE = { type: "UnknownError", message: "unreadable value" };
1230
+ function describeCause(cause) {
1231
+ try {
1232
+ return cause instanceof Error ? {
1233
+ type: toSingleLineMessage(String(cause.name)),
1234
+ message: toSingleLineMessage(String(cause.message))
1235
+ } : { type: "UnknownError", message: toSingleLineMessage(String(cause)) };
1236
+ } catch {
1237
+ return UNREADABLE_CAUSE;
1238
+ }
1239
+ }
1240
+ function safeDestinationName(destination) {
1241
+ try {
1242
+ return String(destination.name);
1243
+ } catch {
1244
+ return "unknown";
1245
+ }
1246
+ }
1247
+ function isLogLevel(value) {
1248
+ return LOG_LEVEL_PRIORITY.includes(value);
1249
+ }
1250
+ var resolvedMinLevels = /* @__PURE__ */ new WeakMap();
1251
+ function safeMinLevel(destination) {
1252
+ if (resolvedMinLevels.has(destination)) {
1253
+ return resolvedMinLevels.get(destination);
1254
+ }
1255
+ let resolved;
1256
+ try {
1257
+ const read = destination.minLevel;
1258
+ resolved = isLogLevel(read) ? read : void 0;
1259
+ } catch {
1260
+ }
1261
+ resolvedMinLevels.set(destination, resolved);
1262
+ return resolved;
1263
+ }
1264
+
1265
+ // src/server/utils/otel-detector.ts
1266
+ var brokenInstallWarned = false;
1267
+ function isOtelApiMissing(cause) {
1268
+ try {
1269
+ const { code, message } = cause;
1270
+ return code === "MODULE_NOT_FOUND" && /^Cannot find module '@opentelemetry\/api'/.test(String(message));
1271
+ } catch {
1272
+ return false;
1273
+ }
1274
+ }
1213
1275
  function loadTraceApiFrom(anchor) {
1276
+ let from;
1214
1277
  try {
1215
- const requireFrom = module$1.createRequire(anchor());
1216
- const mod = requireFrom("@opentelemetry/api");
1217
- return mod.trace;
1278
+ from = anchor();
1218
1279
  } catch {
1219
- return void 0;
1280
+ return { api: void 0 };
1281
+ }
1282
+ try {
1283
+ const mod = module$1.createRequire(from)("@opentelemetry/api");
1284
+ const trace = typeof mod === "object" && mod !== null || typeof mod === "function" ? mod.trace : void 0;
1285
+ if (typeof trace?.getActiveSpan !== "function") {
1286
+ throw new TypeError("@opentelemetry/api resolved but exports no usable `trace` namespace");
1287
+ }
1288
+ return { api: trace };
1289
+ } catch (cause) {
1290
+ return isOtelApiMissing(cause) ? { api: void 0 } : { api: void 0, broken: { cause } };
1220
1291
  }
1221
1292
  }
1222
- function detectOtelTraceApi() {
1223
- return loadTraceApiFrom(() => __filename) ?? loadTraceApiFrom(() => path.join(process.cwd(), "noop.cjs"));
1293
+ function warnBrokenInstallOnce(cause) {
1294
+ if (brokenInstallWarned) {
1295
+ return;
1296
+ }
1297
+ brokenInstallWarned = true;
1298
+ writeStderrSafely(
1299
+ JSON.stringify({
1300
+ level: "warn",
1301
+ logKey: RESERVED_LOG_KEYS.LOGGER_OTEL_API_BROKEN,
1302
+ msg: "@opentelemetry/api is installed but could not be loaded, so traceId and spanId are absent from every entry. Reinstall it, or set otel.shouldAutoInjectTraceContext to false.",
1303
+ err: describeCause(cause)
1304
+ }) + "\n"
1305
+ );
1306
+ }
1307
+ var DEFAULT_ANCHORS = [
1308
+ () => __filename,
1309
+ () => path.join(process.cwd(), "noop.cjs")
1310
+ ];
1311
+ function detectOtelTraceApi(anchors = DEFAULT_ANCHORS) {
1312
+ let broken;
1313
+ for (const anchor of anchors) {
1314
+ const attempt = loadTraceApiFrom(anchor);
1315
+ if (attempt.api !== void 0) {
1316
+ return attempt.api;
1317
+ }
1318
+ broken ??= attempt.broken;
1319
+ }
1320
+ if (broken !== void 0) {
1321
+ warnBrokenInstallOnce(broken.cause);
1322
+ }
1323
+ return void 0;
1224
1324
  }
1225
1325
  function isValidTraceId(traceId) {
1226
1326
  return /^[0-9a-f]{32}$/.test(traceId) && !/^0+$/.test(traceId);
@@ -1239,17 +1339,21 @@ function createTraceContextMixin(logContext, opts) {
1239
1339
  Object.assign(merged, store);
1240
1340
  }
1241
1341
  if (traceApi) {
1242
- const span = traceApi.getActiveSpan();
1243
- if (span) {
1244
- const ctx = span.spanContext();
1245
- if (isValidTraceId(ctx.traceId) && isValidSpanId(ctx.spanId)) {
1246
- Reflect.set(merged, opts.traceIdField, ctx.traceId);
1247
- Reflect.set(merged, opts.spanIdField, ctx.spanId);
1248
- if (typeof ctx.traceFlags === "number") {
1249
- const flagsByte = ctx.traceFlags & 255;
1250
- Reflect.set(merged, opts.traceFlagsField, flagsByte.toString(16).padStart(2, "0"));
1342
+ try {
1343
+ const span = traceApi.getActiveSpan();
1344
+ if (span) {
1345
+ const { traceId, spanId, traceFlags } = span.spanContext();
1346
+ if (isValidTraceId(traceId) && isValidSpanId(spanId)) {
1347
+ const flags = typeof traceFlags === "number" ? (traceFlags & 255).toString(16).padStart(2, "0") : void 0;
1348
+ Reflect.set(merged, opts.traceIdField, traceId);
1349
+ Reflect.set(merged, opts.spanIdField, spanId);
1350
+ if (flags !== void 0) {
1351
+ Reflect.set(merged, opts.traceFlagsField, flags);
1352
+ }
1251
1353
  }
1252
1354
  }
1355
+ } catch (cause) {
1356
+ warnBrokenInstallOnce(cause);
1253
1357
  }
1254
1358
  }
1255
1359
  return merged;
@@ -1261,52 +1365,6 @@ function compileRedactPaths(extraPaths, shouldSkipDefaults) {
1261
1365
  const sources = shouldSkipDefaults ? [extraPaths] : [DEFAULT_REDACT_PATHS, extraPaths];
1262
1366
  return Array.from(new Set(sources.flat()));
1263
1367
  }
1264
-
1265
- // src/server/utils/report-destination-failure.util.ts
1266
- function reportDestinationFailure(logKey, name, cause, msg) {
1267
- try {
1268
- const err = cause instanceof Error ? {
1269
- type: toSingleLineMessage(String(cause.name)),
1270
- message: toSingleLineMessage(String(cause.message))
1271
- } : { type: "UnknownError", message: toSingleLineMessage(String(cause)) };
1272
- writeStderrSafely(
1273
- JSON.stringify({
1274
- level: "error",
1275
- logKey,
1276
- destination: toSingleLineMessage(name),
1277
- err,
1278
- msg: toSingleLineMessage(msg)
1279
- }) + "\n"
1280
- );
1281
- } catch {
1282
- }
1283
- }
1284
- function safeDestinationName(destination) {
1285
- try {
1286
- return String(destination.name);
1287
- } catch {
1288
- return "unknown";
1289
- }
1290
- }
1291
- function isLogLevel(value) {
1292
- return LOG_LEVEL_PRIORITY.includes(value);
1293
- }
1294
- var resolvedMinLevels = /* @__PURE__ */ new WeakMap();
1295
- function safeMinLevel(destination) {
1296
- if (resolvedMinLevels.has(destination)) {
1297
- return resolvedMinLevels.get(destination);
1298
- }
1299
- let resolved;
1300
- try {
1301
- const read = destination.minLevel;
1302
- resolved = isLogLevel(read) ? read : void 0;
1303
- } catch {
1304
- }
1305
- resolvedMinLevels.set(destination, resolved);
1306
- return resolved;
1307
- }
1308
-
1309
- // src/server/utils/destination-to-stream.ts
1310
1368
  function reportWriteFailure(destination, cause) {
1311
1369
  const name = safeDestinationName(destination);
1312
1370
  reportDestinationFailure(
@@ -2562,6 +2620,22 @@ var MAX_BUFFERED_BYTES = 4 * 1024 * 1024;
2562
2620
  function writeRawToStdout(payload) {
2563
2621
  writeStdoutSafely(payload);
2564
2622
  }
2623
+ var RESOLUTION_FAILURE_CODES = ["MODULE_NOT_FOUND", "ERR_MODULE_NOT_FOUND"];
2624
+ function isPinoPrettyMissing(cause) {
2625
+ try {
2626
+ const { code, message } = cause;
2627
+ return RESOLUTION_FAILURE_CODES.includes(code) && /^Cannot find (?:module|package) 'pino-pretty'/.test(String(message));
2628
+ } catch {
2629
+ return false;
2630
+ }
2631
+ }
2632
+ function describeFailure(cause) {
2633
+ try {
2634
+ return toSingleLineMessage(cause instanceof Error ? cause.message : String(cause));
2635
+ } catch {
2636
+ return "unreadable value";
2637
+ }
2638
+ }
2565
2639
  var PrettyDevDestination = class {
2566
2640
  /**
2567
2641
  * @param opts.minLevel — Optional minimum level filter applied by the
@@ -2634,10 +2708,11 @@ var PrettyDevDestination = class {
2634
2708
  // and the last-resort rescue.
2635
2709
  destination: process.stdout
2636
2710
  });
2637
- } catch {
2711
+ } catch (cause) {
2638
2712
  this.initFailed = true;
2639
2713
  throw new Error(
2640
- "[PrettyDevDestination] pino-pretty is not installed. Install it as a peer dependency (`pnpm add -D pino-pretty`) or remove PrettyDevDestination from `destinations`."
2714
+ isPinoPrettyMissing(cause) ? "[PrettyDevDestination] pino-pretty is not installed. Install it as a peer dependency (`pnpm add -D pino-pretty`) or remove PrettyDevDestination from `destinations`." : `[PrettyDevDestination] pino-pretty failed to start: ${describeFailure(cause)}`,
2715
+ { cause }
2641
2716
  );
2642
2717
  }
2643
2718
  this.flushBuffer((payload) => {
@@ -3102,7 +3177,13 @@ exports.PinoUnexpectedErrorSink = class PinoUnexpectedErrorSink {
3102
3177
  void 0,
3103
3178
  metadata
3104
3179
  );
3105
- } catch {
3180
+ } catch (cause) {
3181
+ reportDestinationFailure(
3182
+ RESERVED_LOG_KEYS.HTTP_UNEXPECTED_ERROR_DROPPED,
3183
+ "PinoUnexpectedErrorSink",
3184
+ cause,
3185
+ "An unexpected-error report could not be logged and was dropped."
3186
+ );
3106
3187
  }
3107
3188
  }
3108
3189
  };
@@ -585,12 +585,14 @@ declare const RESERVED_LOG_KEYS: Readonly<{
585
585
  readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
586
586
  readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
587
587
  readonly HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR";
588
+ readonly HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED";
588
589
  readonly METHOD_EXECUTION: "METHOD_EXECUTION";
589
590
  readonly METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION";
590
591
  readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
591
592
  readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
592
593
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
593
594
  readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
595
+ readonly LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN";
594
596
  }>;
595
597
  /**
596
598
  * Keys that are reserved but intentionally never emitted, each with the reason.
@@ -585,12 +585,14 @@ declare const RESERVED_LOG_KEYS: Readonly<{
585
585
  readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
586
586
  readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
587
587
  readonly HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR";
588
+ readonly HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED";
588
589
  readonly METHOD_EXECUTION: "METHOD_EXECUTION";
589
590
  readonly METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION";
590
591
  readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
591
592
  readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
592
593
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
593
594
  readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
595
+ readonly LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN";
594
596
  }>;
595
597
  /**
596
598
  * Keys that are reserved but intentionally never emitted, each with the reason.
@@ -322,12 +322,14 @@ var RESERVED_LOG_KEYS = Object.freeze({
322
322
  HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
323
323
  HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
324
324
  HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR",
325
+ HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED",
325
326
  METHOD_EXECUTION: "METHOD_EXECUTION",
326
327
  METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
327
328
  LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
328
329
  LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
329
330
  LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
330
- LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
331
+ LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED",
332
+ LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN"
331
333
  });
332
334
  var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
333
335
  /**
@@ -426,6 +428,7 @@ function assignOwnErrorFields(target, source) {
426
428
  }
427
429
  }
428
430
  } catch {
431
+ Reflect.defineProperty(target, "_errorFieldsIncomplete", { value: true, enumerable: true });
429
432
  }
430
433
  }
431
434
  function toSanitizedChild(value, seen, depth2, maxDepth) {
@@ -1207,17 +1210,114 @@ var DEFAULT_REDACT_PATHS = [
1207
1210
  ...REDACT_COMMON_FIELDS.flatMap((field) => depth(field)),
1208
1211
  ...REDACT_ABSOLUTE_PATHS
1209
1212
  ];
1213
+
1214
+ // src/server/utils/report-destination-failure.util.ts
1215
+ function reportDestinationFailure(logKey, name, cause, msg) {
1216
+ writeStderrSafely(
1217
+ JSON.stringify({
1218
+ level: "error",
1219
+ logKey,
1220
+ destination: toSingleLineMessage(name),
1221
+ err: describeCause(cause),
1222
+ msg: toSingleLineMessage(msg)
1223
+ }) + "\n"
1224
+ );
1225
+ }
1226
+ var UNREADABLE_CAUSE = { type: "UnknownError", message: "unreadable value" };
1227
+ function describeCause(cause) {
1228
+ try {
1229
+ return cause instanceof Error ? {
1230
+ type: toSingleLineMessage(String(cause.name)),
1231
+ message: toSingleLineMessage(String(cause.message))
1232
+ } : { type: "UnknownError", message: toSingleLineMessage(String(cause)) };
1233
+ } catch {
1234
+ return UNREADABLE_CAUSE;
1235
+ }
1236
+ }
1237
+ function safeDestinationName(destination) {
1238
+ try {
1239
+ return String(destination.name);
1240
+ } catch {
1241
+ return "unknown";
1242
+ }
1243
+ }
1244
+ function isLogLevel(value) {
1245
+ return LOG_LEVEL_PRIORITY.includes(value);
1246
+ }
1247
+ var resolvedMinLevels = /* @__PURE__ */ new WeakMap();
1248
+ function safeMinLevel(destination) {
1249
+ if (resolvedMinLevels.has(destination)) {
1250
+ return resolvedMinLevels.get(destination);
1251
+ }
1252
+ let resolved;
1253
+ try {
1254
+ const read = destination.minLevel;
1255
+ resolved = isLogLevel(read) ? read : void 0;
1256
+ } catch {
1257
+ }
1258
+ resolvedMinLevels.set(destination, resolved);
1259
+ return resolved;
1260
+ }
1261
+
1262
+ // src/server/utils/otel-detector.ts
1263
+ var brokenInstallWarned = false;
1264
+ function isOtelApiMissing(cause) {
1265
+ try {
1266
+ const { code, message } = cause;
1267
+ return code === "MODULE_NOT_FOUND" && /^Cannot find module '@opentelemetry\/api'/.test(String(message));
1268
+ } catch {
1269
+ return false;
1270
+ }
1271
+ }
1210
1272
  function loadTraceApiFrom(anchor) {
1273
+ let from;
1211
1274
  try {
1212
- const requireFrom = createRequire(anchor());
1213
- const mod = requireFrom("@opentelemetry/api");
1214
- return mod.trace;
1275
+ from = anchor();
1215
1276
  } catch {
1216
- return void 0;
1277
+ return { api: void 0 };
1278
+ }
1279
+ try {
1280
+ const mod = createRequire(from)("@opentelemetry/api");
1281
+ const trace = typeof mod === "object" && mod !== null || typeof mod === "function" ? mod.trace : void 0;
1282
+ if (typeof trace?.getActiveSpan !== "function") {
1283
+ throw new TypeError("@opentelemetry/api resolved but exports no usable `trace` namespace");
1284
+ }
1285
+ return { api: trace };
1286
+ } catch (cause) {
1287
+ return isOtelApiMissing(cause) ? { api: void 0 } : { api: void 0, broken: { cause } };
1217
1288
  }
1218
1289
  }
1219
- function detectOtelTraceApi() {
1220
- return loadTraceApiFrom(() => __filename$1) ?? loadTraceApiFrom(() => join(process.cwd(), "noop.cjs"));
1290
+ function warnBrokenInstallOnce(cause) {
1291
+ if (brokenInstallWarned) {
1292
+ return;
1293
+ }
1294
+ brokenInstallWarned = true;
1295
+ writeStderrSafely(
1296
+ JSON.stringify({
1297
+ level: "warn",
1298
+ logKey: RESERVED_LOG_KEYS.LOGGER_OTEL_API_BROKEN,
1299
+ msg: "@opentelemetry/api is installed but could not be loaded, so traceId and spanId are absent from every entry. Reinstall it, or set otel.shouldAutoInjectTraceContext to false.",
1300
+ err: describeCause(cause)
1301
+ }) + "\n"
1302
+ );
1303
+ }
1304
+ var DEFAULT_ANCHORS = [
1305
+ () => __filename$1,
1306
+ () => join(process.cwd(), "noop.cjs")
1307
+ ];
1308
+ function detectOtelTraceApi(anchors = DEFAULT_ANCHORS) {
1309
+ let broken;
1310
+ for (const anchor of anchors) {
1311
+ const attempt = loadTraceApiFrom(anchor);
1312
+ if (attempt.api !== void 0) {
1313
+ return attempt.api;
1314
+ }
1315
+ broken ??= attempt.broken;
1316
+ }
1317
+ if (broken !== void 0) {
1318
+ warnBrokenInstallOnce(broken.cause);
1319
+ }
1320
+ return void 0;
1221
1321
  }
1222
1322
  function isValidTraceId(traceId) {
1223
1323
  return /^[0-9a-f]{32}$/.test(traceId) && !/^0+$/.test(traceId);
@@ -1236,17 +1336,21 @@ function createTraceContextMixin(logContext, opts) {
1236
1336
  Object.assign(merged, store);
1237
1337
  }
1238
1338
  if (traceApi) {
1239
- const span = traceApi.getActiveSpan();
1240
- if (span) {
1241
- const ctx = span.spanContext();
1242
- if (isValidTraceId(ctx.traceId) && isValidSpanId(ctx.spanId)) {
1243
- Reflect.set(merged, opts.traceIdField, ctx.traceId);
1244
- Reflect.set(merged, opts.spanIdField, ctx.spanId);
1245
- if (typeof ctx.traceFlags === "number") {
1246
- const flagsByte = ctx.traceFlags & 255;
1247
- Reflect.set(merged, opts.traceFlagsField, flagsByte.toString(16).padStart(2, "0"));
1339
+ try {
1340
+ const span = traceApi.getActiveSpan();
1341
+ if (span) {
1342
+ const { traceId, spanId, traceFlags } = span.spanContext();
1343
+ if (isValidTraceId(traceId) && isValidSpanId(spanId)) {
1344
+ const flags = typeof traceFlags === "number" ? (traceFlags & 255).toString(16).padStart(2, "0") : void 0;
1345
+ Reflect.set(merged, opts.traceIdField, traceId);
1346
+ Reflect.set(merged, opts.spanIdField, spanId);
1347
+ if (flags !== void 0) {
1348
+ Reflect.set(merged, opts.traceFlagsField, flags);
1349
+ }
1248
1350
  }
1249
1351
  }
1352
+ } catch (cause) {
1353
+ warnBrokenInstallOnce(cause);
1250
1354
  }
1251
1355
  }
1252
1356
  return merged;
@@ -1258,52 +1362,6 @@ function compileRedactPaths(extraPaths, shouldSkipDefaults) {
1258
1362
  const sources = shouldSkipDefaults ? [extraPaths] : [DEFAULT_REDACT_PATHS, extraPaths];
1259
1363
  return Array.from(new Set(sources.flat()));
1260
1364
  }
1261
-
1262
- // src/server/utils/report-destination-failure.util.ts
1263
- function reportDestinationFailure(logKey, name, cause, msg) {
1264
- try {
1265
- const err = cause instanceof Error ? {
1266
- type: toSingleLineMessage(String(cause.name)),
1267
- message: toSingleLineMessage(String(cause.message))
1268
- } : { type: "UnknownError", message: toSingleLineMessage(String(cause)) };
1269
- writeStderrSafely(
1270
- JSON.stringify({
1271
- level: "error",
1272
- logKey,
1273
- destination: toSingleLineMessage(name),
1274
- err,
1275
- msg: toSingleLineMessage(msg)
1276
- }) + "\n"
1277
- );
1278
- } catch {
1279
- }
1280
- }
1281
- function safeDestinationName(destination) {
1282
- try {
1283
- return String(destination.name);
1284
- } catch {
1285
- return "unknown";
1286
- }
1287
- }
1288
- function isLogLevel(value) {
1289
- return LOG_LEVEL_PRIORITY.includes(value);
1290
- }
1291
- var resolvedMinLevels = /* @__PURE__ */ new WeakMap();
1292
- function safeMinLevel(destination) {
1293
- if (resolvedMinLevels.has(destination)) {
1294
- return resolvedMinLevels.get(destination);
1295
- }
1296
- let resolved;
1297
- try {
1298
- const read = destination.minLevel;
1299
- resolved = isLogLevel(read) ? read : void 0;
1300
- } catch {
1301
- }
1302
- resolvedMinLevels.set(destination, resolved);
1303
- return resolved;
1304
- }
1305
-
1306
- // src/server/utils/destination-to-stream.ts
1307
1365
  function reportWriteFailure(destination, cause) {
1308
1366
  const name = safeDestinationName(destination);
1309
1367
  reportDestinationFailure(
@@ -2559,6 +2617,22 @@ var MAX_BUFFERED_BYTES = 4 * 1024 * 1024;
2559
2617
  function writeRawToStdout(payload) {
2560
2618
  writeStdoutSafely(payload);
2561
2619
  }
2620
+ var RESOLUTION_FAILURE_CODES = ["MODULE_NOT_FOUND", "ERR_MODULE_NOT_FOUND"];
2621
+ function isPinoPrettyMissing(cause) {
2622
+ try {
2623
+ const { code, message } = cause;
2624
+ return RESOLUTION_FAILURE_CODES.includes(code) && /^Cannot find (?:module|package) 'pino-pretty'/.test(String(message));
2625
+ } catch {
2626
+ return false;
2627
+ }
2628
+ }
2629
+ function describeFailure(cause) {
2630
+ try {
2631
+ return toSingleLineMessage(cause instanceof Error ? cause.message : String(cause));
2632
+ } catch {
2633
+ return "unreadable value";
2634
+ }
2635
+ }
2562
2636
  var PrettyDevDestination = class {
2563
2637
  /**
2564
2638
  * @param opts.minLevel — Optional minimum level filter applied by the
@@ -2631,10 +2705,11 @@ var PrettyDevDestination = class {
2631
2705
  // and the last-resort rescue.
2632
2706
  destination: process.stdout
2633
2707
  });
2634
- } catch {
2708
+ } catch (cause) {
2635
2709
  this.initFailed = true;
2636
2710
  throw new Error(
2637
- "[PrettyDevDestination] pino-pretty is not installed. Install it as a peer dependency (`pnpm add -D pino-pretty`) or remove PrettyDevDestination from `destinations`."
2711
+ isPinoPrettyMissing(cause) ? "[PrettyDevDestination] pino-pretty is not installed. Install it as a peer dependency (`pnpm add -D pino-pretty`) or remove PrettyDevDestination from `destinations`." : `[PrettyDevDestination] pino-pretty failed to start: ${describeFailure(cause)}`,
2712
+ { cause }
2638
2713
  );
2639
2714
  }
2640
2715
  this.flushBuffer((payload) => {
@@ -3099,7 +3174,13 @@ var PinoUnexpectedErrorSink = class {
3099
3174
  void 0,
3100
3175
  metadata
3101
3176
  );
3102
- } catch {
3177
+ } catch (cause) {
3178
+ reportDestinationFailure(
3179
+ RESERVED_LOG_KEYS.HTTP_UNEXPECTED_ERROR_DROPPED,
3180
+ "PinoUnexpectedErrorSink",
3181
+ cause,
3182
+ "An unexpected-error report could not be logged and was dropped."
3183
+ );
3103
3184
  }
3104
3185
  }
3105
3186
  };
@@ -18,12 +18,14 @@ var RESERVED_LOG_KEYS = Object.freeze({
18
18
  HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
19
19
  HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
20
20
  HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR",
21
+ HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED",
21
22
  METHOD_EXECUTION: "METHOD_EXECUTION",
22
23
  METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION",
23
24
  LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED",
24
25
  LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED",
25
26
  LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
26
- LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
27
+ LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED",
28
+ LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN"
27
29
  });
28
30
  var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
29
31
  /**
@@ -239,12 +239,14 @@ declare const RESERVED_LOG_KEYS: Readonly<{
239
239
  readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
240
240
  readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
241
241
  readonly HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR";
242
+ readonly HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED";
242
243
  readonly METHOD_EXECUTION: "METHOD_EXECUTION";
243
244
  readonly METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION";
244
245
  readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
245
246
  readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
246
247
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
247
248
  readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
249
+ readonly LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN";
248
250
  }>;
249
251
  /**
250
252
  * Keys that are reserved but intentionally never emitted, each with the reason.
@@ -239,12 +239,14 @@ declare const RESERVED_LOG_KEYS: Readonly<{
239
239
  readonly HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED";
240
240
  readonly HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED";
241
241
  readonly HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR";
242
+ readonly HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED";
242
243
  readonly METHOD_EXECUTION: "METHOD_EXECUTION";
243
244
  readonly METHOD_SLOW_EXECUTION: "METHOD_SLOW_EXECUTION";
244
245
  readonly LOGGER_DESTINATION_INIT_FAILED: "LOGGER_DESTINATION_INIT_FAILED";
245
246
  readonly LOGGER_DESTINATION_WRITE_FAILED: "LOGGER_DESTINATION_WRITE_FAILED";
246
247
  readonly LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED";
247
248
  readonly LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED";
249
+ readonly LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN";
248
250
  }>;
249
251
  /**
250
252
  * Keys that are reserved but intentionally never emitted, each with the reason.
@@ -16,12 +16,14 @@ var RESERVED_LOG_KEYS = Object.freeze({
16
16
  HTTP_EXCEPTION_HANDLED: "HTTP_EXCEPTION_HANDLED",
17
17
  HTTP_EXCEPTION_UNHANDLED: "HTTP_EXCEPTION_UNHANDLED",
18
18
  HTTP_UNEXPECTED_ERROR: "HTTP_UNEXPECTED_ERROR",
19
+ HTTP_UNEXPECTED_ERROR_DROPPED: "HTTP_UNEXPECTED_ERROR_DROPPED",
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
24
  LOGGER_ENTRY_TRUNCATED: "LOGGER_ENTRY_TRUNCATED",
24
- LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED"
25
+ LOGGER_REDACTION_FAILED: "LOGGER_REDACTION_FAILED",
26
+ LOGGER_OTEL_API_BROKEN: "LOGGER_OTEL_API_BROKEN"
25
27
  });
26
28
  var RESERVED_LOG_KEYS_NOT_EMITTED = Object.freeze({
27
29
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-logger",
3
- "version": "1.4.5",
3
+ "version": "1.4.6",
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",
@@ -57,6 +57,7 @@
57
57
  "bench": "node --expose-gc --import tsx bench/throughput.bench.ts",
58
58
  "build": "pnpm clean && tsup",
59
59
  "check:exports": "attw --pack .",
60
+ "check:api": "node scripts/check-api-surface.mjs",
60
61
  "check:docs": "node scripts/check-doc-snippets.mjs",
61
62
  "check:mutants": "node scripts/check-mutation-directives.mjs",
62
63
  "check:published": "node scripts/check-published-surface.mjs",