@zudojs/logger 1.2.0 → 1.4.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.
Files changed (46) hide show
  1. package/README.md +74 -5
  2. package/dist/loggerCore/core/loggerCore.context.d.ts +4 -4
  3. package/dist/loggerCore/core/loggerCore.core.d.ts +4 -4
  4. package/dist/loggerCore/core/loggerCore.core.js +8 -8
  5. package/dist/loggerCore/core/loggerCore.type.d.ts +14 -4
  6. package/dist/loggerCore/helpers/loggerCore.helper.d.ts +2 -2
  7. package/dist/loggerCore/helpers/loggerCoreMethods/index.d.ts +1 -1
  8. package/dist/loggerCore/helpers/loggerCoreMethods/index.js +1 -1
  9. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.child.d.ts +2 -2
  10. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.dispatch.js +71 -25
  11. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.d.ts +6 -1
  12. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.entry.js +8 -3
  13. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.d.ts +7 -0
  14. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.level.js +35 -2
  15. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.d.ts +3 -3
  16. package/dist/loggerCore/helpers/loggerCoreMethods/loggerCoreMethods.lifecycle.js +8 -6
  17. package/dist/loggerEntry/loggerEntryCreate.js +2 -1
  18. package/dist/loggerEntry/loggerEntryHelpers/index.d.ts +1 -1
  19. package/dist/loggerEntry/loggerEntryHelpers/index.js +1 -1
  20. package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.interfaces.d.ts +11 -1
  21. package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.d.ts +18 -5
  22. package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.sanitize.js +66 -21
  23. package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.serialize.js +2 -1
  24. package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.d.ts +11 -2
  25. package/dist/loggerEntry/loggerEntryHelpers/loggerEntryHelpers.valueSerialize.js +53 -20
  26. package/dist/loggerFactory/loggerFactory.core.d.ts +9 -2
  27. package/dist/loggerFactory/loggerFactory.core.js +10 -0
  28. package/dist/loggerFormatter/loggerFormatter.core.js +3 -2
  29. package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.json.js +26 -13
  30. package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.d.ts +5 -2
  31. package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.metadata.js +12 -5
  32. package/dist/loggerFormatter/loggerFormatterFormatters/loggerFormatterFormatters.text.js +8 -4
  33. package/dist/loggerLevel/loggerLevel.type.d.ts +13 -0
  34. package/dist/loggerLevel/loggerLevel.type.js +17 -2
  35. package/dist/loggerManager/loggerManager.core.d.ts +10 -0
  36. package/dist/loggerManager/loggerManager.core.js +24 -7
  37. package/dist/loggerOptions/loggerOptions.type.d.ts +14 -3
  38. package/dist/loggerOptions/loggerOptions.type.js +7 -3
  39. package/dist/loggerTransport/loggerTransportComposite/loggerTransportComposite.buffered.js +9 -0
  40. package/dist/loggerTransport/loggerTransportConsole/loggerTransportConsole.core.d.ts +3 -2
  41. package/dist/loggerTransport/loggerTransportConsole/loggerTransportConsole.core.js +9 -4
  42. package/dist/loggerTransport/loggerTransportHelpers/index.d.ts +1 -1
  43. package/dist/loggerTransport/loggerTransportHelpers/index.js +1 -1
  44. package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.d.ts +15 -0
  45. package/dist/loggerTransport/loggerTransportHelpers/loggerTransportHelpers.js +22 -0
  46. package/package.json +4 -4
@@ -4,6 +4,7 @@
4
4
  * Lower numeric values represent more severe messages.
5
5
  * Higher numeric values represent more verbose messages.
6
6
  */
7
+ import { InvalidLoggerLevelError } from "../loggerErrors/loggerError.base.js";
7
8
  export var LoggerLevel;
8
9
  (function (LoggerLevel) {
9
10
  LoggerLevel[LoggerLevel["FATAL"] = 0] = "FATAL";
@@ -29,7 +30,7 @@ export function loggerLevelToName(level) {
29
30
  case LoggerLevel.TRACE:
30
31
  return "trace";
31
32
  default:
32
- throw new RangeError(`Unknown logger level: ${String(level)}`);
33
+ throw new InvalidLoggerLevelError(level);
33
34
  }
34
35
  }
35
36
  /** Converts a logger level name into its enum value. */
@@ -50,9 +51,23 @@ export function loggerLevelFromName(name) {
50
51
  case "trace":
51
52
  return LoggerLevel.TRACE;
52
53
  default:
53
- throw new RangeError(`Unknown logger level name: "${name}"`);
54
+ throw new InvalidLoggerLevelError(name);
54
55
  }
55
56
  }
