@bymax-one/nest-logger 1.4.7 → 1.4.8

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,33 @@ heading here.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.4.8] - 2026-11-01
15
+
16
+ ### Fixed
17
+
18
+ - **A logging call no longer throws because of what it was handed.** `error`, `warn`, `log`, `fatal`
19
+ and the other NestJS variadic methods threw out of the call when an `Error` had a `name` or `message`
20
+ getter that throws, and when the message had no text form (a null-prototype object, a throwing
21
+ `toString`). In `catch (e) { logger.error(e) }` that second throw replaced the original error and
22
+ nothing was logged. The call now returns and the entry is written: an unreadable `Error` arrives as
23
+ the same `err` node `errorStructured` produces, with `err.type: 'SanitizeFailed'`, and a message with
24
+ no text form is logged as `Unreadable log message`.
25
+
26
+ #### Apply to a derived backend
27
+
28
+ Nothing to change in code. What can differ at run time:
29
+
30
+ - Entries that were never written now appear. A host that handled the throw (a `try` around the logging
31
+ call, or an error handler that reacted to it) no longer sees it; one that relied on the throw to detect
32
+ a hostile input should look for `err.type: 'SanitizeFailed'` (an `Error`) or the message
33
+ `Unreadable log message` (a message) instead.
34
+
35
+ ### Tests
36
+
37
+ - Each variadic position with an unreadable `name` or `message`, and each message with no text form on
38
+ `error`, `warn` and `log`, has a failing-first spec through the real Pino pipeline, with a control that
39
+ a readable error is logged as before.
40
+
14
41
  ## [1.4.7] - 2026-11-01
15
42
 
16
43
  ### Fixed
@@ -2311,7 +2338,8 @@ published `dist/` is identical — no runtime behaviour changes for consumers.
2311
2338
  - Professional CI suite: `ci.yml`, `bench.yml`, `codeql.yml`, `scorecard.yml`,
2312
2339
  `release.yml`, Dependabot, and issue templates
2313
2340
 
