@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.
- package/LICENSE +21 -0
- package/README.md +293 -0
- package/dist/formatters.d.ts +7 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +37 -0
- package/dist/formatters.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +30 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +131 -0
- package/dist/logger.js.map +1 -0
- package/dist/singleton.d.ts +15 -0
- package/dist/singleton.d.ts.map +1 -0
- package/dist/singleton.js +40 -0
- package/dist/singleton.js.map +1 -0
- package/dist/store.d.ts +7 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +11 -0
- package/dist/store.js.map +1 -0
- package/dist/transports.d.ts +7 -0
- package/dist/transports.d.ts.map +1 -0
- package/dist/transports.js +22 -0
- package/dist/transports.js.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/mask-secrets.d.ts +8 -0
- package/dist/utils/mask-secrets.d.ts.map +1 -0
- package/dist/utils/mask-secrets.js +69 -0
- package/dist/utils/mask-secrets.js.map +1 -0
- package/dist/utils/request-id.d.ts +8 -0
- package/dist/utils/request-id.d.ts.map +1 -0
- package/dist/utils/request-id.js +24 -0
- package/dist/utils/request-id.js.map +1 -0
- package/dist/utils/timing.d.ts +18 -0
- package/dist/utils/timing.d.ts.map +1 -0
- package/dist/utils/timing.js +37 -0
- package/dist/utils/timing.js.map +1 -0
- 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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -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"}
|
package/dist/store.d.ts
ADDED
|
@@ -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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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
|
+
}
|