@rawnodes/logger 1.0.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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +293 -0
  3. package/dist/formatters.d.ts +7 -0
  4. package/dist/formatters.d.ts.map +1 -0
  5. package/dist/formatters.js +37 -0
  6. package/dist/formatters.js.map +1 -0
  7. package/dist/index.d.ts +6 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +7 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/logger.d.ts +30 -0
  12. package/dist/logger.d.ts.map +1 -0
  13. package/dist/logger.js +131 -0
  14. package/dist/logger.js.map +1 -0
  15. package/dist/singleton.d.ts +15 -0
  16. package/dist/singleton.d.ts.map +1 -0
  17. package/dist/singleton.js +40 -0
  18. package/dist/singleton.js.map +1 -0
  19. package/dist/store.d.ts +7 -0
  20. package/dist/store.d.ts.map +1 -0
  21. package/dist/store.js +11 -0
  22. package/dist/store.js.map +1 -0
  23. package/dist/transports.d.ts +7 -0
  24. package/dist/transports.d.ts.map +1 -0
  25. package/dist/transports.js +22 -0
  26. package/dist/transports.js.map +1 -0
  27. package/dist/types.d.ts +23 -0
  28. package/dist/types.d.ts.map +1 -0
  29. package/dist/types.js +2 -0
  30. package/dist/types.js.map +1 -0
  31. package/dist/utils/index.d.ts +4 -0
  32. package/dist/utils/index.d.ts.map +1 -0
  33. package/dist/utils/index.js +4 -0
  34. package/dist/utils/index.js.map +1 -0
  35. package/dist/utils/mask-secrets.d.ts +8 -0
  36. package/dist/utils/mask-secrets.d.ts.map +1 -0
  37. package/dist/utils/mask-secrets.js +69 -0
  38. package/dist/utils/mask-secrets.js.map +1 -0
  39. package/dist/utils/request-id.d.ts +8 -0
  40. package/dist/utils/request-id.d.ts.map +1 -0
  41. package/dist/utils/request-id.js +24 -0
  42. package/dist/utils/request-id.js.map +1 -0
  43. package/dist/utils/timing.d.ts +18 -0
  44. package/dist/utils/timing.d.ts.map +1 -0
  45. package/dist/utils/timing.js +37 -0
  46. package/dist/utils/timing.js.map +1 -0
  47. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 RawNodes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,293 @@