2314
- [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.4.7...HEAD
2341
+ [Unreleased]: https://github.com/bymaxone/nest-logger/compare/v1.4.8...HEAD
2342
+ [1.4.8]: https://github.com/bymaxone/nest-logger/compare/v1.4.7...v1.4.8
2315
2343
  [1.4.7]: https://github.com/bymaxone/nest-logger/compare/v1.4.6...v1.4.7
2316
2344
  [1.4.6]: https://github.com/bymaxone/nest-logger/compare/v1.4.5...v1.4.6
2317
2345
  [1.4.5]: https://github.com/bymaxone/nest-logger/compare/v1.4.4...v1.4.5
@@ -386,15 +386,29 @@ function sanitizeError(err, options) {
386
386
  return toSanitizedError(err, /* @__PURE__ */ new WeakSet(), 0, maxCauseDepth);
387
387
  }
388
388
  function isErrorLike(value) {
389
+ try {
390
+ return readsAsError(value);
391
+ } catch {
392
+ return isErrorInstance(value);
393
+ }
394
+ }
395
+ function readsAsError(value) {
389
396
  if (typeof value !== "object" || value === null) {
390
397
  return false;
391
398
  }
392
399
  const candidate = value;
393
400
  return typeof candidate.name === "string" && typeof candidate.message === "string";
394
401
  }
402
+ function isErrorInstance(value) {
403
+ try {
404
+ return value instanceof Error;
405
+ } catch {
406
+ return false;
407
+ }
408
+ }
395
409
  function toSanitizedError(value, seen, depth2, maxDepth) {
396
410
  try {
397
- if (!isErrorLike(value)) {
411
+ if (!readsAsError(value)) {
398
412
  return { name: "UnknownError", message: String(value) };
399
413
  }
400
414
  seen.add(value);
@@ -500,6 +514,13 @@ function safeErrorMessage(error) {
500
514
  return "Unreadable error message";
501
515
  }
502
516
  }
517
+ function safeLogMessage(message) {
518
+ try {
519
+ return toSingleLineMessage(typeof message === "string" ? message : String(message));
520
+ } catch {
521
+ return "Unreadable log message";
522
+ }
523
+ }
503
524
  function findErrorParam(optionalParams) {
504
525
  return optionalParams.find((param) => isErrorLike(param));
505
526
  }
@@ -571,10 +592,7 @@ exports.PinoLoggerService = class PinoLoggerService {
571
592
  assignIfDefined(payload, "context", context);
572
593
  assignIfDefined(payload, "stack", stack);
573
594
  assignIfDefined(payload, "err", findErrorParam(optionalParams));
574
- this.pino.error(
575
- payload,
576
- toSingleLineMessage(typeof message === "string" ? message : String(message))
577
- );
595
+ this.pino.error(payload, safeLogMessage(message));
578
596
  }
579
597
  /**
580
598
  * NestJS `warn` (warn level).
@@ -731,7 +749,7 @@ exports.PinoLoggerService = class PinoLoggerService {
731
749
  assignIfDefined(payload, "context", this.resolveContext(optionalParams));
732
750
  const leading = isErrorLike(message) ? message : void 0;
733
751
  assignIfDefined(payload, "err", leading ?? findErrorParam(optionalParams));
734
- const msg = leading === void 0 ? toSingleLineMessage(typeof message === "string" ? message : String(message)) : safeErrorMessage(leading);
752
+ const msg = leading === void 0 ? safeLogMessage(message) : safeErrorMessage(leading);
735
753
  switch (level) {
736
754
  case "info":
737
755
  this.pino.info(payload, msg);
@@ -3218,11 +3236,7 @@ exports.PinoUnexpectedErrorSink = __decorateClass([
3218
3236
  __decorateParam(0, common.Inject(exports.PinoLoggerService))
3219
3237
  ], exports.PinoUnexpectedErrorSink);
3220
3238
  function toLoggableError(value) {
3221
- try {
3222
- return isErrorLike(value) ? value : sanitizeError(value);
3223
- } catch {
3224
- return sanitizeError(value);
3225
- }
3239
+ return isErrorLike(value) ? value : sanitizeError(value);
3226
3240
  }
3227
3241
  var INJECT_LOGGER_CONTEXT_METADATA_KEY = "bymax_logger:context";
3228
3242
  function InjectLogger(context) {
@@ -383,15 +383,29 @@ function sanitizeError(err, options) {
383
383
  return toSanitizedError(err, /* @__PURE__ */ new WeakSet(), 0, maxCauseDepth);
384
384
  }
385
385
  function isErrorLike(value) {
386
+ try {
387
+ return readsAsError(value);
388
+ } catch {
389
+ return isErrorInstance(value);
390
+ }
391
+ }
392
+ function readsAsError(value) {
386
393
  if (typeof value !== "object" || value === null) {
387
394
  return false;
388
395
  }
389
396
  const candidate = value;
390
397
  return typeof candidate.name === "string" && typeof candidate.message === "string";
391
398
  }
399
+ function isErrorInstance(value) {
400
+ try {
401
+ return value instanceof Error;
402
+ } catch {
403
+ return false;
404
+ }
405
+ }
392
406
  function toSanitizedError(value, seen, depth2, maxDepth) {
393
407
  try {
394
- if (!isErrorLike(value)) {
408
+ if (!readsAsError(value)) {
395
409
  return { name: "UnknownError", message: String(value) };
396
410
  }
397
411
  seen.add(value);
@@ -497,6 +511,13 @@ function safeErrorMessage(error) {
497
511
  return "Unreadable error message";
498
512
  }
499
513
  }
514
+ function safeLogMessage(message) {
515
+ try {
516
+ return toSingleLineMessage(typeof message === "string" ? message : String(message));
517
+ } catch {
518
+ return "Unreadable log message";
519
+ }
520
+ }
500
521
  function findErrorParam(optionalParams) {
501
522
  return optionalParams.find((param) => isErrorLike(param));
502
523
  }
@@ -568,10 +589,7 @@ var PinoLoggerService = class {
568
589
  assignIfDefined(payload, "context", context);
569
590
  assignIfDefined(payload, "stack", stack);
570
591
  assignIfDefined(payload, "err", findErrorParam(optionalParams));
571
- this.pino.error(
572
- payload,
573
- toSingleLineMessage(typeof message === "string" ? message : String(message))
574
- );
592
+ this.pino.error(payload, safeLogMessage(message));
575
593
  }
576
594
  /**
577
595
  * NestJS `warn` (warn level).
@@ -728,7 +746,7 @@ var PinoLoggerService = class {
728
746
  assignIfDefined(payload, "context", this.resolveContext(optionalParams));
729
747
  const leading = isErrorLike(message) ? message : void 0;
730
748
  assignIfDefined(payload, "err", leading ?? findErrorParam(optionalParams));
731
- const msg = leading === void 0 ? toSingleLineMessage(typeof message === "string" ? message : String(message)) : safeErrorMessage(leading);
749
+ const msg = leading === void 0 ? safeLogMessage(message) : safeErrorMessage(leading);
732
750
  switch (level) {
733
751
  case "info":
734
752
  this.pino.info(payload, msg);
@@ -3215,11 +3233,7 @@ PinoUnexpectedErrorSink = __decorateClass([
3215
3233
  __decorateParam(0, Inject(PinoLoggerService))
3216
3234
  ], PinoUnexpectedErrorSink);
3217
3235
  function toLoggableError(value) {
3218
- try {
3219
- return isErrorLike(value) ? value : sanitizeError(value);
3220
- } catch {
3221
- return sanitizeError(value);
3222
- }
3236
+ return isErrorLike(value) ? value : sanitizeError(value);
3223
3237
  }
3224
3238
  var INJECT_LOGGER_CONTEXT_METADATA_KEY = "bymax_logger:context";
3225
3239
  function InjectLogger(context) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-logger",
3
- "version": "1.4.7",
3
+ "version": "1.4.8",
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",