@unchainedshop/logger 4.3.4 → 4.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.
@@ -1,5 +1,5 @@
1
1
  import { performance } from 'node:perf_hooks';
2
- import { createLogger, resetLoggerInitialization } from '../src/createLogger.js';
2
+ import { createLogger, resetLoggerInitialization } from '../src/createLogger.ts';
3
3
 
4
4
  interface BenchmarkResult {
5
5
  name: string;
@@ -5,20 +5,5 @@ export interface Logger {
5
5
  warn: (message: any, ...args: any[]) => void;
6
6
  error: (message: any, ...args: any[]) => void;
7
7
  }
8
- /**
9
- * Resets all internal caches. Used for testing to ensure a clean state.
10
- */
11
8
  export declare const resetLoggerInitialization: () => void;
12
- /**
13
- * Creates a logger instance for the specified module name.
14
- * The logger respects DEBUG, LOG_LEVEL, and UNCHAINED_LOG_FORMAT environment variables.
15
- *
16
- * Performance optimizations:
17
- * - Returns no-op functions for disabled log levels (zero-cost logging)
18
- * - Caches regex patterns and debug results for fast pattern matching
19
- *
20
- * @param moduleName - The name of the module (used for filtering and display)
21
- * @returns A logger instance with trace, debug, info, warn, and error methods
22
- */
23
9
  export declare const createLogger: (moduleName: string) => Logger;
24
- //# sourceMappingURL=createLogger.d.ts.map
@@ -1,25 +1,11 @@
1
1
  import { inspect } from 'node:util';
2
2
  import { stringify } from 'safe-stable-stringify';
3
- import { LogLevel } from './logger.types.js';
4
- /**
5
- * Performance optimization: Cache compiled regex patterns to avoid recreating them
6
- * on every DEBUG pattern match. This provides ~190% improvement in pattern matching.
7
- */
3
+ import { LogLevel } from "./logger.types.js";
8
4
  const regexCache = new Map();
9
- /**
10
- * Performance optimization: Cache DEBUG pattern matching results per module
11
- * to avoid recomputation for the same module names.
12
- */
13
5
  const debugPatternCache = new Map();
14
- /**
15
- * Checks if a module name matches the DEBUG environment variable pattern.
16
- * Supports wildcards (*), exclusions (-pattern), and comma-separated lists.
17
- * Results are cached for performance.
18
- */
19
6
  const debugStringContainsModule = (debugString, moduleName) => {
20
7
  if (!debugString)
21
8
  return false;
22
- // Check cache first for performance
23
9
  const cacheKey = `${debugString}::${moduleName}`;
24
10
  const cached = debugPatternCache.get(cacheKey);
25
11
  if (cached !== undefined)
@@ -27,7 +13,6 @@ const debugStringContainsModule = (debugString, moduleName) => {
27
13
  const loggingMatched = debugString.split(',').reduce((accumulator, name) => {
28
14
  if (accumulator === false)
29
15
  return accumulator;
30
- // Get or create cached regex pattern
31
16
  let regExp = regexCache.get(name);
32
17
  if (!regExp) {
33
18
  const nameRegex = name.replace(/-/i, '\\-?').replace(/:\*/i, '\\:?*').replace(/\*/i, '.*');
@@ -35,7 +20,6 @@ const debugStringContainsModule = (debugString, moduleName) => {
35
20
  regexCache.set(name, regExp);
36
21
  }
37
22
  if (regExp.test(moduleName)) {
38
- // Exclusion pattern (starts with -)
39
23
  if (name.slice(0, 1) === '-') {
40
24
  return false;
41
25
  }
@@ -47,7 +31,6 @@ const debugStringContainsModule = (debugString, moduleName) => {
47
31
  debugPatternCache.set(cacheKey, result);
48
32
  return result;
49
33
  };
50
- // ANSI color codes
51
34
  const colors = {
52
35
  gray: '\x1b[90m',
53
36
  green: '\x1b[32m',
@@ -58,22 +41,19 @@ const colors = {
58
41
  magenta: '\x1b[35m',
59
42
  reset: '\x1b[0m',
60
43
  };
61
- // Log level configuration
62
- var LogLevelValue;
63
- (function (LogLevelValue) {
64
- LogLevelValue[LogLevelValue["TRACE"] = 0] = "TRACE";
65
- LogLevelValue[LogLevelValue["DEBUG"] = 1] = "DEBUG";
66
- LogLevelValue[LogLevelValue["INFO"] = 2] = "INFO";
67
- LogLevelValue[LogLevelValue["WARN"] = 3] = "WARN";
68
- LogLevelValue[LogLevelValue["ERROR"] = 4] = "ERROR";
69
- })(LogLevelValue || (LogLevelValue = {}));
44
+ const LogLevelValue = {
45
+ TRACE: 0,
46
+ DEBUG: 1,
47
+ INFO: 2,
48
+ WARN: 3,
49
+ ERROR: 4,
50
+ };
70
51
  const logLevelMap = {
71
52
  [LogLevel.Verbose]: LogLevelValue.TRACE,
72
53
  [LogLevel.Debug]: LogLevelValue.DEBUG,
73
54
  [LogLevel.Info]: LogLevelValue.INFO,
74
55
  [LogLevel.Warning]: LogLevelValue.WARN,
75
56
  [LogLevel.Error]: LogLevelValue.ERROR,
76
- // Add trace as an alias for verbose
77
57
  trace: LogLevelValue.TRACE,
78
58
  };
79
59
  const levelColors = {
@@ -83,10 +63,6 @@ const levelColors = {
83
63
  warn: colors.yellow,
84
64
  error: colors.red,
85
65
  };
86
- /**
87
- * Formats the current time as HH:MM:SS for log output.
88
- * Optimized to avoid unnecessary string conversions.
89
- */
90
66
  const formatTimestamp = () => {
91
67
  const now = new Date();
92
68
  const hours = now.getHours().toString().padStart(2, '0');
@@ -94,42 +70,22 @@ const formatTimestamp = () => {
94
70
  const seconds = now.getSeconds().toString().padStart(2, '0');
95
71
  return `${hours}:${minutes}:${seconds}`;
96
72
  };
97
- /**
98
- * Custom JSON replacer function that handles BigInt values by converting them to strings.
99
- * This ensures BigInt values can be serialized in JSON logs.
100
- */
101
73
  const bigintReplacer = (_key, value) => {
102
74
  if (typeof value === 'bigint') {
103
75
  return value.toString();
104
76
  }
105
77
  return value;
106
78
  };
107
- /**
108
- * Resets all internal caches. Used for testing to ensure a clean state.
109
- */
110
79
  export const resetLoggerInitialization = () => {
111
80
  regexCache.clear();
112
81
  debugPatternCache.clear();
113
82
  };
114
- /**
115
- * Creates a logger instance for the specified module name.
116
- * The logger respects DEBUG, LOG_LEVEL, and UNCHAINED_LOG_FORMAT environment variables.
117
- *
118
- * Performance optimizations:
119
- * - Returns no-op functions for disabled log levels (zero-cost logging)
120
- * - Caches regex patterns and debug results for fast pattern matching
121
- *
122
- * @param moduleName - The name of the module (used for filtering and display)
123
- * @returns A logger instance with trace, debug, info, warn, and error methods
124
- */
125
83
  export const createLogger = (moduleName) => {
126
84
  const { DEBUG = '', LOG_LEVEL = LogLevel.Info, UNCHAINED_LOG_FORMAT = 'unchained' } = process.env;
127
- // Validate format at logger creation time
128
85
  const format = UNCHAINED_LOG_FORMAT.toLowerCase();
129
86
  if (format !== 'json' && format !== 'unchained') {
130
87
  throw new Error(`UNCHAINED_LOG_FORMAT is invalid, use one of json,unchained`);
131
88
  }
132
- // Determine minimum log level
133
89
  const loggingMatched = debugStringContainsModule(DEBUG, moduleName);
134
90
  const logLevelLower = LOG_LEVEL.toLowerCase();
135
91
  const mappedLevel = logLevelMap[logLevelLower];
@@ -138,35 +94,28 @@ export const createLogger = (moduleName) => {
138
94
  : mappedLevel !== undefined
139
95
  ? mappedLevel
140
96
  : LogLevelValue.INFO;
141
- // Performance optimization: No-op function for disabled log levels
142
97
  const noop = () => {
143
- // Intentionally empty for performance
144
98
  };
145
99
  const log = (level, levelValue, message, ...args) => {
146
100
  if (levelValue < minLevel)
147
101
  return;
148
102
  if (format === 'json') {
149
- // JSON format
150
103
  const logObject = {
151
104
  timestamp: new Date().toISOString(),
152
105
  level: level.toUpperCase(),
153
106
  name: moduleName,
154
107
  message: typeof message === 'string' ? message : message,
155
108
  };
156
- // Merge additional args if they're objects, guarding against prototype pollution
157
109
  if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {
158
110
  for (const key in args[0]) {
159
- // Skip prototype pollution vectors
160
111
  if (key === '__proto__' || key === 'constructor' || key === 'prototype')
161
112
  continue;
162
113
  logObject[key] = args[0][key];
163
114
  }
164
115
  }
165
- // Use safe-stable-stringify for proper JSON output with BigInt support
166
116
  console.log(stringify(logObject, bigintReplacer));
167
117
  }
168
118
  else {
169
- // Unchained format (pretty)
170
119
  const timestamp = formatTimestamp();
171
120
  const levelColor = levelColors[level] || colors.reset;
172
121
  const prefix = `${colors.gray}${timestamp}${colors.reset} [${colors.green}${moduleName}${colors.reset}] ${levelColor}${level}:${colors.reset}`;
@@ -196,4 +145,3 @@ export const createLogger = (moduleName) => {
196
145
  : (message, ...args) => log('error', LogLevelValue.ERROR, message, ...args),
197
146
  };
198
147
  };
199
- //# sourceMappingURL=createLogger.js.map
package/lib/log.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export declare const defaultLogger: import("./createLogger.js").Logger;
1
+ export declare const defaultLogger: import("./createLogger.ts").Logger;
2
2
  export declare const log: (message: any, ...args: any[]) => void;
3
- //# sourceMappingURL=log.d.ts.map
package/lib/log.js CHANGED
@@ -1,5 +1,4 @@
1
- import { createLogger } from './createLogger.js';
1
+ import { createLogger } from "./createLogger.js";
2
2
  const logger = createLogger('unchained');
3
3
  export const defaultLogger = logger;
4
4
  export const log = logger.info;
5
- //# sourceMappingURL=log.js.map
@@ -1,4 +1,3 @@
1
- export * from './createLogger.js';
2
- export * from './logger.types.js';
3
- export * from './log.js';
4
- //# sourceMappingURL=logger-index.d.ts.map
1
+ export * from './createLogger.ts';
2
+ export * from './logger.types.ts';
3
+ export * from './log.ts';
@@ -1,4 +1,3 @@
1
- export * from './createLogger.js';
2
- export * from './logger.types.js';
3
- export * from './log.js';
4
- //# sourceMappingURL=logger-index.js.map
1
+ export * from "./createLogger.js";
2
+ export * from "./logger.types.js";
3
+ export * from "./log.js";
@@ -1,8 +1,8 @@
1
- export declare enum LogLevel {
2
- Verbose = "verbose",
3
- Info = "info",
4
- Debug = "debug",
5
- Error = "error",
6
- Warning = "warn"
7
- }
8
- //# sourceMappingURL=logger.types.d.ts.map
1
+ export declare const LogLevel: {
2
+ readonly Verbose: "verbose";
3
+ readonly Info: "info";
4
+ readonly Debug: "debug";
5
+ readonly Error: "error";
6
+ readonly Warning: "warn";
7
+ };
8
+ export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
@@ -1,9 +1,7 @@
1
- export var LogLevel;
2
- (function (LogLevel) {
3
- LogLevel["Verbose"] = "verbose";
4
- LogLevel["Info"] = "info";
5
- LogLevel["Debug"] = "debug";
6
- LogLevel["Error"] = "error";
7
- LogLevel["Warning"] = "warn";
8
- })(LogLevel || (LogLevel = {}));
9
- //# sourceMappingURL=logger.types.js.map
1
+ export const LogLevel = {
2
+ Verbose: 'verbose',
3
+ Info: 'info',
4
+ Debug: 'debug',
5
+ Error: 'error',
6
+ Warning: 'warn',
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unchainedshop/logger",
3
- "version": "4.3.4",
3
+ "version": "4.4.0",
4
4
  "main": "lib/logger-index.js",
5
5
  "types": "lib/logger-index.d.ts",
6
6
  "type": "module",
@@ -9,9 +9,9 @@
9
9
  "build": "tsc -b",
10
10
  "prepublishOnly": "npm run clean && npm run build",
11
11
  "watch": "tsc -w",
12
- "test": "tsx --test",
13
- "test:watch": "tsx --test --watch",
14
- "benchmark": "tsx benchmarks/benchmark.ts"
12
+ "test": "node --test",
13
+ "test:watch": "node --test --watch",
14
+ "benchmark": "node benchmarks/benchmark.ts"
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",
@@ -23,8 +23,10 @@
23
23
  "core"
24
24
  ],
25
25
  "authors": [
26
- "Joël Meiller",
27
- "Pascal Kaufmann"
26
+ "Pascal Kaufmann",
27
+ "Mikael Araya",
28
+ "Vedran Rudelj",
29
+ "Joël Meiller"
28
30
  ],
29
31
  "license": "EUPL-1.2",
30
32
  "bugs": {
@@ -35,8 +37,7 @@
35
37
  "safe-stable-stringify": "^2.5.0"
36
38
  },
37
39
  "devDependencies": {
38
- "@types/node": "^24.0.13",
39
- "tsx": "^4.20.3",
40
+ "@types/node": "^25.0.0",
40
41
  "typescript": "^5.8.3"
41
42
  }
42
43
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"createLogger.d.ts","sourceRoot":"","sources":["../src/createLogger.ts"],"names":[],"mappings":"AA8FA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC9C,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC9C,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC7C,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC7C,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CAC/C;AAyBD;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,IAG5C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GAAI,YAAY,MAAM,KAAG,MAmFjD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"createLogger.js","sourceRoot":"","sources":["../src/createLogger.ts"],"names":[],"mappings":"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"}
package/lib/log.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,aAAa,oCAAS,CAAC;AAEpC,eAAO,MAAM,GAAG,wCAAc,CAAC"}
package/lib/log.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;AAEzC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger-index.d.ts","sourceRoot":"","sources":["../src/logger-index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger-index.js","sourceRoot":"","sources":["../src/logger-index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.types.d.ts","sourceRoot":"","sources":["../src/logger.types.ts"],"names":[],"mappings":"AAAA,oBAAY,QAAQ;IAClB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAO,SAAS;CACjB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.types.js","sourceRoot":"","sources":["../src/logger.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,QAMX;AAND,WAAY,QAAQ;IAClB,+BAAmB,CAAA;IACnB,yBAAa,CAAA;IACb,2BAAe,CAAA;IACf,2BAAe,CAAA;IACf,4BAAgB,CAAA;AAClB,CAAC,EANW,QAAQ,KAAR,QAAQ,QAMnB"}
@@ -1,228 +0,0 @@
1
- import { inspect } from 'node:util';
2
- import { stringify } from 'safe-stable-stringify';
3
- import { LogLevel } from './logger.types.js';
4
-
5
- /**
6
- * Performance optimization: Cache compiled regex patterns to avoid recreating them
7
- * on every DEBUG pattern match. This provides ~190% improvement in pattern matching.
8
- */
9
- const regexCache = new Map<string, RegExp>();
10
-
11
- /**
12
- * Performance optimization: Cache DEBUG pattern matching results per module
13
- * to avoid recomputation for the same module names.
14
- */
15
- const debugPatternCache = new Map<string, boolean>();
16
-
17
- /**
18
- * Checks if a module name matches the DEBUG environment variable pattern.
19
- * Supports wildcards (*), exclusions (-pattern), and comma-separated lists.
20
- * Results are cached for performance.
21
- */
22
- const debugStringContainsModule = (debugString: string, moduleName: string): boolean => {
23
- if (!debugString) return false;
24
-
25
- // Check cache first for performance
26
- const cacheKey = `${debugString}::${moduleName}`;
27
- const cached = debugPatternCache.get(cacheKey);
28
- if (cached !== undefined) return cached;
29
-
30
- const loggingMatched = debugString.split(',').reduce((accumulator: any, name: string) => {
31
- if (accumulator === false) return accumulator;
32
-
33
- // Get or create cached regex pattern
34
- let regExp = regexCache.get(name);
35
- if (!regExp) {
36
- const nameRegex = name.replace(/-/i, '\\-?').replace(/:\*/i, '\\:?*').replace(/\*/i, '.*');
37
- regExp = new RegExp(`^${nameRegex}$`, 'm');
38
- regexCache.set(name, regExp);
39
- }
40
-
41
- if (regExp.test(moduleName)) {
42
- // Exclusion pattern (starts with -)
43
- if (name.slice(0, 1) === '-') {
44
- return false;
45
- }
46
- return true;
47
- }
48
- return accumulator;
49
- }, undefined);
50
-
51
- const result = loggingMatched || false;
52
- debugPatternCache.set(cacheKey, result);
53
- return result;
54
- };
55
-
56
- // ANSI color codes
57
- const colors = {
58
- gray: '\x1b[90m',
59
- green: '\x1b[32m',
60
- cyan: '\x1b[36m',
61
- blue: '\x1b[34m',
62
- yellow: '\x1b[33m',
63
- red: '\x1b[31m',
64
- magenta: '\x1b[35m',
65
- reset: '\x1b[0m',
66
- };
67
-
68
- // Log level configuration
69
- enum LogLevelValue {
70
- TRACE = 0,
71
- DEBUG = 1,
72
- INFO = 2,
73
- WARN = 3,
74
- ERROR = 4,
75
- }
76
-
77
- const logLevelMap: Record<string, LogLevelValue> = {
78
- [LogLevel.Verbose]: LogLevelValue.TRACE,
79
- [LogLevel.Debug]: LogLevelValue.DEBUG,
80
- [LogLevel.Info]: LogLevelValue.INFO,
81
- [LogLevel.Warning]: LogLevelValue.WARN,
82
- [LogLevel.Error]: LogLevelValue.ERROR,
83
- // Add trace as an alias for verbose
84
- trace: LogLevelValue.TRACE,
85
- };
86
-
87
- const levelColors: Record<string, string> = {
88
- trace: colors.magenta,
89
- debug: colors.cyan,
90
- info: colors.blue,
91
- warn: colors.yellow,
92
- error: colors.red,
93
- };
94
-
95
- export interface Logger {
96
- trace: (message: any, ...args: any[]) => void;
97
- debug: (message: any, ...args: any[]) => void;
98
- info: (message: any, ...args: any[]) => void;
99
- warn: (message: any, ...args: any[]) => void;
100
- error: (message: any, ...args: any[]) => void;
101
- }
102
-
103
- /**
104
- * Formats the current time as HH:MM:SS for log output.
105
- * Optimized to avoid unnecessary string conversions.
106
- */
107
- const formatTimestamp = (): string => {
108
- const now = new Date();
109
- const hours = now.getHours().toString().padStart(2, '0');
110
- const minutes = now.getMinutes().toString().padStart(2, '0');
111
- const seconds = now.getSeconds().toString().padStart(2, '0');
112
- return `${hours}:${minutes}:${seconds}`;
113
- };
114
-
115
- /**
116
- * Custom JSON replacer function that handles BigInt values by converting them to strings.
117
- * This ensures BigInt values can be serialized in JSON logs.
118
- */
119
- const bigintReplacer = (_key: string, value: any): any => {
120
- if (typeof value === 'bigint') {
121
- return value.toString();
122
- }
123
- return value;
124
- };
125
-
126
- /**
127
- * Resets all internal caches. Used for testing to ensure a clean state.
128
- */
129
- export const resetLoggerInitialization = (): void => {
130
- regexCache.clear();
131
- debugPatternCache.clear();
132
- };
133
-
134
- /**
135
- * Creates a logger instance for the specified module name.
136
- * The logger respects DEBUG, LOG_LEVEL, and UNCHAINED_LOG_FORMAT environment variables.
137
- *
138
- * Performance optimizations:
139
- * - Returns no-op functions for disabled log levels (zero-cost logging)
140
- * - Caches regex patterns and debug results for fast pattern matching
141
- *
142
- * @param moduleName - The name of the module (used for filtering and display)
143
- * @returns A logger instance with trace, debug, info, warn, and error methods
144
- */
145
- export const createLogger = (moduleName: string): Logger => {
146
- const { DEBUG = '', LOG_LEVEL = LogLevel.Info, UNCHAINED_LOG_FORMAT = 'unchained' } = process.env;
147
-
148
- // Validate format at logger creation time
149
- const format = UNCHAINED_LOG_FORMAT.toLowerCase();
150
- if (format !== 'json' && format !== 'unchained') {
151
- throw new Error(`UNCHAINED_LOG_FORMAT is invalid, use one of json,unchained`);
152
- }
153
-
154
- // Determine minimum log level
155
- const loggingMatched = debugStringContainsModule(DEBUG, moduleName);
156
- const logLevelLower = LOG_LEVEL.toLowerCase();
157
- const mappedLevel = logLevelMap[logLevelLower];
158
- const minLevel = loggingMatched
159
- ? LogLevelValue.DEBUG
160
- : mappedLevel !== undefined
161
- ? mappedLevel
162
- : LogLevelValue.INFO;
163
-
164
- // Performance optimization: No-op function for disabled log levels
165
- const noop = () => {
166
- // Intentionally empty for performance
167
- };
168
-
169
- const log = (level: string, levelValue: LogLevelValue, message: any, ...args: any[]) => {
170
- if (levelValue < minLevel) return;
171
-
172
- if (format === 'json') {
173
- // JSON format
174
- const logObject: any = {
175
- timestamp: new Date().toISOString(),
176
- level: level.toUpperCase(),
177
- name: moduleName,
178
- message: typeof message === 'string' ? message : message,
179
- };
180
-
181
- // Merge additional args if they're objects, guarding against prototype pollution
182
- if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {
183
- for (const key in args[0]) {
184
- // Skip prototype pollution vectors
185
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;
186
- logObject[key] = args[0][key];
187
- }
188
- }
189
-
190
- // Use safe-stable-stringify for proper JSON output with BigInt support
191
- console.log(stringify(logObject, bigintReplacer));
192
- } else {
193
- // Unchained format (pretty)
194
- const timestamp = formatTimestamp();
195
- const levelColor = levelColors[level] || colors.reset;
196
- const prefix = `${colors.gray}${timestamp}${colors.reset} [${colors.green}${moduleName}${colors.reset}] ${levelColor}${level}:${colors.reset}`;
197
-
198
- if (typeof message === 'string') {
199
- console.log(prefix, message, ...args);
200
- } else {
201
- console.log(prefix, inspect(message, { colors: true, depth: 3 }), ...args);
202
- }
203
- }
204
- };
205
-
206
- return {
207
- trace:
208
- LogLevelValue.TRACE < minLevel
209
- ? noop
210
- : (message: any, ...args: any[]) => log('trace', LogLevelValue.TRACE, message, ...args),
211
- debug:
212
- LogLevelValue.DEBUG < minLevel
213
- ? noop
214
- : (message: any, ...args: any[]) => log('debug', LogLevelValue.DEBUG, message, ...args),
215
- info:
216
- LogLevelValue.INFO < minLevel
217
- ? noop
218
- : (message: any, ...args: any[]) => log('info', LogLevelValue.INFO, message, ...args),
219
- warn:
220
- LogLevelValue.WARN < minLevel
221
- ? noop
222
- : (message: any, ...args: any[]) => log('warn', LogLevelValue.WARN, message, ...args),
223
- error:
224
- LogLevelValue.ERROR < minLevel
225
- ? noop
226
- : (message: any, ...args: any[]) => log('error', LogLevelValue.ERROR, message, ...args),
227
- };
228
- };
package/src/log.ts DELETED
@@ -1,7 +0,0 @@
1
- import { createLogger } from './createLogger.js';
2
-
3
- const logger = createLogger('unchained');
4
-
5
- export const defaultLogger = logger;
6
-
7
- export const log = logger.info;
@@ -1,3 +0,0 @@
1
- export * from './createLogger.js';
2
- export * from './logger.types.js';
3
- export * from './log.js';
@@ -1,7 +0,0 @@
1
- export enum LogLevel {
2
- Verbose = 'verbose',
3
- Info = 'info',
4
- Debug = 'debug',
5
- Error = 'error',
6
- Warning = 'warn',
7
- }