1
+ # @rawnodes/logger
2
+
3
+ Flexible Winston-based logger with AsyncLocalStorage context, level overrides, and timing utilities.
4
+
5
+ ## Features
6
+
7
+ - **Context Propagation** - Automatic context via AsyncLocalStorage
8
+ - **Level Overrides** - Debug specific users/requests without global log level change
9
+ - **Timing Utilities** - Built-in performance measurement
10
+ - **Request ID** - Generate and extract request IDs
11
+ - **Secret Masking** - Mask sensitive data in logs
12
+ - **Singleton Factory** - Easy setup with `createSingletonLogger()`
13
+ - **TypeScript First** - Full generic type support
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add @rawnodes/logger
19
+ # or
20
+ npm install @rawnodes/logger
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### 1. Create your app logger
26
+
27
+ ```typescript
28
+ // src/logger/app.logger.ts
29
+ import { createSingletonLogger, type LoggerContext } from '@rawnodes/logger';
30
+
31
+ export interface AppLoggerContext extends LoggerContext {
32
+ userId?: number;
33
+ requestId?: string;
34
+ }
35
+
36
+ export const AppLogger = createSingletonLogger<AppLoggerContext>();
37
+ ```
38
+
39
+ ### 2. Initialize on startup
40
+
41
+ ```typescript
42
+ // src/main.ts
43
+ import { AppLogger } from './logger/app.logger.js';
44
+
45
+ AppLogger.getInstance({
46
+ level: 'info',
47
+ console: { level: 'debug' },
48
+ file: {
49
+ dirname: 'logs',
50
+ filename: 'app-%DATE%.log',
51
+ level: 'info',
52
+ datePattern: 'YYYY-MM-DD',
53
+ maxFiles: '14d',
54
+ },
55
+ });
56
+ ```
57
+
58
+ ### 3. Use in your code
59
+
60
+ ```typescript
61
+ import { AppLogger } from './logger/app.logger.js';
62
+
63
+ const logger = AppLogger.for('UserService');
64
+
65
+ logger.info('User created', { userId: 123 });
66
+ logger.error('Failed to create user', { error });
67
+ ```
68
+
69
+ ### 4. Add context in middleware
70
+
71
+ ```typescript
72
+ // Express middleware
73
+ app.use((req, res, next) => {
74
+ const context: AppLoggerContext = {
75
+ userId: req.user?.id,
76
+ requestId: req.headers['x-request-id'] || generateRequestId(),
77
+ };
78
+ AppLogger.getStore().run(context, () => next());
79
+ });
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ ```typescript
85
+ interface LoggerConfig {
86
+ level: string; // Default log level
87
+
88
+ console: {
89
+ level: string; // Console transport level
90
+ };
91
+
92
+ file?: {
93
+ dirname: string; // Log directory
94
+ filename: string; // Filename pattern (supports %DATE%)
95
+ level: string; // File transport level
96
+ datePattern: string; // Date pattern for rotation
97
+ zippedArchive?: boolean;
98
+ maxSize?: string; // e.g., '20m'
99
+ maxFiles?: string; // e.g., '14d'
100
+ };
101
+ }
102
+ ```
103
+
104
+ ## Level Overrides
105
+
106
+ Debug specific users without changing global log level:
107
+
108
+ ```typescript
109
+ // Enable debug logging for user 123
110
+ AppLogger.setLevelOverride({ userId: 123 }, 'debug');
111
+
112
+ // Now all logs from user 123's requests will include debug level
113
+ // Other users still get the default level
114
+
115
+ // Remove override when done
116
+ AppLogger.removeLevelOverride({ userId: 123 });
117
+
118
+ // Or clear all overrides
119
+ AppLogger.clearLevelOverrides();
120
+ ```
121
+
122
+ ## Timing
123
+
124
+ Measure execution time:
125
+
126
+ ```typescript
127
+ const logger = AppLogger.getInstance();
128
+
129
+ // Manual timing
130
+ const timer = logger.time('database-query');
131
+ await db.query('SELECT ...');
132
+ logger.timeEnd(timer); // Logs: "database-query completed in 45.23ms"
133
+
134
+ // Async wrapper
135
+ const users = await logger.timeAsync('fetch-users', async () => {
136
+ return await userService.findAll();
137
+ });
138
+ ```
139
+
140
+ ## Request ID Utilities
141
+
142
+ ```typescript
143
+ import { generateRequestId, getOrGenerateRequestId } from '@rawnodes/logger';
144
+
145
+ // Generate new request ID
146
+ const requestId = generateRequestId();
147
+ // => "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
148
+
149
+ // Short format
150
+ const shortId = generateRequestId({ short: true });
151
+ // => "a1b2c3d4"
152
+
153
+ // With prefix
154
+ const prefixedId = generateRequestId({ prefix: 'req' });
155
+ // => "req-a1b2c3d4-e5f6-..."
156
+
157
+ // Extract from headers or generate new
158
+ const id = getOrGenerateRequestId(req.headers);
159
+ ```
160
+
161
+ ## Secret Masking
162
+
163
+ ```typescript
164
+ import { maskSecrets } from '@rawnodes/logger';
165
+
166
+ const masked = maskSecrets({
167
+ user: 'admin',
168
+ password: 'secret123',
169
+ apiToken: 'tok_abc123xyz',
170
+ url: 'postgres://user:pass@localhost/db',
171
+ });
172
+
173
+ // Result:
174
+ // {
175
+ // user: 'admin',
176
+ // password: '***',
177
+ // apiToken: '***',
178
+ // url: 'postgres://user:***@localhost/db'
179
+ // }
180
+ ```
181
+
182
+ ## Child Loggers
183
+
184
+ Create scoped loggers with automatic context:
185
+
186
+ ```typescript
187
+ // Get child logger with context name
188
+ const logger = AppLogger.for('PaymentService');
189
+ logger.info('Processing payment'); // [PaymentService] Processing payment
190
+
191
+ // Or from instance
192
+ const baseLogger = AppLogger.getInstance();
193
+ const childLogger = baseLogger.getChildLogger('EmailService');
194
+ ```
195
+
196
+ ## API Reference
197
+
198
+ ### `createSingletonLogger<TContext>()`
199
+
200
+ Creates a singleton logger factory.
201
+
202
+ Returns:
203
+ ```typescript
204
+ interface SingletonLogger<TContext> {
205
+ getInstance(config?: LoggerConfig): BaseLogger<TContext>;
206
+ getStore(): LoggerStore<TContext>;
207
+ for(context: string): Logger;
208
+ setLevelOverride(match: Partial<TContext>, level: string): void;
209
+ removeLevelOverride(match: Partial<TContext>): void;
210
+ getLevelOverrides(): LevelOverride<TContext>[];
211
+ clearLevelOverrides(): void;
212
+ }
213
+ ```
214
+
215
+ ### `BaseLogger<TContext>`
216
+
217
+ Main logger class with methods:
218
+ - `log(message, context?, meta?)`
219
+ - `info(message, context?, meta?)`
220
+ - `warn(message, context?, meta?)`
221
+ - `error(message, error?, context?)`
222
+ - `debug(message, context?, meta?)`
223
+ - `verbose(message, context?, meta?)`
224
+ - `time(label): Timer`
225
+ - `timeEnd(timer, context?): TimingResult`
226
+ - `timeAsync<T>(label, fn, context?): Promise<T>`
227
+ - `getChildLogger(context): Logger`
228
+ - `getStore(): LoggerStore<TContext>`
229
+ - `setLevelOverride(match, level)`
230
+ - `removeLevelOverride(match)`
231
+ - `getLevelOverrides()`
232
+ - `clearLevelOverrides()`
233
+
234
+ ### `LoggerStore<TContext>`
235
+
236
+ AsyncLocalStorage wrapper:
237
+ - `getStore(): TContext | undefined`
238
+ - `run<T>(context, fn): T`
239
+
240
+ ## Integration Examples
241
+
242
+ ### Express
243
+
244
+ ```typescript
245
+ import express from 'express';
246
+ import { AppLogger, generateRequestId } from './logger';
247
+
248
+ const app = express();
249
+
250
+ app.use((req, res, next) => {
251
+ const context = {
252
+ requestId: req.headers['x-request-id'] || generateRequestId({ short: true }),
253
+ userId: req.user?.id,
254
+ };
255
+ AppLogger.getStore().run(context, () => next());
256
+ });
257
+ ```
258
+
259
+ ### NestJS
260
+
261
+ ```typescript
262
+ import { Injectable, NestMiddleware } from '@nestjs/common';
263
+ import { AppLogger, generateRequestId } from './logger';
264
+
265
+ @Injectable()
266
+ export class LoggerMiddleware implements NestMiddleware {
267
+ use(req: any, res: any, next: () => void) {
268
+ const context = {
269
+ requestId: req.headers['x-request-id'] || generateRequestId({ short: true }),
270
+ };
271
+ AppLogger.getStore().run(context, () => next());
272
+ }
273
+ }
274
+ ```
275
+
276
+ ### Telegraf (Telegram Bot)
277
+
278
+ ```typescript
279
+ import { Telegraf } from 'telegraf';
280
+ import { AppLogger } from './logger';
281
+
282
+ bot.use((ctx, next) => {
283
+ const context = {
284
+ telegramUserId: ctx.from?.id,
285
+ chatId: ctx.chat?.id,
286
+ };
287
+ return AppLogger.getStore().run(context, () => next());
288
+ });
289
+ ```
290
+
291
+ ## License
292
+
293
+ MIT
@@ -0,0 +1,7 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,37 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,6 @@
1
+ export { BaseLogger } from './logger.js';
2
+ export { createSingletonLogger, type SingletonLogger } from './singleton.js';
3
+ export { LoggerStore } from './store.js';
4
+ export type { LoggerConfig, ConsoleConfig, FileConfig, LoggerContext, LevelOverride, } from './types.js';
5
+ export { createTimer, measureAsync, measureSync, type Timer, type TimingResult, generateRequestId, extractRequestId, getOrGenerateRequestId, type RequestIdOptions, maskSecrets, createMasker, type MaskSecretsOptions, } from './utils/index.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
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/index.js ADDED
@@ -0,0 +1,7 @@
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';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
@@ -0,0 +1,30 @@
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
@@ -0,0 +1 @@
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"}
package/dist/logger.js ADDED
@@ -0,0 +1,131 @@
1
+ import { createLogger } from 'winston';
2
+ import { createFormat } from './formatters.js';
3
+ import { createTransports } from './transports.js';
4
+ import { LoggerStore } from './store.js';
5
+ import { createTimer } from './utils/timing.js';
6
+ const DEFAULT_CONTEXT = 'APP';
7
+ const LOG_LEVELS = {
8
+ error: 0,
9
+ warn: 1,
10
+ info: 2,
11
+ http: 3,
12
+ verbose: 4,
13
+ debug: 5,
14
+ silly: 6,
15
+ };
16
+ export class BaseLogger {
17
+ winstonLogger;
18
+ defaultLevel;
19
+ store;
20
+ levelOverrides = new Map();
21
+ constructor(config, store) {
22
+ const isLocal = process.env.NODE_ENV !== 'production';
23
+ this.defaultLevel = config.level;
24
+ this.store = store ?? new LoggerStore();
25
+ this.winstonLogger = createLogger({
26
+ level: 'silly', // Allow all, we filter manually
27
+ format: createFormat(isLocal, this.store),
28
+ transports: createTransports(config),
29
+ });
30
+ }
31
+ getStore() {
32
+ return this.store;
33
+ }
34
+ setLevelOverride(match, level) {
35
+ const key = JSON.stringify(match);
36
+ this.levelOverrides.set(key, { match, level });
37
+ }
38
+ removeLevelOverride(match) {
39
+ const key = JSON.stringify(match);
40
+ this.levelOverrides.delete(key);
41
+ }
42
+ clearLevelOverrides() {
43
+ this.levelOverrides.clear();
44
+ }
45
+ getLevelOverrides() {
46
+ return Array.from(this.levelOverrides.values());
47
+ }
48
+ getEffectiveLevel() {
49
+ const context = this.store.getStore();
50
+ if (!context)
51
+ return this.defaultLevel;
52
+ for (const { match, level } of this.levelOverrides.values()) {
53
+ if (this.matchesContext(context, match)) {
54
+ return level;
55
+ }
56
+ }
57
+ return this.defaultLevel;
58
+ }
59
+ matchesContext(context, match) {
60
+ return Object.entries(match).every(([key, value]) => context[key] === value);
61
+ }
62
+ shouldLog(level) {
63
+ const effectiveLevel = this.getEffectiveLevel();
64
+ return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];
65
+ }
66
+ getChildLogger(context) {
67
+ return this.winstonLogger.child({ context });
68
+ }
69
+ time(label) {
70
+ return createTimer(label);
71
+ }
72
+ timeEnd(timer, context) {
73
+ const result = timer.end();
74
+ this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {
75
+ timing: result,
76
+ });
77
+ return result;
78
+ }
79
+ async timeAsync(label, fn, context) {
80
+ const timer = this.time(label);
81
+ try {
82
+ const result = await fn();
83
+ this.timeEnd(timer, context);
84
+ return result;
85
+ }
86
+ catch (error) {
87
+ const timing = timer.end();
88
+ this.error(`${label} failed after ${timing.durationFormatted}`, error, context);
89
+ throw error;
90
+ }
91
+ }
92
+ log(message, context, meta) {
93
+ if (!this.shouldLog('info'))
94
+ return;
95
+ this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });
96
+ }
97
+ error(message, error, context) {
98
+ if (!this.shouldLog('error'))
99
+ return;
100
+ const meta = { context: context || DEFAULT_CONTEXT };
101
+ if (error instanceof Error) {
102
+ meta.errorMessage = error.message;
103
+ meta.errorStack = error.stack;
104
+ }
105
+ else if (error) {
106
+ meta.error = error;
107
+ }
108
+ this.winstonLogger.error(message, meta);
109
+ }
110
+ warn(message, context, meta) {
111
+ if (!this.shouldLog('warn'))
112
+ return;
113
+ this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT, ...meta });
114
+ }
115
+ debug(message, context, meta) {
116
+ if (!this.shouldLog('debug'))
117
+ return;
118
+ this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT, ...meta });
119
+ }
120
+ info(message, context, meta) {
121
+ if (!this.shouldLog('info'))
122
+ return;
123
+ this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });
124
+ }
125
+ verbose(message, context, meta) {
126
+ if (!this.shouldLog('verbose'))
127
+ return;
128
+ this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT, ...meta });
129
+ }
130
+ }
131
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Logger } from 'winston';
2
+ import { BaseLogger } from './logger.js';
3
+ import { LoggerStore } from './store.js';
4
+ import type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';
5
+ export interface SingletonLogger<TContext extends LoggerContext> {
6
+ getInstance(config?: LoggerConfig): BaseLogger<TContext>;
7
+ getStore(): LoggerStore<TContext>;
8
+ for(context: string): Logger;
9
+ setLevelOverride(match: Partial<TContext>, level: string): void;
10
+ removeLevelOverride(match: Partial<TContext>): void;
11
+ getLevelOverrides(): LevelOverride<TContext>[];
12
+ clearLevelOverrides(): void;
13
+ }
14
+ export declare function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext>;
15
+ //# sourceMappingURL=singleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.d.ts","sourceRoot":"","sources":["../src/singleton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,aAAa;IAC7D,WAAW,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACzD,QAAQ,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IAClC,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACpD,iBAAiB,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC/C,mBAAmB,IAAI,IAAI,CAAC;CAC7B;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,SAAS,aAAa,KAAK,eAAe,CAAC,QAAQ,CAAC,CA6CjG"}
@@ -0,0 +1,40 @@
1
+ import { BaseLogger } from './logger.js';
2
+ export function createSingletonLogger() {
3
+ let instance = null;
4
+ const ensureInstance = () => {
5
+ if (!instance) {
6
+ throw new Error('Logger not initialized. Call getInstance(config) first.');
7
+ }
8
+ return instance;
9
+ };
10
+ return {
11
+ getInstance(config) {
12
+ if (!instance) {
13
+ if (!config) {
14
+ throw new Error('Logger config is required for first initialization');
15
+ }
16
+ instance = new BaseLogger(config);
17
+ }
18
+ return instance;
19
+ },
20
+ getStore() {
21
+ return ensureInstance().getStore();
22
+ },
23
+ for(context) {
24
+ return ensureInstance().getChildLogger(context);
25
+ },
26
+ setLevelOverride(match, level) {
27
+ ensureInstance().setLevelOverride(match, level);
28
+ },
29
+ removeLevelOverride(match) {
30
+ ensureInstance().removeLevelOverride(match);
31
+ },
32
+ getLevelOverrides() {
33
+ return ensureInstance().getLevelOverrides();
34
+ },
35
+ clearLevelOverrides() {
36
+ ensureInstance().clearLevelOverrides();
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=singleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleton.js","sourceRoot":"","sources":["../src/singleton.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAczC,MAAM,UAAU,qBAAqB;IACnC,IAAI,QAAQ,GAAgC,IAAI,CAAC;IAEjD,MAAM,cAAc,GAAG,GAAyB,EAAE;QAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO;QACL,WAAW,CAAC,MAAqB;YAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;gBACxE,CAAC;gBACD,QAAQ,GAAG,IAAI,UAAU,CAAW,MAAM,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,QAAQ;YACN,OAAO,cAAc,EAAE,CAAC,QAAQ,EAAE,CAAC;QACrC,CAAC;QAED,GAAG,CAAC,OAAe;YACjB,OAAO,cAAc,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAClD,CAAC;QAED,gBAAgB,CAAC,KAAwB,EAAE,KAAa;YACtD,cAAc,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;QAED,mBAAmB,CAAC,KAAwB;YAC1C,cAAc,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC9C,CAAC;QAED,iBAAiB;YACf,OAAO,cAAc,EAAE,CAAC,iBAAiB,EAAE,CAAC;QAC9C,CAAC;QAED,mBAAmB;YACjB,cAAc,EAAE,CAAC,mBAAmB,EAAE,CAAC;QACzC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { LoggerContext } from './types.js';
2
+ export declare class LoggerStore<TContext extends LoggerContext = LoggerContext> {
3
+ private storage;
4
+ getStore(): TContext | undefined;
5
+ run<T>(context: TContext, fn: () => T): T;
6
+ }
7
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,WAAW,CAAC,QAAQ,SAAS,aAAa,GAAG,aAAa;IACrE,OAAO,CAAC,OAAO,CAAqC;IAEpD,QAAQ,IAAI,QAAQ,GAAG,SAAS;IAIhC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;CAG1C"}
package/dist/store.js ADDED
@@ -0,0 +1,11 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ export class LoggerStore {
3
+ storage = new AsyncLocalStorage();
4
+ getStore() {
5
+ return this.storage.getStore();
6
+ }
7
+ run(context, fn) {
8
+ return this.storage.run(context, fn);
9
+ }
10
+ }
11
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,IAAI,iBAAiB,EAAY,CAAC;IAEpD,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;IAED,GAAG,CAAI,OAAiB,EAAE,EAAW;QACnC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACvC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { transports } from 'winston';
2
+ import DailyRotateFile from 'winston-daily-rotate-file';
3
+ import { LoggerConfig } from './types.js';
4
+ type Transport = transports.ConsoleTransportInstance | DailyRotateFile;
5
+ export declare function createTransports(config: LoggerConfig): Transport[];
6
+ export {};
7
+ //# sourceMappingURL=transports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transports.d.ts","sourceRoot":"","sources":["../src/transports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,eAAe,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,KAAK,SAAS,GAAG,UAAU,CAAC,wBAAwB,GAAG,eAAe,CAAC;AAEvE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,EAAE,CAsBlE"}
@@ -0,0 +1,22 @@
1
+ import { transports } from 'winston';
2
+ import DailyRotateFile from 'winston-daily-rotate-file';
3
+ export function createTransports(config) {
4
+ const result = [
5
+ new transports.Console({
6
+ level: config.console.level,
7
+ }),
8
+ ];
9
+ if (config.file) {
10
+ result.push(new DailyRotateFile({
11
+ dirname: config.file.dirname,
12
+ filename: config.file.filename,
13
+ level: config.file.level,
14
+ datePattern: config.file.datePattern,
15
+ zippedArchive: config.file.zippedArchive,
16
+ maxSize: config.file.maxSize,
17
+ maxFiles: config.file.maxFiles,
18
+ }));
19
+ }
20
+ return result;
21
+ }
22
+ //# sourceMappingURL=transports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transports.js","sourceRoot":"","sources":["../src/transports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAKxD,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,MAAM,MAAM,GAAgB;QAC1B,IAAI,UAAU,CAAC,OAAO,CAAC;YACrB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK;SAC5B,CAAC;KACH,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CACT,IAAI,eAAe,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;YAC5B,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;YAC9B,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK;YACxB,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW;YACpC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa;YACxC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;YAC5B,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;SAC/B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface ConsoleConfig {
2
+ level: string;
3
+ }
4
+ export interface FileConfig {
5
+ dirname: string;
6
+ filename: string;
7
+ level: string;
8
+ datePattern: string;
9
+ zippedArchive?: boolean;
10
+ maxSize?: string;
11
+ maxFiles?: string;
12
+ }
13
+ export interface LoggerConfig {
14
+ level: string;
15
+ console: ConsoleConfig;
16
+ file?: FileConfig;
17
+ }
18
+ export type LoggerContext = Record<string, unknown>;
19
+ export interface LevelOverride<TContext extends LoggerContext> {
20
+ match: Partial<TContext>;
21
+ level: string;
22
+ }
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,aAAa;IAC3D,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export { createTimer, measureAsync, measureSync, type Timer, type TimingResult } from './timing.js';
2
+ export { generateRequestId, extractRequestId, getOrGenerateRequestId, type RequestIdOptions, } from './request-id.js';
3
+ export { maskSecrets, createMasker, type MaskSecretsOptions } from './mask-secrets.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACpG,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { createTimer, measureAsync, measureSync } from './timing.js';
2
+ export { generateRequestId, extractRequestId, getOrGenerateRequestId, } from './request-id.js';
3
+ export { maskSecrets, createMasker } from './mask-secrets.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAiC,MAAM,aAAa,CAAC;AACpG,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,GAEvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,YAAY,EAA2B,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface MaskSecretsOptions {
2
+ patterns?: string[];
3
+ mask?: string;
4
+ deep?: boolean;
5
+ }
6
+ export declare function maskSecrets(obj: unknown, options?: MaskSecretsOptions): unknown;
7
+ export declare function createMasker(options?: MaskSecretsOptions): (obj: unknown) => unknown;
8
+ //# sourceMappingURL=mask-secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-secrets.d.ts","sourceRoot":"","sources":["../../src/utils/mask-secrets.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAsBD,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAqCT;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,kBAAuB,IACnD,KAAK,OAAO,KAAG,OAAO,CAC/B"}
@@ -0,0 +1,69 @@
1
+ const DEFAULT_SECRET_PATTERNS = [
2
+ 'password',
3
+ 'secret',
4
+ 'token',
5
+ 'apikey',
6
+ 'api_key',
7
+ 'api-key',
8
+ 'auth',
9
+ 'credential',
10
+ 'private',
11
+ ];
12
+ const DEFAULT_MASK = '***';
13
+ function isSecretKey(key, patterns) {
14
+ const lowerKey = key.toLowerCase();
15
+ return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
16
+ }
17
+ function maskUrlCredentials(url, mask) {
18
+ try {
19
+ const parsed = new URL(url);
20
+ if (parsed.password) {
21
+ parsed.password = mask;
22
+ }
23
+ if (parsed.username && parsed.password) {
24
+ parsed.username = mask;
25
+ }
26
+ return parsed.toString();
27
+ }
28
+ catch {
29
+ return url;
30
+ }
31
+ }
32
+ export function maskSecrets(obj, options = {}) {
33
+ const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
34
+ if (obj === null || obj === undefined) {
35
+ return obj;
36
+ }
37
+ if (typeof obj === 'string') {
38
+ if (obj.startsWith('http://') || obj.startsWith('https://')) {
39
+ return maskUrlCredentials(obj, mask);
40
+ }
41
+ return obj;
42
+ }
43
+ if (Array.isArray(obj)) {
44
+ return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
45
+ }
46
+ if (typeof obj === 'object') {
47
+ const result = {};
48
+ for (const [key, value] of Object.entries(obj)) {
49
+ if (isSecretKey(key, patterns)) {
50
+ result[key] = mask;
51
+ }
52
+ else if (deep && typeof value === 'object' && value !== null) {
53
+ result[key] = maskSecrets(value, options);
54
+ }
55
+ else if (typeof value === 'string') {
56
+ result[key] = maskSecrets(value, options);
57
+ }
58
+ else {
59
+ result[key] = value;
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+ return obj;
65
+ }
66
+ export function createMasker(options = {}) {
67
+ return (obj) => maskSecrets(obj, options);
68
+ }
69
+ //# sourceMappingURL=mask-secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-secrets.js","sourceRoot":"","sources":["../../src/utils/mask-secrets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface RequestIdOptions {
2
+ prefix?: string;
3
+ short?: boolean;
4
+ }
5
+ export declare function generateRequestId(options?: RequestIdOptions): string;
6
+ export declare function extractRequestId(headers: Record<string, string | string[] | undefined>): string | undefined;
7
+ export declare function getOrGenerateRequestId(headers: Record<string, string | string[] | undefined>, options?: RequestIdOptions): string;
8
+ //# sourceMappingURL=request-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../../src/utils/request-id.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAKxE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAc3G;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAER"}
@@ -0,0 +1,24 @@
1
+ import { randomUUID } from 'crypto';
2
+ export function generateRequestId(options = {}) {
3
+ const { prefix, short = false } = options;
4
+ const uuid = randomUUID();
5
+ const id = short ? uuid.split('-')[0] : uuid;
6
+ return prefix ? `${prefix}-${id}` : id;
7
+ }
8
+ export function extractRequestId(headers) {
9
+ const headerNames = ['x-request-id', 'x-correlation-id', 'x-trace-id'];
10
+ for (const name of headerNames) {
11
+ const value = headers[name];
12
+ if (typeof value === 'string' && value.length > 0) {
13
+ return value;
14
+ }
15
+ if (Array.isArray(value) && value.length > 0) {
16
+ return value[0];
17
+ }
18
+ }
19
+ return undefined;
20
+ }
21
+ export function getOrGenerateRequestId(headers, options = {}) {
22
+ return extractRequestId(headers) ?? generateRequestId(options);
23
+ }
24
+ //# sourceMappingURL=request-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.js","sourceRoot":"","sources":["../../src/utils/request-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAOpC,MAAM,UAAU,iBAAiB,CAAC,UAA4B,EAAE;IAC9D,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1C,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAsD;IACrF,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;IAEvE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAAsD,EACtD,UAA4B,EAAE;IAE9B,OAAO,gBAAgB,CAAC,OAAO,CAAC,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface TimingResult {
2
+ label: string;
3
+ durationMs: number;
4
+ durationFormatted: string;
5
+ }
6
+ export interface Timer {
7
+ end: () => TimingResult;
8
+ }
9
+ export declare function createTimer(label: string): Timer;
10
+ export declare function measureAsync<T>(label: string, fn: () => Promise<T>): Promise<{
11
+ result: T;
12
+ timing: TimingResult;
13
+ }>;
14
+ export declare function measureSync<T>(label: string, fn: () => T): {
15
+ result: T;
16
+ timing: TimingResult;
17
+ };
18
+ //# sourceMappingURL=timing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../src/utils/timing.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,YAAY,CAAC;CACzB;AAcD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAahD;AAED,wBAAsB,YAAY,CAAC,CAAC,EAClC,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC,CAK9C;AAED,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,CAAC,GACV;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAKrC"}
@@ -0,0 +1,37 @@
1
+ function formatDuration(ms) {
2
+ if (ms < 1000) {
3
+ return `${ms.toFixed(2)}ms`;
4
+ }
5
+ if (ms < 60000) {
6
+ return `${(ms / 1000).toFixed(2)}s`;
7
+ }
8
+ const minutes = Math.floor(ms / 60000);
9
+ const seconds = ((ms % 60000) / 1000).toFixed(1);
10
+ return `${minutes}m ${seconds}s`;
11
+ }
12
+ export function createTimer(label) {
13
+ const start = performance.now();
14
+ return {
15
+ end() {
16
+ const durationMs = performance.now() - start;
17
+ return {
18
+ label,
19
+ durationMs,
20
+ durationFormatted: formatDuration(durationMs),
21
+ };
22
+ },
23
+ };
24
+ }
25
+ export async function measureAsync(label, fn) {
26
+ const timer = createTimer(label);
27
+ const result = await fn();
28
+ const timing = timer.end();
29
+ return { result, timing };
30
+ }
31
+ export function measureSync(label, fn) {
32
+ const timer = createTimer(label);
33
+ const result = fn();
34
+ const timing = timer.end();
35
+ return { result, timing };
36
+ }
37
+ //# sourceMappingURL=timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/utils/timing.ts"],"names":[],"mappings":"AAUA,SAAS,cAAc,CAAC,EAAU;IAChC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;QACd,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9B,CAAC;IACD,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACtC,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEhC,OAAO;QACL,GAAG;YACD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAC7C,OAAO;gBACL,KAAK;gBACL,UAAU;gBACV,iBAAiB,EAAE,cAAc,CAAC,UAAU,CAAC;aAC9C,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,EAAoB;IAEpB,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,KAAa,EACb,EAAW;IAEX,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,EAAE,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@rawnodes/logger",
3
+ "version": "1.0.0",
4
+ "description": "Flexible Winston-based logger with AsyncLocalStorage context, level overrides, and timing utilities",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsc --watch",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "test:coverage": "vitest run --coverage",
25
+ "lint": "eslint src --ext .ts",
26
+ "prepublishOnly": "pnpm build"
27
+ },
28
+ "keywords": [
29
+ "logger",
30
+ "logging",
31
+ "winston",
32
+ "typescript",
33
+ "context",
34
+ "async-local-storage",
35
+ "timing",
36
+ "request-id"
37
+ ],
38
+ "author": "RawNodes",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/rawnodes/logger.git"
43
+ },
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "dependencies": {
48
+ "winston": "^3.17.0",
49
+ "winston-daily-rotate-file": "^5.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^22.0.0",
53
+ "typescript": "^5.7.0",
54
+ "vitest": "^2.0.0"
55
+ }
56
+ }