@rawnodes/logger 1.0.0 → 1.1.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 (48) hide show
  1. package/dist/index.cjs +386 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +103 -0
  4. package/dist/index.d.ts +103 -6
  5. package/dist/index.js +369 -6
  6. package/dist/index.js.map +1 -1
  7. package/package.json +8 -5
  8. package/dist/formatters.d.ts +0 -7
  9. package/dist/formatters.d.ts.map +0 -1
  10. package/dist/formatters.js +0 -37
  11. package/dist/formatters.js.map +0 -1
  12. package/dist/index.d.ts.map +0 -1
  13. package/dist/logger.d.ts +0 -30
  14. package/dist/logger.d.ts.map +0 -1
  15. package/dist/logger.js +0 -131
  16. package/dist/logger.js.map +0 -1
  17. package/dist/singleton.d.ts +0 -15
  18. package/dist/singleton.d.ts.map +0 -1
  19. package/dist/singleton.js +0 -40
  20. package/dist/singleton.js.map +0 -1
  21. package/dist/store.d.ts +0 -7
  22. package/dist/store.d.ts.map +0 -1
  23. package/dist/store.js +0 -11
  24. package/dist/store.js.map +0 -1
  25. package/dist/transports.d.ts +0 -7
  26. package/dist/transports.d.ts.map +0 -1
  27. package/dist/transports.js +0 -22
  28. package/dist/transports.js.map +0 -1
  29. package/dist/types.d.ts +0 -23
  30. package/dist/types.d.ts.map +0 -1
  31. package/dist/types.js +0 -2
  32. package/dist/types.js.map +0 -1
  33. package/dist/utils/index.d.ts +0 -4
  34. package/dist/utils/index.d.ts.map +0 -1
  35. package/dist/utils/index.js +0 -4
  36. package/dist/utils/index.js.map +0 -1
  37. package/dist/utils/mask-secrets.d.ts +0 -8
  38. package/dist/utils/mask-secrets.d.ts.map +0 -1
  39. package/dist/utils/mask-secrets.js +0 -69
  40. package/dist/utils/mask-secrets.js.map +0 -1
  41. package/dist/utils/request-id.d.ts +0 -8
  42. package/dist/utils/request-id.d.ts.map +0 -1
  43. package/dist/utils/request-id.js +0 -24
  44. package/dist/utils/request-id.js.map +0 -1
  45. package/dist/utils/timing.d.ts +0 -18
  46. package/dist/utils/timing.d.ts.map +0 -1
  47. package/dist/utils/timing.js +0 -37
  48. package/dist/utils/timing.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,7 +1,370 @@