57
+ /**
58
+ * Resolves a configured level (enum value or case-insensitive name) to its
59
+ * enum value.
60
+ *
61
+ * @throws InvalidLoggerLevelError when the value is neither.
62
+ */
63
+ export function resolveLoggerLevel(level) {
64
+ const value = level;
65
+ if (isLoggerLevel(value))
66
+ return value;
67
+ if (typeof value === "string")
68
+ return loggerLevelFromName(value.trim());
69
+ throw new InvalidLoggerLevelError(value);
70
+ }
56
71
  /** Checks whether a value is a valid LoggerLevel. */
57
72
  export function isLoggerLevel(value) {
58
73
  return (typeof value === "number" &&
@@ -16,6 +16,16 @@ export declare class LoggerManager {
16
16
  constructor(options?: LoggerOptions);
17
17
  /** Initializes the logger manager. Initialization is idempotent. */
18
18
  initialize(options?: LoggerOptions): Logger;
19
+ /**
20
+ * Adopts an existing logger as the manager's default logger.
21
+ *
22
+ * The logger is REGISTERED with the underlying factory, so it is
23
+ * covered by flush(), close(), getAll() and size. Assigning it to the
24
+ * private default field alone (as createLoggerManagerFromLogger used
25
+ * to) left the registry empty, making flush()/close() no-ops for the
26
+ * only logger the manager owned.
27
+ */
28
+ adopt(logger: Logger): Logger;
19
29
  /** Returns the default application logger. Lazily initializes when necessary. */
20
30
  getLogger(): Logger;
21
31
  /** Returns a named logger. Named loggers are managed by the underlying factory. */
@@ -1,3 +1,4 @@
1
+ import { LoggerDisposedError } from "../loggerErrors/loggerError.base.js";
1
2
  import { createLogger } from "../loggerCore/core/loggerCore.core.js";
2
3
  import { createDefaultLogger } from "../loggerCore/helpers/loggerCore.helper.js";
3
4
  import { createLoggerFactory } from "../loggerFactory/loggerFactory.core.js";
@@ -19,7 +20,7 @@ export class LoggerManager {
19
20
  /** Initializes the logger manager. Initialization is idempotent. */
20
21
  initialize(options = {}) {
21
22
  if (this.closed)
22
- throw new Error("LoggerManager has been closed.");
23
+ throw new LoggerDisposedError("LoggerManager");
23
24
  if (this.initialized && this.defaultLogger)
24
25
  return this.defaultLogger;
25
26
  const logger = this.factory.create(options.name ?? "zudojs", options);
@@ -27,10 +28,27 @@ export class LoggerManager {
27
28
  this.initialized = true;
28
29
  return logger;
29
30
  }
31
+ /**
32
+ * Adopts an existing logger as the manager's default logger.
33
+ *
34
+ * The logger is REGISTERED with the underlying factory, so it is
35
+ * covered by flush(), close(), getAll() and size. Assigning it to the
36
+ * private default field alone (as createLoggerManagerFromLogger used
37
+ * to) left the registry empty, making flush()/close() no-ops for the
38
+ * only logger the manager owned.
39
+ */
40
+ adopt(logger) {
41
+ if (this.closed)
42
+ throw new LoggerDisposedError("LoggerManager");
43
+ this.factory.register(logger);
44
+ this.defaultLogger = logger;
45
+ this.initialized = true;
46
+ return logger;
47
+ }
30
48
  /** Returns the default application logger. Lazily initializes when necessary. */
31
49
  getLogger() {
32
50
  if (this.closed)
33
- throw new Error("LoggerManager has been closed.");
51
+ throw new LoggerDisposedError("LoggerManager");
34
52
  if (!this.defaultLogger)
35
53
  return this.initialize();
36
54
  return this.defaultLogger;
@@ -38,13 +56,13 @@ export class LoggerManager {
38
56
  /** Returns a named logger. Named loggers are managed by the underlying factory. */
39
57
  get(name, options = {}) {
40
58
  if (this.closed)
41
- throw new Error("LoggerManager has been closed.");
59
+ throw new LoggerDisposedError("LoggerManager");
42
60
  return this.factory.getOrCreate(name, options);
43
61
  }
44
62
  /** Creates a new logger even when another logger with the same name already exists. */
45
63
  create(name, options = {}) {
46
64
  if (this.closed)
47
- throw new Error("LoggerManager has been closed.");
65
+ throw new LoggerDisposedError("LoggerManager");
48
66
  return this.factory.create(name, options, true);
49
67
  }
50
68
  /** Checks whether a named logger exists. */
@@ -99,7 +117,7 @@ export class LoggerManager {
99
117
  /** Provides direct access to the underlying factory. */
100
118
  getFactory() {
101
119
  if (this.closed)
102
- throw new Error("LoggerManager has been closed.");
120
+ throw new LoggerDisposedError("LoggerManager");
103
121
  return this.factory;
104
122
  }
105
123
  }
@@ -120,8 +138,7 @@ export function createManagedDefaultLogger(name = "zudojs") {
120
138
  /** Creates a logger manager from an existing logger. */
121
139
  export function createLoggerManagerFromLogger(logger) {
122
140
  const manager = new LoggerManager();
123
- manager["defaultLogger"] = logger;
124
- manager["initialized"] = true;
141
+ manager.adopt(logger);
125
142
  return manager;
126
143
  }
127
144
  /** Returns a logger from a manager or creates a fallback logger when no manager is supplied. */
@@ -1,4 +1,4 @@
1
- import { LoggerLevel } from "../loggerLevel/loggerLevel.type.js";
1
+ import { LoggerLevel, type LoggerLevelLike } from "../loggerLevel/loggerLevel.type.js";
2
2
  import type { LoggerContextData } from "../loggerContext/loggerContext.core.js";
3
3
  import type { LoggerFormatterLike } from "../loggerFormatter/loggerFormatter.type.js";
4
4
  import type { LoggerTransportLike } from "../loggerTransport/loggerTransport.type.js";
@@ -6,7 +6,8 @@ import type { LoggerRedactionOptions } from "../loggerEntry/loggerEntryHelpers/l
6
6
  /** Options used to configure a Zudojs logger. */
7
7
  export interface LoggerOptions {
8
8
  readonly name?: string;
9
- readonly level?: LoggerLevel;
9
+ /** Threshold: `LoggerLevel.WARN`, or a name such as `"warn"` / `"WARN"`. */
10
+ readonly level?: LoggerLevelLike;
10
11
  readonly environment?: string;
11
12
  readonly metadata?: LoggerContextData;
12
13
  readonly formatter?: LoggerFormatterLike;
@@ -33,6 +34,16 @@ export interface ChildLoggerOptions {
33
34
  readonly metadata?: LoggerContextData;
34
35
  readonly level?: LoggerLevel;
35
36
  }
37
+ /**
38
+ * What `Logger.child()` accepts: `ChildLoggerOptions` whose `level` may also
39
+ * be a name (`"debug"`, `"DEBUG"`). `ChildLoggerOptions` itself keeps the
40
+ * enum, so a custom logger that reads `options.level` still compiles; one
41
+ * that may be handed a name should pass it through `resolveLoggerLevel()`.
42
+ */
43
+ export interface ChildLoggerOptionsInput extends Omit<ChildLoggerOptions, "level"> {
44
+ /** Threshold: `LoggerLevel.DEBUG`, or a name such as `"debug"`. */
45
+ readonly level?: LoggerLevelLike;
46
+ }
36
47
  /** Options for a single log operation. */
37
48
  export interface LogOptions {
38
49
  readonly metadata?: LoggerContextData;
@@ -74,5 +85,5 @@ export declare function resolveLoggerOptions(options?: LoggerOptions): LoggerCon
74
85
  /** Merges two logger option objects. Values from `override` take precedence. */
75
86
  export declare function mergeLoggerOptions(base: LoggerOptions, override: LoggerOptions): LoggerOptions;
76
87
  /** Creates options for a child logger. */
77
- export declare function createChildLoggerOptions(parent: LoggerConfiguration, options?: ChildLoggerOptions): LoggerOptions;
88
+ export declare function createChildLoggerOptions(parent: LoggerConfiguration, options?: ChildLoggerOptionsInput): LoggerOptions;
78
89
  //# sourceMappingURL=loggerOptions.type.d.ts.map
@@ -1,4 +1,4 @@
1
- import { LoggerLevel } from "../loggerLevel/loggerLevel.type.js";
1
+ import { LoggerLevel, resolveLoggerLevel, } from "../loggerLevel/loggerLevel.type.js";
2
2
  /** Default logger configuration values. */
3
3
  export const DEFAULT_LOGGER_OPTIONS = {
4
4
  enabled: true,
@@ -29,7 +29,9 @@ export function resolveLoggerOptions(options = {}) {
29
29
  validateLoggerOptions(options);
30
30
  return Object.freeze({
31
31
  name: options.name ?? "zudojs",
32
- level: options.level ?? LoggerLevel.INFO,
32
+ level: options.level === undefined
33
+ ? LoggerLevel.INFO
34
+ : resolveLoggerLevel(options.level),
33
35
  environment: options.environment,
34
36
  metadata: Object.freeze({ ...(options.metadata ?? {}) }),
35
37
  formatter: options.formatter ?? "text",
@@ -57,7 +59,9 @@ export function mergeLoggerOptions(base, override) {
57
59
  export function createChildLoggerOptions(parent, options = {}) {
58
60
  return {
59
61
  name: options.name ?? parent.name,
60
- level: options.level ?? parent.level,
62
+ level: options.level === undefined
63
+ ? parent.level
64
+ : resolveLoggerLevel(options.level),
61
65
  environment: parent.environment,
62
66
  metadata: { ...parent.metadata, ...(options.metadata ?? {}) },
63
67
  formatter: parent.formatter,
@@ -4,6 +4,7 @@
4
4
  import { createLoggerTransport, writeLoggerTransport, } from "../loggerTransport.core.js";
5
5
  import { closeLoggerTransport, flushLoggerTransport, } from "../loggerTransportHelpers/loggerTransportHelpers.js";
6
6
  import { throwCollectedFailures } from "../../loggerErrors/loggerError.helpers.js";
7
+ import { LoggerTransportClosedError } from "../../loggerErrors/loggerError.base.js";
7
8
  /**
8
9
  * Creates a transport that buffers entries before forwarding
9
10
  * them to another transport.
@@ -14,6 +15,7 @@ export function createBufferedLoggerTransport(transport, options = {}) {
14
15
  const flushInterval = options.flushInterval ?? 0;
15
16
  let timer;
16
17
  let deferredFailure;
18
+ let closed = false;
17
19
  // Each entry is written on its own: one failing write used to abort the
18
20
  // loop after the whole batch had already been spliced out, losing every
19
21
  // entry behind it. Only the entries that actually failed are dropped.
@@ -80,6 +82,12 @@ export function createBufferedLoggerTransport(transport, options = {}) {
80
82
  name: options.name ?? "buffered",
81
83
  enabled: options.enabled ?? true,
82
84
  async write(entry) {
85
+ // A write after close() used to be buffered and then silently
86
+ // dropped: nothing drains the buffer again. Refuse it instead so
87
+ // the caller learns the entry was not accepted.
88
+ if (closed) {
89
+ throw new LoggerTransportClosedError(options.name ?? "buffered");
90
+ }
83
91
  buffer.push(entry);
84
92
  if (buffer.length >= maxSize) {
85
93
  await drain();
@@ -90,6 +98,7 @@ export function createBufferedLoggerTransport(transport, options = {}) {
90
98
  },
91
99
  flush,
92
100
  async close() {
101
+ closed = true;
93
102
  if (timer) {
94
103
  clearTimeout(timer);
95
104
  timer = undefined;
@@ -5,8 +5,9 @@ import type { LoggerTransportOptions, RegisteredLoggerTransport } from "../logge
5
5
  /**
6
6
  * Creates a simple console transport.
7
7
  *
8
- * Uses the standard console methods rather than depending on
9
- * Node.js-specific APIs.
8
+ * Prints one line per record through the standard console methods (no
9
+ * Node.js-specific APIs): `entry.formatted` when the logger's formatter
10
+ * produced it, otherwise the entry as a single JSON line.
10
11
  */
11
12
  export declare function createConsoleLoggerTransport(options?: LoggerTransportOptions): RegisteredLoggerTransport;
12
13
  //# sourceMappingURL=loggerTransportConsole.core.d.ts.map
@@ -2,19 +2,24 @@
2
2
  * Console logger transport.
3
3
  */
4
4
  import { createLoggerTransport } from "../loggerTransport.core.js";
5
- import { serializeTransportEntry } from "../loggerTransportHelpers/loggerTransportHelpers.js";
5
+ import { formatTransportLine } from "../loggerTransportHelpers/loggerTransportHelpers.js";
6
6
  /**
7
7
  * Creates a simple console transport.
8
8
  *
9
- * Uses the standard console methods rather than depending on
10
- * Node.js-specific APIs.
9
+ * Prints one line per record through the standard console methods (no
10
+ * Node.js-specific APIs): `entry.formatted` when the logger's formatter
11
+ * produced it, otherwise the entry as a single JSON line.
11
12
  */
12
13
  export function createConsoleLoggerTransport(options = {}) {
13
14
  const transport = {
14
15
  name: options.name ?? "console",
15
16
  enabled: options.enabled ?? true,
16
17
  write(entry) {
17
- const payload = serializeTransportEntry(entry);
18
+ // One line per record: the formatter's line (text or JSON), or the
19
+ // entry as JSON. Printing the record object showed the timestamp and
20
+ // level twice beside a text line, and spread a structured record over
21
+ // several lines of console output.
22
+ const payload = formatTransportLine(entry);
18
23
  switch (entry.levelName) {
19
24
  case "fatal":
20
25
  case "error":
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Transport helper functions.
5
5
  */
6
- export { serializeTransportEntry, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
6
+ export { serializeTransportEntry, toJsonLogLine, formatTransportLine, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Transport helper functions.
5
5
  */
6
- export { serializeTransportEntry, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
6
+ export { serializeTransportEntry, toJsonLogLine, formatTransportLine, closeLoggerTransport, flushLoggerTransport, } from "./loggerTransportHelpers.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -7,6 +7,21 @@ import type { LoggerTransportLike } from "../loggerTransport.type.js";
7
7
  * Converts a LoggerEntry into a console-friendly object.
8
8
  */
9
9
  export declare function serializeTransportEntry(entry: LoggerEntry): Record<string, unknown>;
10
+ /**
11
+ * Renders a record as one line of JSON.
12
+ *
13
+ * Values go through `serializeLoggerValue` first, so a cycle becomes
14
+ * `"[Circular]"`, a BigInt its decimal string and an Error its name,
15
+ * message and stack. `JSON.stringify` escapes `\n`; U+2028 and U+2029,
16
+ * which it leaves raw and some viewers break lines on, are escaped too.
17
+ */
18
+ export declare function toJsonLogLine(record: unknown): string;
19
+ /**
20
+ * The text a line-oriented transport (console, file, stream) prints for an
21
+ * entry: the formatter's line when there is one, otherwise the entry as a
22
+ * single JSON line.
23
+ */
24
+ export declare function formatTransportLine(entry: LoggerEntry): string;
10
25
  /**
11
26
  * Safely closes a transport.
12
27
  */
@@ -42,6 +42,28 @@ export function serializeTransportEntry(entry) {
42
42
  : {}),
43
43
  };
44
44
  }
45
+ /**
46
+ * Renders a record as one line of JSON.
47
+ *
48
+ * Values go through `serializeLoggerValue` first, so a cycle becomes
49
+ * `"[Circular]"`, a BigInt its decimal string and an Error its name,
50
+ * message and stack. `JSON.stringify` escapes `\n`; U+2028 and U+2029,
51
+ * which it leaves raw and some viewers break lines on, are escaped too.
52
+ */
53
+ export function toJsonLogLine(record) {
54
+ const json = JSON.stringify(serializeLoggerValue(record)) ?? "null";
55
+ return json.replace(/\u2028/gu, "\\u2028").replace(/\u2029/gu, "\\u2029");
56
+ }
57
+ /**
58
+ * The text a line-oriented transport (console, file, stream) prints for an
59
+ * entry: the formatter's line when there is one, otherwise the entry as a
60
+ * single JSON line.
61
+ */
62
+ export function formatTransportLine(entry) {
63
+ return typeof entry.formatted === "string"
64
+ ? entry.formatted
65
+ : toJsonLogLine(serializeTransportEntry(entry));
66
+ }
45
67
  /**
46
68
  * Safely closes a transport.
47
69
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/logger",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Structured logging with transports, log levels, and context propagation for Zudojs applications.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -28,11 +28,11 @@
28
28
  "node": ">=24.0.0"
29
29
  },
30
30
  "dependencies": {
31
- "@zudojs/errors": "1.1.0"
31
+ "@zudojs/errors": "1.3.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "typescript": "7.0.2",
35
- "vitest": "^4.1.11"
35
+ "vitest": "^5.0.1"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -43,7 +43,7 @@
43
43
  "structured-logs",
44
44
  "transports"
45
45
  ],
46
- "homepage": "https://github.com/oyinlola-tech/zudo#readme",
46
+ "homepage": "https://zudojs.oyinlola.site/docs/packages-logger",
47
47
  "bugs": {
48
48
  "url": "https://github.com/oyinlola-tech/zudo/issues"
49
49
  },