@unchainedshop/logger 4.0.0-rc.17 → 4.0.0-rc.19

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/README.md CHANGED
@@ -1,5 +1,97 @@
1
1
  # Logger (Unchained Engine)
2
2
 
3
- This package handles logging for all modules.
3
+ A high-performance, feature-rich logging package for Unchained Engine with support for multiple formats, log levels, and debug patterns.
4
4
 
5
- It exports two actions _log_ and _createLogger_ to log information based on the initial logger configuration.
5
+ ## Features
6
+
7
+ - 🚀 **High Performance**: Optimized for speed with caching and no-op functions for disabled log levels
8
+ - 🎨 **Multiple Formats**: Support for both human-readable (unchained) and JSON formats
9
+ - 🔍 **Debug Patterns**: Flexible DEBUG environment variable with wildcards and exclusions
10
+ - 📊 **Log Levels**: Five log levels (trace, debug, info, warn, error) with environment-based filtering
11
+ - 💪 **TypeScript**: Full TypeScript support with type definitions
12
+ - 🔧 **Zero Dependencies**: Core functionality with minimal external dependencies
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @unchainedshop/logger
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Basic Usage
23
+
24
+ ```typescript
25
+ import { createLogger } from '@unchainedshop/logger';
26
+
27
+ const logger = createLogger('my-module');
28
+
29
+ logger.info('Application started');
30
+ logger.debug('Debug information', { userId: 123 });
31
+ logger.error('Something went wrong', new Error('Details'));
32
+ ```
33
+
34
+ ### Environment Variables
35
+
36
+ #### `UNCHAINED_LOG_FORMAT`
37
+ Controls the output format:
38
+ - `unchained` (default): Human-readable format with colors
39
+ - `json`: Machine-readable JSON format
40
+
41
+ ```bash
42
+ UNCHAINED_LOG_FORMAT=json node app.js
43
+ ```
44
+
45
+ #### `LOG_LEVEL`
46
+ Sets the minimum log level:
47
+ - `verbose` or `trace`: All logs
48
+ - `debug`: Debug and above
49
+ - `info` (default): Info and above
50
+ - `warn`: Warnings and errors only
51
+ - `error`: Errors only
52
+
53
+ ```bash
54
+ LOG_LEVEL=debug node app.js
55
+ ```
56
+
57
+ #### `DEBUG`
58
+ Enables debug logging for specific modules using pattern matching:
59
+ - Wildcards: `DEBUG=app:*`
60
+ - Exclusions: `DEBUG=*,-app:excluded`
61
+ - Multiple patterns: `DEBUG=app:*,core:*`
62
+
63
+ ```bash
64
+ DEBUG=my-module,other:* node app.js
65
+ ```
66
+
67
+ ## API
68
+
69
+ ### `createLogger(moduleName: string): Logger`
70
+
71
+ Creates a logger instance for the specified module.
72
+
73
+ **Parameters:**
74
+ - `moduleName` - The name of the module (used for filtering and display)
75
+
76
+ **Returns:** Logger instance with methods: `trace`, `debug`, `info`, `warn`, `error`
77
+
78
+ ### Default Logger
79
+
80
+ ```typescript
81
+ import { log, defaultLogger } from '@unchainedshop/logger';
82
+
83
+ // Quick logging with default logger
84
+ log('Quick info message');
85
+
86
+ // Or use the default logger directly
87
+ defaultLogger.info('Info message');
88
+ ```
89
+
90
+ ## Performance
91
+
92
+ See [benchmarks/README.md](./benchmarks/README.md) for detailed performance metrics.
93
+
94
+ Key performance features:
95
+ - **Zero-cost disabled logging**: Log levels below the minimum use no-op functions
96
+ - **Regex caching**: Pattern matching results are cached for speed
97
+ - **Optimized hot paths**: Critical logging paths are optimized for maximum throughput
@@ -0,0 +1,32 @@
1
+ # Logger Performance Benchmarks
2
+
3
+ Run with: `npm run benchmark`
4
+
5
+ ## Latest Results (October 7, 2025)
6
+
7
+ ```
8
+ Test Name | Ops/sec | Avg Time | Total Time
9
+ ---------------------------------|--------------|--------------|-------------
10
+ Logger creation (default format) | 935.97K | 0.001 ms | 1.07 ms
11
+ Logger creation (JSON format) | 1.27M | 0.79 µs | 0.79 ms
12
+ Log info (default format) | 8.15M | 0.12 µs | 12.28 ms
13
+ Log info (JSON format) | 1.25M | 0.80 µs | 79.87 ms
14
+ Log complex object (JSON) | 465.65K | 0.002 ms | 21.48 ms
15
+ Debug log (enabled) | 8.34M | 0.12 µs | 11.99 ms
16
+ Debug log (disabled) | 299.36M | 0.00 µs | 0.33 ms
17
+ Pattern matching (createLogger) | 1.21M | 0.82 µs | 4.12 ms
18
+ ```
19
+
20
+ ## Key Insights
21
+
22
+ - JSON format logging is **550.6% slower** than default format
23
+ - Debug logging when disabled is **35.9x faster** (skips log processing entirely)
24
+ - Fastest: Debug log (disabled) at 299.36M ops/s
25
+ - Slowest: Complex object logging at 465.65K ops/s
26
+
27
+ ## Optimizations
28
+
29
+ The current implementation includes targeted optimizations:
30
+ - **Regex pattern caching**: Compiled RegExp objects are cached to avoid recreation
31
+ - **Pattern result caching**: DEBUG pattern matching results are cached per module
32
+ - **No-op functions**: Disabled log levels return empty functions for zero-cost logging
@@ -0,0 +1,273 @@
1
+ import { performance } from 'node:perf_hooks';
2
+ import { createLogger, resetLoggerInitialization } from '../src/createLogger.js';
3
+
4
+ interface BenchmarkResult {
5
+ name: string;
6
+ totalTime: number;
7
+ operations: number;
8
+ opsPerSecond: number;
9
+ avgTimeMs: number;
10
+ }
11
+
12
+ class LoggerBenchmark {
13
+ private originalConsole = {
14
+ log: console.log,
15
+ info: console.info,
16
+ warn: console.warn,
17
+ error: console.error,
18
+ debug: console.debug,
19
+ };
20
+
21
+ private suppressConsole() {
22
+ const noop = () => {
23
+ /* intentionally empty */
24
+ };
25
+ console.log = noop;
26
+ console.info = noop;
27
+ console.warn = noop;
28
+ console.error = noop;
29
+ console.debug = noop;
30
+ }
31
+
32
+ private restoreConsole() {
33
+ Object.assign(console, this.originalConsole);
34
+ }
35
+
36
+ private benchmark(name: string, iterations: number, fn: () => void): BenchmarkResult {
37
+ // Warm-up phase
38
+ for (let i = 0; i < Math.min(100, iterations / 10); i++) {
39
+ fn();
40
+ }
41
+
42
+ // Actual benchmark
43
+ const start = performance.now();
44
+ for (let i = 0; i < iterations; i++) {
45
+ fn();
46
+ }
47
+ const totalTime = performance.now() - start;
48
+
49
+ return {
50
+ name,
51
+ totalTime,
52
+ operations: iterations,
53
+ opsPerSecond: (iterations / totalTime) * 1000,
54
+ avgTimeMs: totalTime / iterations,
55
+ };
56
+ }
57
+
58
+ async run() {
59
+ this.restoreConsole();
60
+ console.log('🚀 Logger Performance Benchmark\n');
61
+ console.log('Running benchmarks...\n');
62
+
63
+ const results: BenchmarkResult[] = [];
64
+
65
+ // Test 1: Logger creation performance
66
+ this.suppressConsole();
67
+ resetLoggerInitialization();
68
+ delete process.env.UNCHAINED_LOG_FORMAT;
69
+ delete process.env.DEBUG;
70
+ delete process.env.LOG_LEVEL;
71
+
72
+ results.push(
73
+ this.benchmark('Logger creation (default format)', 1000, () => {
74
+ createLogger(`module-${Math.random()}`);
75
+ }),
76
+ );
77
+
78
+ // Test 2: Logger creation with JSON format
79
+ resetLoggerInitialization();
80
+ process.env.UNCHAINED_LOG_FORMAT = 'json';
81
+
82
+ results.push(
83
+ this.benchmark('Logger creation (JSON format)', 1000, () => {
84
+ createLogger(`module-json-${Math.random()}`);
85
+ }),
86
+ );
87
+
88
+ // Test 3: Logging performance - default format
89
+ resetLoggerInitialization();
90
+ delete process.env.UNCHAINED_LOG_FORMAT;
91
+ const defaultLogger = createLogger('benchmark');
92
+
93
+ results.push(
94
+ this.benchmark('Log info (default format)', 100000, () => {
95
+ defaultLogger.info('Test message');
96
+ }),
97
+ );
98
+
99
+ // Test 4: Logging performance - JSON format
100
+ resetLoggerInitialization();
101
+ process.env.UNCHAINED_LOG_FORMAT = 'json';
102
+ const jsonLogger = createLogger('benchmark-json');
103
+
104
+ results.push(
105
+ this.benchmark('Log info (JSON format)', 100000, () => {
106
+ jsonLogger.info('Test message', { id: 123 });
107
+ }),
108
+ );
109
+
110
+ // Test 5: Complex object logging
111
+ const complexObject = {
112
+ user: { id: 'user123', name: 'John Doe', roles: ['admin', 'user'] },
113
+ action: 'purchase',
114
+ items: [
115
+ { id: 'item1', name: 'Product A', price: 99.99, quantity: 2 },
116
+ { id: 'item2', name: 'Product B', price: 49.99, quantity: 1 },
117
+ ],
118
+ metadata: {
119
+ timestamp: new Date().toISOString(),
120
+ source: 'web',
121
+ version: '1.0.0',
122
+ },
123
+ };
124
+
125
+ results.push(
126
+ this.benchmark('Log complex object (JSON)', 10000, () => {
127
+ jsonLogger.info('Complex operation', complexObject);
128
+ }),
129
+ );
130
+
131
+ // Test 6: Debug logging when enabled
132
+ resetLoggerInitialization();
133
+ delete process.env.UNCHAINED_LOG_FORMAT;
134
+ process.env.DEBUG = 'benchmark-debug';
135
+ const debugEnabledLogger = createLogger('benchmark-debug');
136
+
137
+ results.push(
138
+ this.benchmark('Debug log (enabled)', 100000, () => {
139
+ debugEnabledLogger.debug('Debug message');
140
+ }),
141
+ );
142
+
143
+ // Test 7: Debug logging when disabled
144
+ resetLoggerInitialization();
145
+ process.env.DEBUG = 'other-module';
146
+ const debugDisabledLogger = createLogger('benchmark-no-debug');
147
+
148
+ results.push(
149
+ this.benchmark('Debug log (disabled)', 100000, () => {
150
+ debugDisabledLogger.debug('Debug message');
151
+ }),
152
+ );
153
+
154
+ // Test 8: Pattern matching performance
155
+ resetLoggerInitialization();
156
+ process.env.DEBUG = 'app:*,!app:excluded,special-*,test:module:*';
157
+ const testModules = [
158
+ 'app:users',
159
+ 'app:excluded',
160
+ 'special-feature',
161
+ 'test:module:sub',
162
+ 'other:module',
163
+ ];
164
+
165
+ results.push(
166
+ this.benchmark('Pattern matching (createLogger)', 5000, () => {
167
+ const module = testModules[Math.floor(Math.random() * testModules.length)];
168
+ createLogger(module);
169
+ }),
170
+ );
171
+
172
+ this.restoreConsole();
173
+ this.printResults(results);
174
+ }
175
+
176
+ private printResults(results: BenchmarkResult[]) {
177
+ console.log('\n📊 Benchmark Results:\n');
178
+
179
+ // Header
180
+ const cols = {
181
+ name: 'Test Name',
182
+ ops: 'Ops/sec',
183
+ avgTime: 'Avg Time',
184
+ total: 'Total Time',
185
+ };
186
+
187
+ const widths = {
188
+ name: Math.max(cols.name.length, ...results.map((r) => r.name.length)),
189
+ ops: 12,
190
+ avgTime: 12,
191
+ total: 12,
192
+ };
193
+
194
+ // Print header
195
+ console.log(
196
+ `${cols.name.padEnd(widths.name)} | ${cols.ops.padStart(widths.ops)} | ${cols.avgTime.padStart(
197
+ widths.avgTime,
198
+ )} | ${cols.total.padStart(widths.total)}`,
199
+ );
200
+ console.log(
201
+ `${'-'.repeat(widths.name)}-|-${'-'.repeat(widths.ops)}-|-${'-'.repeat(widths.avgTime)}-|-${'-'.repeat(widths.total)}`,
202
+ );
203
+
204
+ // Print results
205
+ for (const result of results) {
206
+ const opsPerSec = this.formatNumber(result.opsPerSecond);
207
+ const avgTime = this.formatTime(result.avgTimeMs);
208
+ const totalTime = `${result.totalTime.toFixed(2)} ms`;
209
+
210
+ console.log(
211
+ `${result.name.padEnd(widths.name)} | ${opsPerSec.padStart(widths.ops)} | ${avgTime.padStart(
212
+ widths.avgTime,
213
+ )} | ${totalTime.padStart(widths.total)}`,
214
+ );
215
+ }
216
+
217
+ // Performance insights
218
+ console.log('\n💡 Performance Insights:\n');
219
+
220
+ // Compare format performance
221
+ const defaultLog = results.find((r) => r.name === 'Log info (default format)');
222
+ const jsonLog = results.find((r) => r.name === 'Log info (JSON format)');
223
+ if (defaultLog && jsonLog) {
224
+ const diff = ((jsonLog.avgTimeMs - defaultLog.avgTimeMs) / defaultLog.avgTimeMs) * 100;
225
+ console.log(
226
+ `• JSON format logging is ${Math.abs(diff).toFixed(1)}% ${diff > 0 ? 'slower' : 'faster'} than default format`,
227
+ );
228
+ }
229
+
230
+ // Compare debug enabled vs disabled
231
+ const debugEnabled = results.find((r) => r.name === 'Debug log (enabled)');
232
+ const debugDisabled = results.find((r) => r.name === 'Debug log (disabled)');
233
+ if (debugEnabled && debugDisabled) {
234
+ const speedup = debugEnabled.avgTimeMs / debugDisabled.avgTimeMs;
235
+ console.log(
236
+ `• Debug logging when disabled is ${speedup.toFixed(1)}x faster (skips log processing entirely)`,
237
+ );
238
+ }
239
+
240
+ // Find fastest and slowest
241
+ const sorted = [...results].sort((a, b) => b.opsPerSecond - a.opsPerSecond);
242
+ console.log(
243
+ `• Fastest operation: ${sorted[0].name} (${this.formatNumber(sorted[0].opsPerSecond)} ops/s)`,
244
+ );
245
+ console.log(
246
+ `• Slowest operation: ${sorted[sorted.length - 1].name} (${this.formatNumber(
247
+ sorted[sorted.length - 1].opsPerSecond,
248
+ )} ops/s)`,
249
+ );
250
+
251
+ // Memory note
252
+ console.log(
253
+ `\n📝 Note: These benchmarks measure execution speed. Memory usage and garbage collection`,
254
+ );
255
+ console.log(` impact are not measured but may be important factors in production environments.`);
256
+ }
257
+
258
+ private formatNumber(num: number): string {
259
+ if (num >= 1000000) return `${(num / 1000000).toFixed(2)}M`;
260
+ if (num >= 1000) return `${(num / 1000).toFixed(2)}K`;
261
+ return num.toFixed(0);
262
+ }
263
+
264
+ private formatTime(ms: number): string {
265
+ if (ms < 0.001) return `${(ms * 1000).toFixed(2)} µs`;
266
+ if (ms < 1) return `${ms.toFixed(3)} ms`;
267
+ return `${ms.toFixed(2)} ms`;
268
+ }
269
+ }
270
+
271
+ // Run benchmark
272
+ const benchmark = new LoggerBenchmark();
273
+ benchmark.run().catch(console.error);
@@ -1,3 +1,24 @@
1
- import { default as log } from 'loglevel';
2
- export declare const createLogger: (moduleName: string) => log.Logger;
1
+ export interface Logger {
2
+ trace: (message: any, ...args: any[]) => void;
3
+ debug: (message: any, ...args: any[]) => void;
4
+ info: (message: any, ...args: any[]) => void;
5
+ warn: (message: any, ...args: any[]) => void;
6
+ error: (message: any, ...args: any[]) => void;
7
+ }
8
+ /**
9
+ * Resets all internal caches. Used for testing to ensure a clean state.
10
+ */
11
+ 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
+ export declare const createLogger: (moduleName: string) => Logger;
3
24
  //# sourceMappingURL=createLogger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createLogger.d.ts","sourceRoot":"","sources":["../src/createLogger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAC;AAsE1C,eAAO,MAAM,YAAY,GAAI,YAAY,MAAM,eAc9C,CAAC"}
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"}