1
- // Core
2
- export { BaseLogger } from './logger.js';
3
- export { createSingletonLogger } from './singleton.js';
4
- export { LoggerStore } from './store.js';
5
- // Utilities
6
- export { createTimer, measureAsync, measureSync, generateRequestId, extractRequestId, getOrGenerateRequestId, maskSecrets, createMasker, } from './utils/index.js';
1
+ import { createLogger, transports, format } from 'winston';
2
+ import { inspect } from 'util';
3
+ import DailyRotateFile from 'winston-daily-rotate-file';
4
+ import { AsyncLocalStorage } from 'async_hooks';
5
+ import { randomUUID } from 'crypto';
6
+
7
+ // src/logger.ts
8
+ var DEFAULT_CONTEXT = "APP";
9
+ function formatMeta(meta, colors) {
10
+ return Object.entries(meta).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => {
11
+ if (typeof value === "object") {
12
+ const inspected = inspect(value, { depth: 4, colors, compact: false });
13
+ return `
14
+ ${key}: ${inspected.split("\n").join("\n ")}`;
15
+ }
16
+ return `
17
+ ${key}: ${value}`;
18
+ }).join("");
19
+ }
20
+ function addStoreContext(store) {
21
+ return format((info) => {
22
+ const storeContext = store.getStore();
23
+ if (storeContext) {
24
+ return { ...info, ...storeContext };
25
+ }
26
+ return info;
27
+ })();
28
+ }
29
+ function createLocalFormat(store) {
30
+ return format.combine(
31
+ format.errors({ stack: true }),
32
+ format.timestamp(),
33
+ addStoreContext(store),
34
+ format.colorize(),
35
+ format.printf(({ timestamp, level, context, message, ...meta }) => {
36
+ const formattedMeta = formatMeta(meta, true);
37
+ return `[${timestamp}] ${level} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;
38
+ })
39
+ );
40
+ }
41
+ function createProductionFormat(store) {
42
+ return format.combine(
43
+ format.errors({ stack: true }),
44
+ format.timestamp(),
45
+ addStoreContext(store),
46
+ format.json()
47
+ );
48
+ }
49
+ function createFormat(isLocal, store) {
50
+ return isLocal ? createLocalFormat(store) : createProductionFormat(store);
51
+ }
52
+ function createTransports(config) {
53
+ const result = [
54
+ new transports.Console({
55
+ level: config.console.level
56
+ })
57
+ ];
58
+ if (config.file) {
59
+ result.push(
60
+ new DailyRotateFile({
61
+ dirname: config.file.dirname,
62
+ filename: config.file.filename,
63
+ level: config.file.level,
64
+ datePattern: config.file.datePattern,
65
+ zippedArchive: config.file.zippedArchive,
66
+ maxSize: config.file.maxSize,
67
+ maxFiles: config.file.maxFiles
68
+ })
69
+ );
70
+ }
71
+ return result;
72
+ }
73
+ var LoggerStore = class {
74
+ storage = new AsyncLocalStorage();
75
+ getStore() {
76
+ return this.storage.getStore();
77
+ }
78
+ run(context, fn) {
79
+ return this.storage.run(context, fn);
80
+ }
81
+ };
82
+
83
+ // src/utils/timing.ts
84
+ function formatDuration(ms) {
85
+ if (ms < 1e3) {
86
+ return `${ms.toFixed(2)}ms`;
87
+ }
88
+ if (ms < 6e4) {
89
+ return `${(ms / 1e3).toFixed(2)}s`;
90
+ }
91
+ const minutes = Math.floor(ms / 6e4);
92
+ const seconds = (ms % 6e4 / 1e3).toFixed(1);
93
+ return `${minutes}m ${seconds}s`;
94
+ }
95
+ function createTimer(label) {
96
+ const start = performance.now();
97
+ return {
98
+ end() {
99
+ const durationMs = performance.now() - start;
100
+ return {
101
+ label,
102
+ durationMs,
103
+ durationFormatted: formatDuration(durationMs)
104
+ };
105
+ }
106
+ };
107
+ }
108
+ async function measureAsync(label, fn) {
109
+ const timer = createTimer(label);
110
+ const result = await fn();
111
+ const timing = timer.end();
112
+ return { result, timing };
113
+ }
114
+ function measureSync(label, fn) {
115
+ const timer = createTimer(label);
116
+ const result = fn();
117
+ const timing = timer.end();
118
+ return { result, timing };
119
+ }
120
+
121
+ // src/logger.ts
122
+ var DEFAULT_CONTEXT2 = "APP";
123
+ var LOG_LEVELS = {
124
+ error: 0,
125
+ warn: 1,
126
+ info: 2,
127
+ http: 3,
128
+ verbose: 4,
129
+ debug: 5,
130
+ silly: 6
131
+ };
132
+ var BaseLogger = class {
133
+ winstonLogger;
134
+ defaultLevel;
135
+ store;
136
+ levelOverrides = /* @__PURE__ */ new Map();
137
+ constructor(config, store) {
138
+ const isLocal = process.env.NODE_ENV !== "production";
139
+ this.defaultLevel = config.level;
140
+ this.store = store ?? new LoggerStore();
141
+ this.winstonLogger = createLogger({
142
+ level: "silly",
143
+ // Allow all, we filter manually
144
+ format: createFormat(isLocal, this.store),
145
+ transports: createTransports(config)
146
+ });
147
+ }
148
+ getStore() {
149
+ return this.store;
150
+ }
151
+ setLevelOverride(match, level) {
152
+ const key = JSON.stringify(match);
153
+ this.levelOverrides.set(key, { match, level });
154
+ }
155
+ removeLevelOverride(match) {
156
+ const key = JSON.stringify(match);
157
+ this.levelOverrides.delete(key);
158
+ }
159
+ clearLevelOverrides() {
160
+ this.levelOverrides.clear();
161
+ }
162
+ getLevelOverrides() {
163
+ return Array.from(this.levelOverrides.values());
164
+ }
165
+ getEffectiveLevel() {
166
+ const context = this.store.getStore();
167
+ if (!context) return this.defaultLevel;
168
+ for (const { match, level } of this.levelOverrides.values()) {
169
+ if (this.matchesContext(context, match)) {
170
+ return level;
171
+ }
172
+ }
173
+ return this.defaultLevel;
174
+ }
175
+ matchesContext(context, match) {
176
+ return Object.entries(match).every(([key, value]) => context[key] === value);
177
+ }
178
+ shouldLog(level) {
179
+ const effectiveLevel = this.getEffectiveLevel();
180
+ return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];
181
+ }
182
+ getChildLogger(context) {
183
+ return this.winstonLogger.child({ context });
184
+ }
185
+ time(label) {
186
+ return createTimer(label);
187
+ }
188
+ timeEnd(timer, context) {
189
+ const result = timer.end();
190
+ this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {
191
+ timing: result
192
+ });
193
+ return result;
194
+ }
195
+ async timeAsync(label, fn, context) {
196
+ const timer = this.time(label);
197
+ try {
198
+ const result = await fn();
199
+ this.timeEnd(timer, context);
200
+ return result;
201
+ } catch (error) {
202
+ const timing = timer.end();
203
+ this.error(`${label} failed after ${timing.durationFormatted}`, error, context);
204
+ throw error;
205
+ }
206
+ }
207
+ log(message, context, meta) {
208
+ if (!this.shouldLog("info")) return;
209
+ this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT2, ...meta });
210
+ }
211
+ error(message, error, context) {
212
+ if (!this.shouldLog("error")) return;
213
+ const meta = { context: context || DEFAULT_CONTEXT2 };
214
+ if (error instanceof Error) {
215
+ meta.errorMessage = error.message;
216
+ meta.errorStack = error.stack;
217
+ } else if (error) {
218
+ meta.error = error;
219
+ }
220
+ this.winstonLogger.error(message, meta);
221
+ }
222
+ warn(message, context, meta) {
223
+ if (!this.shouldLog("warn")) return;
224
+ this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT2, ...meta });
225
+ }
226
+ debug(message, context, meta) {
227
+ if (!this.shouldLog("debug")) return;
228
+ this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT2, ...meta });
229
+ }
230
+ info(message, context, meta) {
231
+ if (!this.shouldLog("info")) return;
232
+ this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT2, ...meta });
233
+ }
234
+ verbose(message, context, meta) {
235
+ if (!this.shouldLog("verbose")) return;
236
+ this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT2, ...meta });
237
+ }
238
+ };
239
+
240
+ // src/singleton.ts
241
+ function createSingletonLogger() {
242
+ let instance = null;
243
+ const ensureInstance = () => {
244
+ if (!instance) {
245
+ throw new Error("Logger not initialized. Call getInstance(config) first.");
246
+ }
247
+ return instance;
248
+ };
249
+ return {
250
+ getInstance(config) {
251
+ if (!instance) {
252
+ if (!config) {
253
+ throw new Error("Logger config is required for first initialization");
254
+ }
255
+ instance = new BaseLogger(config);
256
+ }
257
+ return instance;
258
+ },
259
+ getStore() {
260
+ return ensureInstance().getStore();
261
+ },
262
+ for(context) {
263
+ return ensureInstance().getChildLogger(context);
264
+ },
265
+ setLevelOverride(match, level) {
266
+ ensureInstance().setLevelOverride(match, level);
267
+ },
268
+ removeLevelOverride(match) {
269
+ ensureInstance().removeLevelOverride(match);
270
+ },
271
+ getLevelOverrides() {
272
+ return ensureInstance().getLevelOverrides();
273
+ },
274
+ clearLevelOverrides() {
275
+ ensureInstance().clearLevelOverrides();
276
+ }
277
+ };
278
+ }
279
+ function generateRequestId(options = {}) {
280
+ const { prefix, short = false } = options;
281
+ const uuid = randomUUID();
282
+ const id = short ? uuid.split("-")[0] : uuid;
283
+ return prefix ? `${prefix}-${id}` : id;
284
+ }
285
+ function extractRequestId(headers) {
286
+ const headerNames = ["x-request-id", "x-correlation-id", "x-trace-id"];
287
+ for (const name of headerNames) {
288
+ const value = headers[name];
289
+ if (typeof value === "string" && value.length > 0) {
290
+ return value;
291
+ }
292
+ if (Array.isArray(value) && value.length > 0) {
293
+ return value[0];
294
+ }
295
+ }
296
+ return void 0;
297
+ }
298
+ function getOrGenerateRequestId(headers, options = {}) {
299
+ return extractRequestId(headers) ?? generateRequestId(options);
300
+ }
301
+
302
+ // src/utils/mask-secrets.ts
303
+ var DEFAULT_SECRET_PATTERNS = [
304
+ "password",
305
+ "secret",
306
+ "token",
307
+ "apikey",
308
+ "api_key",
309
+ "api-key",
310
+ "auth",
311
+ "credential",
312
+ "private"
313
+ ];
314
+ var DEFAULT_MASK = "***";
315
+ function isSecretKey(key, patterns) {
316
+ const lowerKey = key.toLowerCase();
317
+ return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
318
+ }
319
+ function maskUrlCredentials(url, mask) {
320
+ try {
321
+ const parsed = new URL(url);
322
+ if (parsed.password) {
323
+ parsed.password = mask;
324
+ }
325
+ if (parsed.username && parsed.password) {
326
+ parsed.username = mask;
327
+ }
328
+ return parsed.toString();
329
+ } catch {
330
+ return url;
331
+ }
332
+ }
333
+ function maskSecrets(obj, options = {}) {
334
+ const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
335
+ if (obj === null || obj === void 0) {
336
+ return obj;
337
+ }
338
+ if (typeof obj === "string") {
339
+ if (obj.startsWith("http://") || obj.startsWith("https://")) {
340
+ return maskUrlCredentials(obj, mask);
341
+ }
342
+ return obj;
343
+ }
344
+ if (Array.isArray(obj)) {
345
+ return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
346
+ }
347
+ if (typeof obj === "object") {
348
+ const result = {};
349
+ for (const [key, value] of Object.entries(obj)) {
350
+ if (isSecretKey(key, patterns)) {
351
+ result[key] = mask;
352
+ } else if (deep && typeof value === "object" && value !== null) {
353
+ result[key] = maskSecrets(value, options);
354
+ } else if (typeof value === "string") {
355
+ result[key] = maskSecrets(value, options);
356
+ } else {
357
+ result[key] = value;
358
+ }
359
+ }
360
+ return result;
361
+ }
362
+ return obj;
363
+ }
364
+ function createMasker(options = {}) {
365
+ return (obj) => maskSecrets(obj, options);
366
+ }
367
+
368
+ export { BaseLogger, LoggerStore, createMasker, createSingletonLogger, createTimer, extractRequestId, generateRequestId, getOrGenerateRequestId, maskSecrets, measureAsync, measureSync };
369
+ //# sourceMappingURL=index.js.map
7
370
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO;AACP,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAwB,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAWzC,YAAY;AACZ,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EAGX,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EAEtB,WAAW,EACX,YAAY,GAEb,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"sources":["../src/formatters.ts","../src/transports.ts","../src/store.ts","../src/utils/timing.ts","../src/logger.ts","../src/singleton.ts","../src/utils/request-id.ts","../src/utils/mask-secrets.ts"],"names":["DEFAULT_CONTEXT"],"mappings":"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","file":"index.js","sourcesContent":["import { inspect } from 'util';\nimport { format, Logform } from 'winston';\nimport { LoggerStore } from './store.js';\nimport type { LoggerContext } from './types.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nfunction formatMeta(meta: Record<string, unknown>, colors: boolean): string {\n return Object.entries(meta)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (typeof value === 'object') {\n const inspected = inspect(value, { depth: 4, colors, compact: false });\n return `\\n ${key}: ${inspected.split('\\n').join('\\n ')}`;\n }\n return `\\n ${key}: ${value}`;\n })\n .join('');\n}\n\nfunction addStoreContext<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format((info) => {\n const storeContext = store.getStore();\n if (storeContext) {\n return { ...info, ...storeContext };\n }\n return info;\n })();\n}\n\nexport function createLocalFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n format.colorize(),\n format.printf(({ timestamp, level, context, message, ...meta }) => {\n const formattedMeta = formatMeta(meta, true);\n return `[${timestamp}] ${level} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;\n }),\n );\n}\n\nexport function createProductionFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n format.json(),\n );\n}\n\nexport function createFormat<TContext extends LoggerContext>(isLocal: boolean, store: LoggerStore<TContext>): Logform.Format {\n return isLocal ? createLocalFormat(store) : createProductionFormat(store);\n}\n","import { transports } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport { LoggerConfig } from './types.js';\n\ntype Transport = transports.ConsoleTransportInstance | DailyRotateFile;\n\nexport function createTransports(config: LoggerConfig): Transport[] {\n const result: Transport[] = [\n new transports.Console({\n level: config.console.level,\n }),\n ];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n level: config.file.level,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\nimport type { LoggerContext } from './types.js';\n\nexport class LoggerStore<TContext extends LoggerContext = LoggerContext> {\n private storage = new AsyncLocalStorage<TContext>();\n\n getStore(): TContext | undefined {\n return this.storage.getStore();\n }\n\n run<T>(context: TContext, fn: () => T): T {\n return this.storage.run(context, fn);\n }\n}\n","export interface TimingResult {\n label: string;\n durationMs: number;\n durationFormatted: string;\n}\n\nexport interface Timer {\n end: () => TimingResult;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms.toFixed(2)}ms`;\n }\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(2)}s`;\n }\n const minutes = Math.floor(ms / 60000);\n const seconds = ((ms % 60000) / 1000).toFixed(1);\n return `${minutes}m ${seconds}s`;\n}\n\nexport function createTimer(label: string): Timer {\n const start = performance.now();\n\n return {\n end(): TimingResult {\n const durationMs = performance.now() - start;\n return {\n label,\n durationMs,\n durationFormatted: formatDuration(durationMs),\n };\n },\n };\n}\n\nexport async function measureAsync<T>(\n label: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; timing: TimingResult }> {\n const timer = createTimer(label);\n const result = await fn();\n const timing = timer.end();\n return { result, timing };\n}\n\nexport function measureSync<T>(\n label: string,\n fn: () => T,\n): { result: T; timing: TimingResult } {\n const timer = createTimer(label);\n const result = fn();\n const timing = timer.end();\n return { result, timing };\n}\n","import { createLogger, Logger } from 'winston';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\nimport { createFormat } from './formatters.js';\nimport { createTransports } from './transports.js';\nimport { LoggerStore } from './store.js';\nimport { createTimer, type Timer, type TimingResult } from './utils/timing.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n http: 3,\n verbose: 4,\n debug: 5,\n silly: 6,\n};\n\nexport class BaseLogger<TContext extends LoggerContext = LoggerContext> {\n private winstonLogger: Logger;\n private defaultLevel: string;\n private store: LoggerStore<TContext>;\n private levelOverrides: Map<string, LevelOverride<TContext>> = new Map();\n\n constructor(config: LoggerConfig, store?: LoggerStore<TContext>) {\n const isLocal = process.env.NODE_ENV !== 'production';\n\n this.defaultLevel = config.level;\n this.store = store ?? new LoggerStore<TContext>();\n\n this.winstonLogger = createLogger({\n level: 'silly', // Allow all, we filter manually\n format: createFormat(isLocal, this.store),\n transports: createTransports(config),\n });\n }\n\n getStore(): LoggerStore<TContext> {\n return this.store;\n }\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n const key = JSON.stringify(match);\n this.levelOverrides.set(key, { match, level });\n }\n\n removeLevelOverride(match: Partial<TContext>): void {\n const key = JSON.stringify(match);\n this.levelOverrides.delete(key);\n }\n\n clearLevelOverrides(): void {\n this.levelOverrides.clear();\n }\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return Array.from(this.levelOverrides.values());\n }\n\n private getEffectiveLevel(): string {\n const context = this.store.getStore();\n if (!context) return this.defaultLevel;\n\n for (const { match, level } of this.levelOverrides.values()) {\n if (this.matchesContext(context, match)) {\n return level;\n }\n }\n return this.defaultLevel;\n }\n\n private matchesContext(context: TContext, match: Partial<TContext>): boolean {\n return Object.entries(match).every(([key, value]) => context[key] === value);\n }\n\n private shouldLog(level: string): boolean {\n const effectiveLevel = this.getEffectiveLevel();\n return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];\n }\n\n getChildLogger(context: string): Logger {\n return this.winstonLogger.child({ context });\n }\n\n time(label: string): Timer {\n return createTimer(label);\n }\n\n timeEnd(timer: Timer, context?: string): TimingResult {\n const result = timer.end();\n this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {\n timing: result,\n });\n return result;\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>, context?: string): Promise<T> {\n const timer = this.time(label);\n try {\n const result = await fn();\n this.timeEnd(timer, context);\n return result;\n } catch (error) {\n const timing = timer.end();\n this.error(`${label} failed after ${timing.durationFormatted}`, error, context);\n throw error;\n }\n }\n\n log(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n error(message: string, error?: Error | unknown, context?: string): void {\n if (!this.shouldLog('error')) return;\n const meta: Record<string, unknown> = { context: context || DEFAULT_CONTEXT };\n if (error instanceof Error) {\n meta.errorMessage = error.message;\n meta.errorStack = error.stack;\n } else if (error) {\n meta.error = error;\n }\n this.winstonLogger.error(message, meta);\n }\n\n warn(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('warn')) return;\n this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n debug(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('debug')) return;\n this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n info(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n verbose(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('verbose')) return;\n this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n}\n","import { Logger } from 'winston';\nimport { BaseLogger } from './logger.js';\nimport { LoggerStore } from './store.js';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\n\nexport interface SingletonLogger<TContext extends LoggerContext> {\n getInstance(config?: LoggerConfig): BaseLogger<TContext>;\n getStore(): LoggerStore<TContext>;\n for(context: string): Logger;\n setLevelOverride(match: Partial<TContext>, level: string): void;\n removeLevelOverride(match: Partial<TContext>): void;\n getLevelOverrides(): LevelOverride<TContext>[];\n clearLevelOverrides(): void;\n}\n\nexport function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext> {\n let instance: BaseLogger<TContext> | null = null;\n\n const ensureInstance = (): BaseLogger<TContext> => {\n if (!instance) {\n throw new Error('Logger not initialized. Call getInstance(config) first.');\n }\n return instance;\n };\n\n return {\n getInstance(config?: LoggerConfig): BaseLogger<TContext> {\n if (!instance) {\n if (!config) {\n throw new Error('Logger config is required for first initialization');\n }\n instance = new BaseLogger<TContext>(config);\n }\n return instance;\n },\n\n getStore(): LoggerStore<TContext> {\n return ensureInstance().getStore();\n },\n\n for(context: string): Logger {\n return ensureInstance().getChildLogger(context);\n },\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n ensureInstance().setLevelOverride(match, level);\n },\n\n removeLevelOverride(match: Partial<TContext>): void {\n ensureInstance().removeLevelOverride(match);\n },\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return ensureInstance().getLevelOverrides();\n },\n\n clearLevelOverrides(): void {\n ensureInstance().clearLevelOverrides();\n },\n };\n}\n","import { randomUUID } from 'crypto';\n\nexport interface RequestIdOptions {\n prefix?: string;\n short?: boolean;\n}\n\nexport function generateRequestId(options: RequestIdOptions = {}): string {\n const { prefix, short = false } = options;\n const uuid = randomUUID();\n const id = short ? uuid.split('-')[0] : uuid;\n return prefix ? `${prefix}-${id}` : id;\n}\n\nexport function extractRequestId(headers: Record<string, string | string[] | undefined>): string | undefined {\n const headerNames = ['x-request-id', 'x-correlation-id', 'x-trace-id'];\n\n for (const name of headerNames) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n }\n\n return undefined;\n}\n\nexport function getOrGenerateRequestId(\n headers: Record<string, string | string[] | undefined>,\n options: RequestIdOptions = {},\n): string {\n return extractRequestId(headers) ?? generateRequestId(options);\n}\n","const DEFAULT_SECRET_PATTERNS = [\n 'password',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'api-key',\n 'auth',\n 'credential',\n 'private',\n];\n\nconst DEFAULT_MASK = '***';\n\nexport interface MaskSecretsOptions {\n patterns?: string[];\n mask?: string;\n deep?: boolean;\n}\n\nfunction isSecretKey(key: string, patterns: string[]): boolean {\n const lowerKey = key.toLowerCase();\n return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));\n}\n\nfunction maskUrlCredentials(url: string, mask: string): string {\n try {\n const parsed = new URL(url);\n if (parsed.password) {\n parsed.password = mask;\n }\n if (parsed.username && parsed.password) {\n parsed.username = mask;\n }\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nexport function maskSecrets(\n obj: unknown,\n options: MaskSecretsOptions = {},\n): unknown {\n const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string') {\n if (obj.startsWith('http://') || obj.startsWith('https://')) {\n return maskUrlCredentials(obj, mask);\n }\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return deep ? obj.map((item) => maskSecrets(item, options)) : obj;\n }\n\n if (typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isSecretKey(key, patterns)) {\n result[key] = mask;\n } else if (deep && typeof value === 'object' && value !== null) {\n result[key] = maskSecrets(value, options);\n } else if (typeof value === 'string') {\n result[key] = maskSecrets(value, options);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n return obj;\n}\n\nexport function createMasker(options: MaskSecretsOptions = {}) {\n return (obj: unknown): unknown => maskSecrets(obj, options);\n}\n"]}
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@rawnodes/logger",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Flexible Winston-based logger with AsyncLocalStorage context, level overrides, and timing utilities",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
7
8
  "types": "./dist/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
11
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
12
14
  }
13
15
  },
14
16
  "files": [
@@ -17,8 +19,8 @@
17
19
  "LICENSE"
18
20
  ],
19
21
  "scripts": {
20
- "build": "tsc",
21
- "dev": "tsc --watch",
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
22
24
  "test": "vitest run",
23
25
  "test:watch": "vitest",
24
26
  "test:coverage": "vitest run --coverage",
@@ -50,6 +52,7 @@
50
52
  },
51
53
  "devDependencies": {
52
54
  "@types/node": "^22.0.0",
55
+ "tsup": "^8.0.0",
53
56
  "typescript": "^5.7.0",
54
57
  "vitest": "^2.0.0"
55
58
  }
@@ -1,7 +0,0 @@
1
- import { Logform } from 'winston';
2
- import { LoggerStore } from './store.js';
3
- import type { LoggerContext } from './types.js';
4
- export declare function createLocalFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format;
5
- export declare function createProductionFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format;
6
- export declare function createFormat<TContext extends LoggerContext>(isLocal: boolean, store: LoggerStore<TContext>): Logform.Format;
7
- //# sourceMappingURL=formatters.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,OAAO,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA2BhD,wBAAgB,iBAAiB,CAAC,QAAQ,SAAS,aAAa,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAW9G;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,SAAS,aAAa,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAOnH;AAED,wBAAgB,YAAY,CAAC,QAAQ,SAAS,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAE3H"}
@@ -1,37 +0,0 @@
1
- import { inspect } from 'util';
2
- import { format } from 'winston';
3
- const DEFAULT_CONTEXT = 'APP';
4
- function formatMeta(meta, colors) {
5
- return Object.entries(meta)
6
- .filter(([, value]) => value !== undefined && value !== null)
7
- .map(([key, value]) => {
8
- if (typeof value === 'object') {
9
- const inspected = inspect(value, { depth: 4, colors, compact: false });
10
- return `\n ${key}: ${inspected.split('\n').join('\n ')}`;
11
- }
12
- return `\n ${key}: ${value}`;
13
- })
14
- .join('');
15
- }
16
- function addStoreContext(store) {
17
- return format((info) => {
18
- const storeContext = store.getStore();
19
- if (storeContext) {
20
- return { ...info, ...storeContext };
21
- }
22
- return info;
23
- })();
24
- }
25
- export function createLocalFormat(store) {
26
- return format.combine(format.errors({ stack: true }), format.timestamp(), addStoreContext(store), format.colorize(), format.printf(({ timestamp, level, context, message, ...meta }) => {
27
- const formattedMeta = formatMeta(meta, true);
28
- return `[${timestamp}] ${level} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;
29
- }));
30
- }
31
- export function createProductionFormat(store) {
32
- return format.combine(format.errors({ stack: true }), format.timestamp(), addStoreContext(store), format.json());
33
- }
34
- export function createFormat(isLocal, store) {
35
- return isLocal ? createLocalFormat(store) : createProductionFormat(store);
36
- }
37
- //# sourceMappingURL=formatters.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAW,MAAM,SAAS,CAAC;AAI1C,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,SAAS,UAAU,CAAC,IAA6B,EAAE,MAAe;IAChE,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC;SAC5D,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACvE,OAAO,OAAO,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,OAAO,GAAG,KAAK,KAAK,EAAE,CAAC;IAChC,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAiC,KAA4B;IACnF,OAAO,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,YAAY,EAAE,CAAC;QACtC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,EAAE,CAAC;AACP,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAiC,KAA4B;IAC5F,OAAO,MAAM,CAAC,OAAO,CACnB,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAC9B,MAAM,CAAC,SAAS,EAAE,EAClB,eAAe,CAAC,KAAK,CAAC,EACtB,MAAM,CAAC,QAAQ,EAAE,EACjB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE;QAChE,MAAM,aAAa,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7C,OAAO,IAAI,SAAS,KAAK,KAAK,KAAK,OAAO,IAAI,eAAe,KAAK,OAAO,GAAG,aAAa,EAAE,CAAC;IAC9F,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAiC,KAA4B;IACjG,OAAO,MAAM,CAAC,OAAO,CACnB,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAC9B,MAAM,CAAC,SAAS,EAAE,EAClB,eAAe,CAAC,KAAK,CAAC,EACtB,MAAM,CAAC,IAAI,EAAE,CACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAiC,OAAgB,EAAE,KAA4B;IACzG,OAAO,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;AAC5E,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,YAAY,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EACV,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,WAAW,EACX,YAAY,EACZ,KAAK,kBAAkB,GACxB,MAAM,kBAAkB,CAAC"}
package/dist/logger.d.ts DELETED
@@ -1,30 +0,0 @@
1
- import { Logger } from 'winston';
2
- import type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';
3
- import { LoggerStore } from './store.js';
4
- import { type Timer, type TimingResult } from './utils/timing.js';
5
- export declare class BaseLogger<TContext extends LoggerContext = LoggerContext> {
6
- private winstonLogger;
7
- private defaultLevel;
8
- private store;
9
- private levelOverrides;
10
- constructor(config: LoggerConfig, store?: LoggerStore<TContext>);
11
- getStore(): LoggerStore<TContext>;
12
- setLevelOverride(match: Partial<TContext>, level: string): void;
13
- removeLevelOverride(match: Partial<TContext>): void;
14
- clearLevelOverrides(): void;
15
- getLevelOverrides(): LevelOverride<TContext>[];
16
- private getEffectiveLevel;
17
- private matchesContext;
18
- private shouldLog;
19
- getChildLogger(context: string): Logger;
20
- time(label: string): Timer;
21
- timeEnd(timer: Timer, context?: string): TimingResult;
22
- timeAsync<T>(label: string, fn: () => Promise<T>, context?: string): Promise<T>;
23
- log(message: string, context?: string, meta?: object): void;
24
- error(message: string, error?: Error | unknown, context?: string): void;
25
- warn(message: string, context?: string, meta?: object): void;
26
- debug(message: string, context?: string, meta?: object): void;
27
- info(message: string, context?: string, meta?: object): void;
28
- verbose(message: string, context?: string, meta?: object): void;
29
- }
30
- //# sourceMappingURL=logger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG7E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAe,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAc/E,qBAAa,UAAU,CAAC,QAAQ,SAAS,aAAa,GAAG,aAAa;IACpE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,cAAc,CAAmD;gBAE7D,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC;IAa/D,QAAQ,IAAI,WAAW,CAAC,QAAQ,CAAC;IAIjC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK/D,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI;IAKnD,mBAAmB,IAAI,IAAI;IAI3B,iBAAiB,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE;IAI9C,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,SAAS;IAKjB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIvC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK;IAI1B,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY;IAQ/C,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAarF,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAK3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAYvE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAK5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAK7D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAK5D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;CAIhE"}