@lssm/lib.logger 1.7.4 → 1.9.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 (67) hide show
  1. package/README.md +26 -525
  2. package/dist/{context.d.ts → context.d.mts} +2 -2
  3. package/dist/{context.d.cts.map → context.d.mts.map} +1 -1
  4. package/dist/{context.js → context.mjs} +1 -1
  5. package/dist/context.mjs.map +1 -0
  6. package/dist/{elysia-plugin.d.cts → elysia-plugin.d.mts} +3 -3
  7. package/dist/{elysia-plugin.d.cts.map → elysia-plugin.d.mts.map} +1 -1
  8. package/dist/elysia-plugin.mjs +2 -0
  9. package/dist/elysia-plugin.mjs.map +1 -0
  10. package/dist/{formatters.d.cts → formatters.d.mts} +2 -2
  11. package/dist/{formatters.d.cts.map → formatters.d.mts.map} +1 -1
  12. package/dist/{formatters.js → formatters.mjs} +2 -2
  13. package/dist/formatters.mjs.map +1 -0
  14. package/dist/{index.d.cts → index.d.mts} +7 -7
  15. package/dist/index.mjs +1 -0
  16. package/dist/{logger.d.cts → logger.d.mts} +3 -3
  17. package/dist/{logger.d.cts.map → logger.d.mts.map} +1 -1
  18. package/dist/logger.mjs +2 -0
  19. package/dist/logger.mjs.map +1 -0
  20. package/dist/{timer.d.ts → timer.d.mts} +2 -2
  21. package/dist/{timer.d.cts.map → timer.d.mts.map} +1 -1
  22. package/dist/{timer.js → timer.mjs} +1 -1
  23. package/dist/timer.mjs.map +1 -0
  24. package/dist/{tracer.d.cts → tracer.d.mts} +2 -2
  25. package/dist/{tracer.d.cts.map → tracer.d.mts.map} +1 -1
  26. package/dist/tracer.mjs +2 -0
  27. package/dist/tracer.mjs.map +1 -0
  28. package/dist/{types.d.cts → types.d.mts} +1 -1
  29. package/dist/{types.d.cts.map → types.d.mts.map} +1 -1
  30. package/dist/{types.js → types.mjs} +1 -1
  31. package/dist/types.mjs.map +1 -0
  32. package/package.json +15 -39
  33. package/dist/_virtual/rolldown_runtime.cjs +0 -1
  34. package/dist/context.cjs +0 -1
  35. package/dist/context.d.cts +0 -44
  36. package/dist/context.d.ts.map +0 -1
  37. package/dist/context.js.map +0 -1
  38. package/dist/elysia-plugin.cjs +0 -1
  39. package/dist/elysia-plugin.d.ts +0 -64
  40. package/dist/elysia-plugin.d.ts.map +0 -1
  41. package/dist/elysia-plugin.js +0 -2
  42. package/dist/elysia-plugin.js.map +0 -1
  43. package/dist/formatters.cjs +0 -9
  44. package/dist/formatters.d.ts +0 -29
  45. package/dist/formatters.d.ts.map +0 -1
  46. package/dist/formatters.js.map +0 -1
  47. package/dist/index.cjs +0 -1
  48. package/dist/index.d.ts +0 -8
  49. package/dist/index.js +0 -1
  50. package/dist/logger.cjs +0 -1
  51. package/dist/logger.d.ts +0 -51
  52. package/dist/logger.d.ts.map +0 -1
  53. package/dist/logger.js +0 -2
  54. package/dist/logger.js.map +0 -1
  55. package/dist/timer.cjs +0 -1
  56. package/dist/timer.d.cts +0 -103
  57. package/dist/timer.d.ts.map +0 -1
  58. package/dist/timer.js.map +0 -1
  59. package/dist/tracer.cjs +0 -1
  60. package/dist/tracer.d.ts +0 -51
  61. package/dist/tracer.d.ts.map +0 -1
  62. package/dist/tracer.js +0 -2
  63. package/dist/tracer.js.map +0 -1
  64. package/dist/types.cjs +0 -1
  65. package/dist/types.d.ts +0 -71
  66. package/dist/types.d.ts.map +0 -1
  67. package/dist/types.js.map +0 -1
package/README.md CHANGED
@@ -1,550 +1,51 @@
1
1
  # @lssm/lib.logger
2
2
 
3
- This library builds with tsdown using the shared `@lssm/tool.tsdown` presets.
3
+ High-performance logging library optimized for Bun, with native ElysiaJS integration.
4
4
 
5
- A comprehensive logging library optimized for Bun with **first-class ElysiaJS integration**, distributed tracing, context management, and beautiful development output.
5
+ ## Purpose
6
6
 
7
- ## Features
8
-
9
- - 🚀 **Optimized for Bun** - Uses Bun's native performance APIs and optimized for Bun runtime
10
- - 🦋 **ElysiaJS Native** - Seamless integration with [ElysiaJS](https://elysiajs.com) lifecycle and context
11
- - 🔍 **Distributed Tracing** - Track operations across HTTP, WebSocket, cron, and queue processing
12
- - ⏱️ **Performance Timing** - Built-in high-precision timing for operations
13
- - 🔄 **Context Management** - Maintain context across async operations (like cls-hooked/nestjs-cls)
14
- - 🎨 **Environment-aware Output** - Pretty logs in dev, structured JSON in production
15
- - 🔌 **Easy Integrations** - Built-in middleware for HTTP, WebSocket, cron, and queues
7
+ To provide structured, performant logging with support for request tracing, timing, and varied output formats (JSON/Pretty). It includes a plugin for ElysiaJS to automatically log HTTP requests.
16
8
 
17
9
  ## Installation
18
10
 
19
11
  ```bash
12
+ npm install @lssm/lib.logger
13
+ # or
20
14
  bun add @lssm/lib.logger
21
- # If using ElysiaJS
22
- bun add elysia @lssm/lib.logger
23
- ```
24
-
25
- ## Quick Start
26
-
27
- ```typescript
28
- import { logger, Logger, LogLevel } from "@lssm/lib.logger";
29
-
30
- // Basic logging
31
- logger.info("Server started", { port: 3000 });
32
- logger.error("Database error", { table: "users" }, error);
33
-
34
- // Create a custom logger
35
- const customLogger = new Logger({
36
- level: LogLevel.DEBUG,
37
- environment: "production",
38
- enableTracing: true,
39
- });
40
- ```
41
-
42
- ## Core Logging
43
-
44
- ```typescript
45
- import { logger } from "@lssm/lib.logger";
46
-
47
- // Different log levels
48
- logger.trace("Detailed debug info"); // TRACE level
49
- logger.debug("Debug information"); // DEBUG level
50
- logger.info("General information"); // INFO level
51
- logger.warn("Warning message"); // WARN level
52
- logger.error("Error occurred", {}, err); // ERROR level
53
- logger.fatal("Critical error", {}, err); // FATAL level
54
- ```
55
-
56
- ## Context Management
57
-
58
- The logger maintains context across async operations using AsyncLocalStorage:
59
-
60
- ```typescript
61
- import { logger } from "@lssm/lib.logger";
62
-
63
- // Run code within a context
64
- logger.withContext({ userId: "123", requestId: "abc" }, () => {
65
- logger.info("Processing user request"); // Will include userId and requestId
66
-
67
- someAsyncOperation(); // Context is maintained across async calls
68
- });
69
-
70
- // Extend existing context
71
- logger.extendContext({ operation: "payment" }, () => {
72
- logger.info("Processing payment"); // Includes all previous context + operation
73
- });
74
-
75
- // Set individual context values
76
- logger.setContext("sessionId", "xyz789");
77
- logger.info("User action"); // Will include sessionId
78
-
79
- // Get current context
80
- const context = logger.getContext();
81
- console.log(context); // { userId: '123', requestId: 'abc', sessionId: 'xyz789' }
82
- ```
83
-
84
- ## Distributed Tracing
85
-
86
- Track operations across your application with automatic span management:
87
-
88
- ```typescript
89
- import { logger } from "@lssm/lib.logger";
90
-
91
- // Trace an operation
92
- await logger.trace(
93
- {
94
- operationType: "http",
95
- operationName: "GET /api/users",
96
- metadata: { userId: "123" },
97
- tags: ["api", "users"],
98
- autoTiming: true,
99
- },
100
- async () => {
101
- // Your operation code here
102
- const users = await fetchUsers();
103
- return users;
104
- }
105
- );
106
-
107
- // Manual span management
108
- const span = logger.startSpan({
109
- operationType: "database",
110
- operationName: "user-query",
111
- });
112
-
113
- try {
114
- const result = await database.query("SELECT * FROM users");
115
- logger.addTraceMetadata("rowCount", result.length);
116
- logger.addTraceTags("database", "users");
117
- return result;
118
- } finally {
119
- logger.finishSpan(span.spanId);
120
- }
121
15
  ```
122
16
 
123
- ## Performance Timing
124
-
125
- Measure execution times with high precision:
126
-
127
- ```typescript
128
- import { logger } from "@lssm/lib.logger";
17
+ ## Key Concepts
129
18
 
130
- // Start a timer
131
- const timer = logger.startTimer("database-operation");
19
+ - **Structured Logging**: Logs are JSON objects by default for easy parsing.
20
+ - **Context Awareness**: Supports AsyncLocalStorage for request-scoped context (Trace IDs).
21
+ - **Elysia Plugin**: Drop-in middleware for Elysia apps.
132
22
 
133
- // ... do some work ...
23
+ ## Exports
134
24
 
135
- const duration = timer.stop();
136
- console.log(`Operation took ${duration}ms`);
25
+ - `logger`: The main logger instance.
26
+ - `elysiaPlugin`: Middleware for Elysia.
27
+ - `timer`: Utilities for measuring execution time.
28
+ - `tracer`: Request tracing utilities.
137
29
 
138
- // Profile function execution
139
- const result = await logger.profile(
140
- "expensive-calculation",
141
- async () => {
142
- return await someExpensiveOperation();
143
- },
144
- { logResult: true, logLevel: LogLevel.INFO }
145
- );
30
+ ## Usage
146
31
 
147
- // Manual timing with laps
148
- const timer2 = logger.startTimer("multi-step-process");
149
- timer2.lap("step-1-complete");
150
- // ... more work ...
151
- timer2.lap("step-2-complete");
152
- const total = timer2.stop();
153
- ```
154
-
155
- ## ElysiaJS Integration
32
+ ### Basic Logging
156
33
 
157
- ### Basic Setup
34
+ ```ts
35
+ import { logger } from '@lssm/lib.logger';
158
36
 
159
- ```typescript
160
- import { Elysia } from "elysia";
161
- import { elysiaLogger } from "@lssm/lib.logger";
162
-
163
- const app = new Elysia()
164
- .use(
165
- elysiaLogger({
166
- logRequests: true,
167
- logResponses: true,
168
- excludePaths: ["/health", "/metrics"],
169
- })
170
- )
171
- .get("/", ({ logInfo }) => {
172
- logInfo("Processing request");
173
- return "Hello World";
174
- })
175
- .listen(3000);
37
+ logger.info('Server started', { port: 3000 });
38
+ logger.error('Database connection failed', { error: err });
176
39
  ```
177
40
 
178
- The plugin automatically:
41
+ ### With Elysia
179
42
 
180
- - ✅ Logs all incoming requests with timing
181
- - Logs responses with status codes and duration
182
- - Traces operations with correlation IDs
183
- - ✅ Maintains context across async operations
184
- - ✅ Provides helper functions in route context
43
+ ```ts
44
+ import { Elysia } from 'elysia';
45
+ import { elysiaLogger } from '@lssm/lib.logger/elysia-plugin';
185
46
 
186
- ### Advanced ElysiaJS Usage
187
-
188
- ```typescript
189
- import { Elysia } from "elysia";
190
- import {
191
- elysiaLogger,
192
- createDatabaseUtils,
193
- Logger,
194
- LogLevel,
195
- } from "@lssm/lib.logger";
196
-
197
- const customLogger = new Logger({
198
- level: LogLevel.DEBUG,
199
- environment: "production",
200
- });
201
-
202
- const db = createDatabaseUtils(customLogger);
203
-
204
- const app = new Elysia()
205
- .use(
206
- elysiaLogger({
207
- logger: customLogger,
208
- maskSensitiveData: true,
209
- })
210
- )
211
- .derive(() => ({ db }))
212
- .get("/users", async ({ logInfo, traceOperation, db }) => {
213
- logInfo("Fetching users from database");
214
-
215
- const users = await traceOperation("fetch-users", async () => {
216
- return db.query("select-users", () =>
217
- // Your database query here
218
- Promise.resolve([{ id: 1, name: "John" }])
219
- );
220
- });
221
-
222
- return users;
223
- })
224
- .listen(3000);
225
- ```
226
-
227
- ### ElysiaJS WebSocket Logging
228
-
229
- ```typescript
230
- import { Elysia } from "elysia";
231
- import { elysiaLogger, createWebSocketUtils } from "@lssm/lib.logger";
232
-
233
- const wsLogger = createWebSocketUtils();
234
-
235
- const app = new Elysia()
47
+ new Elysia()
236
48
  .use(elysiaLogger())
237
- .ws("/chat", {
238
- open(ws) {
239
- const connectionId = crypto.randomUUID();
240
- wsLogger.logConnection(connectionId, {
241
- userAgent: ws.data.headers?.["user-agent"],
242
- });
243
- },
244
- message(ws, message) {
245
- wsLogger.logMessage(ws.id, typeof message, message.length);
246
- ws.send(`Echo: ${message}`);
247
- },
248
- close(ws, code, reason) {
249
- wsLogger.logDisconnection(ws.id, code, reason);
250
- },
251
- })
49
+ .get('/', () => 'Hello World')
252
50
  .listen(3000);
253
51
  ```
254
-
255
- ### ElysiaJS with Authentication Logging
256
-
257
- ```typescript
258
- import { Elysia } from "elysia";
259
- import { elysiaLogger, createAuthUtils } from "@lssm/lib.logger";
260
-
261
- const authLogger = createAuthUtils();
262
-
263
- const app = new Elysia()
264
- .use(elysiaLogger())
265
- .derive(() => ({ authLogger }))
266
- .post("/auth/login", async ({ body, authLogger }) => {
267
- try {
268
- // Your authentication logic
269
- const user = await authenticateUser(body.email, body.password);
270
-
271
- authLogger.logLogin(user.id, {
272
- email: body.email,
273
- ip: request.headers.get("x-forwarded-for"),
274
- });
275
-
276
- return { success: true, token: generateToken(user) };
277
- } catch (error) {
278
- authLogger.logAuthFailure("invalid_credentials", {
279
- email: body.email,
280
- });
281
- throw error;
282
- }
283
- })
284
- .listen(3000);
285
- ```
286
-
287
- ### Production Configuration for ElysiaJS
288
-
289
- ```typescript
290
- import { Elysia } from "elysia";
291
- import { elysiaLogger, Logger, LogLevel } from "@lssm/lib.logger";
292
-
293
- const productionLogger = new Logger({
294
- level: LogLevel.INFO,
295
- environment: "production",
296
- enableTracing: true,
297
- enableTiming: true,
298
- });
299
-
300
- const app = new Elysia()
301
- .use(
302
- elysiaLogger({
303
- logger: productionLogger,
304
- logRequests: true,
305
- logResponses: true,
306
- excludePaths: ["/health", "/metrics", "/favicon.ico"],
307
- maskSensitiveData: true,
308
- })
309
- )
310
- .get("/health", () => ({ status: "ok" })) // This won't be logged
311
- .get("/api/*", ({ logInfo, traceOperation }) => {
312
- // All API routes automatically logged and traced
313
- return traceOperation("business-logic", async () => {
314
- // Your business logic here
315
- return { success: true };
316
- });
317
- })
318
- .listen(3000);
319
- ```
320
-
321
- ## HTTP Integration (Non-ElysiaJS)
322
-
323
- ### Express/Hono Middleware
324
-
325
- ```typescript
326
- import { createHttpMiddleware } from "@lssm/lib.logger";
327
- import express from "express";
328
-
329
- const app = express();
330
-
331
- // Add logging middleware
332
- app.use(createHttpMiddleware()); // Uses default logger
333
-
334
- // All subsequent requests will have context and tracing
335
- app.get("/api/users", (req, res) => {
336
- logger.info("Fetching users"); // Automatically includes request context
337
- // ... handle request
338
- });
339
- ```
340
-
341
- ### Bun HTTP Server
342
-
343
- ```typescript
344
- import { createBunHttpHandler } from "@lssm/lib.logger";
345
-
346
- const handler = createBunHttpHandler(async (req) => {
347
- // Request is automatically traced and timed
348
- logger.info("Processing request"); // Includes request context
349
-
350
- return new Response("Hello World");
351
- });
352
-
353
- Bun.serve({
354
- fetch: handler,
355
- port: 3000,
356
- });
357
- ```
358
-
359
- ## WebSocket Integration
360
-
361
- ```typescript
362
- import { createWebSocketMiddleware } from "@lssm/lib.logger";
363
-
364
- const wsMiddleware = createWebSocketMiddleware();
365
-
366
- // WebSocket server setup
367
- const server = Bun.serve({
368
- websocket: {
369
- open: wsMiddleware.onOpen,
370
- message: wsMiddleware.onMessage,
371
- close: wsMiddleware.onClose,
372
- error: wsMiddleware.onError,
373
- },
374
- });
375
- ```
376
-
377
- ## Cron Job Integration
378
-
379
- ```typescript
380
- import { createCronWrapper } from "@lssm/lib.logger";
381
-
382
- const cronWrapper = createCronWrapper();
383
-
384
- // Wrap your cron jobs
385
- const wrappedJob = cronWrapper("daily-cleanup", async () => {
386
- logger.info("Starting daily cleanup");
387
- await cleanupOldData();
388
- logger.info("Cleanup completed");
389
- });
390
-
391
- // Schedule with your preferred cron library
392
- schedule.scheduleJob("0 2 * * *", wrappedJob);
393
- ```
394
-
395
- ## Queue Processing Integration
396
-
397
- ```typescript
398
- import { createQueueWrapper } from "@lssm/lib.logger";
399
-
400
- const queueWrapper = createQueueWrapper();
401
-
402
- // Wrap queue processors
403
- const processEmailJob = queueWrapper.wrapProcessor(
404
- "email-queue",
405
- async (job: EmailJob, jobId: string) => {
406
- logger.info("Processing email job", { recipient: job.recipient });
407
- await sendEmail(job);
408
- return { success: true };
409
- }
410
- );
411
-
412
- // Log queue events
413
- queueWrapper.logEnqueue("email-queue", "job-123", emailData);
414
- queueWrapper.logDequeue("email-queue", "job-123");
415
- queueWrapper.logRetry("email-queue", "job-123", 2, 5);
416
- ```
417
-
418
- ## Database Integration
419
-
420
- ```typescript
421
- import { createDatabaseWrapper } from "@lssm/lib.logger";
422
-
423
- const dbWrapper = createDatabaseWrapper();
424
-
425
- // Wrap database operations
426
- const users = await dbWrapper.wrapQuery(
427
- "fetch-users",
428
- () => prisma.user.findMany(),
429
- { table: "users", operation: "findMany" }
430
- );
431
- ```
432
-
433
- ## Configuration
434
-
435
- ```typescript
436
- import { Logger, LogLevel } from "@lssm/lib.logger";
437
-
438
- const logger = new Logger({
439
- level: LogLevel.INFO, // Minimum log level
440
- environment: "production", // 'development' | 'production' | 'test'
441
- enableTracing: true, // Enable distributed tracing
442
- enableTiming: true, // Enable performance timing
443
- enableContext: true, // Enable context management
444
- enableColors: true, // Enable colors in dev output
445
- maxContextDepth: 10, // Max nested context depth
446
- timestampFormat: "iso", // 'iso' | 'epoch' | 'relative'
447
- });
448
- ```
449
-
450
- ## Custom Formatters
451
-
452
- ```typescript
453
- import {
454
- Logger,
455
- CustomFormatter,
456
- DevFormatter,
457
- ProductionFormatter,
458
- } from "@lssm/lib.logger";
459
-
460
- // Use custom formatter
461
- const customFormatter = new CustomFormatter(
462
- "{timestamp} [{level}] {traceId} {message}",
463
- (date) => date.toLocaleDateString()
464
- );
465
-
466
- const logger = new Logger();
467
- logger.setFormatter(customFormatter);
468
-
469
- // Or create your own
470
- class MyFormatter implements Formatter {
471
- format(entry: LogEntry): string {
472
- return `${entry.timestamp} - ${entry.message}`;
473
- }
474
- }
475
- ```
476
-
477
- ## Example Output
478
-
479
- ### Development Mode (Pretty)
480
-
481
- ```
482
- 14:32:15.123 ● INFO [trace:a1b2c3d4|span:e5f6g7h8] HTTP request started (12.34ms)
483
- Context: { userId: "123", requestId: "req-456" }
484
- Metadata: { method: "GET", url: "/api/users", userAgent: "Mozilla/5.0..." }
485
-
486
- 14:32:15.135 ✖ ERROR Database connection failed (156.78ms)
487
- Error: ConnectionError: Unable to connect to database
488
- at DatabaseClient.connect (database.js:45:12)
489
- at UserService.fetchUsers (user-service.js:23:8)
490
- at ApiHandler.getUsers (api-handler.js:67:15)
491
- ```
492
-
493
- ### Production Mode (JSON)
494
-
495
- ```json
496
- {"timestamp":"2024-01-15T14:32:15.123Z","level":"info","message":"HTTP request started","traceId":"a1b2c3d4e5f6g7h8","spanId":"e5f6g7h8","duration":12.34,"context":{"userId":"123","requestId":"req-456"},"metadata":{"method":"GET","url":"/api/users"}}
497
-
498
- {"timestamp":"2024-01-15T14:32:15.135Z","level":"error","message":"Database connection failed","traceId":"a1b2c3d4e5f6g7h8","duration":156.78,"error":{"name":"ConnectionError","message":"Unable to connect to database","stack":"ConnectionError: Unable to connect to database\n at DatabaseClient.connect..."}}
499
- ```
500
-
501
- ## Best Practices
502
-
503
- 1. **Use context for request correlation**:
504
-
505
- ```typescript
506
- logger.withContext({ requestId, userId }, () => {
507
- // All logs in this scope will include requestId and userId
508
- });
509
- ```
510
-
511
- 2. **Trace important operations**:
512
-
513
- ```typescript
514
- await logger.trace(
515
- {
516
- operationType: "database",
517
- operationName: "user-creation",
518
- },
519
- () => createUser(userData)
520
- );
521
- ```
522
-
523
- 3. **Profile performance-critical code**:
524
-
525
- ```typescript
526
- const result = await logger.profile("data-processing", () => {
527
- return processLargeDataset(data);
528
- });
529
- ```
530
-
531
- 4. **Use appropriate log levels**:
532
-
533
- - `trace`: Very detailed debugging (typically disabled in production)
534
- - `debug`: Debugging information
535
- - `info`: General application flow
536
- - `warn`: Warning conditions
537
- - `error`: Error conditions
538
- - `fatal`: Critical errors that might cause the application to exit
539
-
540
- 5. **Clean up in production**:
541
- ```typescript
542
- process.on("SIGTERM", async () => {
543
- await logger.flush();
544
- process.exit(0);
545
- });
546
- ```
547
-
548
- ## License
549
-
550
- MIT
@@ -1,4 +1,4 @@
1
- import { ContextData, TraceContext } from "./types.js";
1
+ import { ContextData, TraceContext } from "./types.mjs";
2
2
 
3
3
  //#region src/context.d.ts
4
4
  declare class LogContext {
@@ -41,4 +41,4 @@ declare class LogContext {
41
41
  }
42
42
  //#endregion
43
43
  export { LogContext };
44
- //# sourceMappingURL=context.d.ts.map
44
+ //# sourceMappingURL=context.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.cts","names":[],"sources":["../src/context.ts"],"sourcesContent":[],"mappings":";;;cAQa,UAAA;;EAAA,QAAA,OAAU;EAQC,WAAA,CAAA;EAUN,OAAA,WAAA,CAAA,CAAA,EAVM,UAUN;EAAuB;;;EAWV,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EAXb,WAWa,EAAA,EAAA,EAAA,GAAA,GAXU,CAWV,CAAA,EAXc,CAWd;EAAgC;;;EA+B/C,MAAA,CAAA,CAAA,CAAA,CAAA,iBAAA,EA/Be,OA+Bf,CA/BuB,WA+BvB,CAAA,EAAA,EAAA,EAAA,GAAA,GA/B+C,CA+B/C,CAAA,EA/BmD,CA+BnD;EAQE;;;;;;;uBAhBK;;;;gBAQP;;;;kBAQE;;;;qBAUG"}
1
+ {"version":3,"file":"context.d.mts","names":[],"sources":["../src/context.ts"],"sourcesContent":[],"mappings":";;;cAQa,UAAA;;EAAA,QAAA,OAAU;EAQC,WAAA,CAAA;EAUN,OAAA,WAAA,CAAA,CAAA,EAVM,UAUN;EAAuB;;;EAWV,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EAXb,WAWa,EAAA,EAAA,EAAA,GAAA,GAXU,CAWV,CAAA,EAXc,CAWd;EAAgC;;;EA+B/C,MAAA,CAAA,CAAA,CAAA,CAAA,iBAAA,EA/Be,OA+Bf,CA/BuB,WA+BvB,CAAA,EAAA,EAAA,EAAA,GAAA,GA/B+C,CA+B/C,CAAA,EA/BmD,CA+BnD;EAQE;;;;;;;uBAhBK;;;;gBAQP;;;;kBAQE;;;;qBAUG"}
@@ -1,2 +1,2 @@
1
1
  import{AsyncLocalStorage as e}from"node:async_hooks";var t=class t{static instance;storage;constructor(){this.storage=new e}static getInstance(){return t.instance||=new t,t.instance}run(e,t){let n={context:{...e},trace:this.getCurrentTrace()};return this.storage.run(n,t)}extend(e,t){let n={...this.getContext(),...e};return this.run(n,t)}set(e,t){let n=this.storage.getStore();n&&(n.context[e]=t)}get(e){return this.storage.getStore()?.context?.[e]}getContext(){return this.storage.getStore()?.context||{}}setTrace(e){let t=this.storage.getStore();t&&(t.trace=e)}getCurrentTrace(){return this.storage.getStore()?.trace}generateId(){return crypto.randomUUID()}};export{t as LogContext};
2
- //# sourceMappingURL=context.js.map
2
+ //# sourceMappingURL=context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.mjs","names":["contextData: LogContextData","mergedContext: ContextData"],"sources":["../src/context.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport type { ContextData, TraceContext } from './types';\n\ninterface LogContextData {\n context: ContextData;\n trace?: TraceContext;\n}\n\nexport class LogContext {\n private static instance: LogContext;\n private storage: AsyncLocalStorage<LogContextData>;\n\n constructor() {\n this.storage = new AsyncLocalStorage<LogContextData>();\n }\n\n static getInstance(): LogContext {\n if (!LogContext.instance) {\n LogContext.instance = new LogContext();\n }\n return LogContext.instance;\n }\n\n /**\n * Run a function with a new context\n */\n run<T>(context: ContextData, fn: () => T): T {\n const contextData: LogContextData = {\n context: { ...context },\n trace: this.getCurrentTrace(),\n };\n return this.storage.run(contextData, fn) as T;\n }\n\n /**\n * Run a function with an extended context (merges with current)\n */\n extend<T>(additionalContext: Partial<ContextData>, fn: () => T): T {\n const currentContext = this.getContext();\n const mergedContext: ContextData = {\n ...currentContext,\n ...additionalContext,\n };\n return this.run(mergedContext, fn);\n }\n\n /**\n * Set context data for the current execution context\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n set(key: string, value: any): void {\n const current = this.storage.getStore();\n if (current) {\n current.context[key] = value;\n }\n }\n\n /**\n * Get a specific context value\n */\n get<T>(key: string): T | undefined {\n const current = this.storage.getStore();\n return current?.context?.[key];\n }\n\n /**\n * Get all context data\n */\n getContext(): ContextData {\n const current = this.storage.getStore();\n return current?.context || {};\n }\n\n /**\n * Set trace context\n */\n setTrace(trace: TraceContext): void {\n const current = this.storage.getStore();\n if (current) {\n current.trace = trace;\n }\n }\n\n /**\n * Get current trace context\n */\n getCurrentTrace(): TraceContext | undefined {\n const current = this.storage.getStore();\n return current?.trace;\n }\n /**\n * Generate a unique ID for requests/operations\n */\n generateId(): string {\n return crypto.randomUUID();\n }\n}\n"],"mappings":"qDAQA,IAAa,EAAb,MAAa,CAAW,CACtB,OAAe,SACf,QAEA,aAAc,CACZ,KAAK,QAAU,IAAI,EAGrB,OAAO,aAA0B,CAI/B,MAHA,CACE,EAAW,WAAW,IAAI,EAErB,EAAW,SAMpB,IAAO,EAAsB,EAAgB,CAC3C,IAAMA,EAA8B,CAClC,QAAS,CAAE,GAAG,EAAS,CACvB,MAAO,KAAK,iBAAiB,CAC9B,CACD,OAAO,KAAK,QAAQ,IAAI,EAAa,EAAG,CAM1C,OAAU,EAAyC,EAAgB,CAEjE,IAAMC,EAA6B,CACjC,GAFqB,KAAK,YAAY,CAGtC,GAAG,EACJ,CACD,OAAO,KAAK,IAAI,EAAe,EAAG,CAOpC,IAAI,EAAa,EAAkB,CACjC,IAAM,EAAU,KAAK,QAAQ,UAAU,CACnC,IACF,EAAQ,QAAQ,GAAO,GAO3B,IAAO,EAA4B,CAEjC,OADgB,KAAK,QAAQ,UAAU,EACvB,UAAU,GAM5B,YAA0B,CAExB,OADgB,KAAK,QAAQ,UAAU,EACvB,SAAW,EAAE,CAM/B,SAAS,EAA2B,CAClC,IAAM,EAAU,KAAK,QAAQ,UAAU,CACnC,IACF,EAAQ,MAAQ,GAOpB,iBAA4C,CAE1C,OADgB,KAAK,QAAQ,UAAU,EACvB,MAKlB,YAAqB,CACnB,OAAO,OAAO,YAAY"}
@@ -1,5 +1,5 @@
1
- import { ContextData } from "./types.cjs";
2
- import { Logger } from "./logger.cjs";
1
+ import { ContextData } from "./types.mjs";
2
+ import { Logger } from "./logger.mjs";
3
3
  import * as elysia0 from "elysia";
4
4
  import { Elysia } from "elysia";
5
5
 
@@ -61,4 +61,4 @@ declare function elysiaLogger<T extends Elysia>(config?: ElysiaLoggerConfig): (a
61
61
  declare const createElysiaLogger: typeof elysiaLogger;
62
62
  //#endregion
63
63
  export { ElysiaLoggerConfig, createElysiaLogger, elysiaLogger };
64
- //# sourceMappingURL=elysia-plugin.d.cts.map
64
+ //# sourceMappingURL=elysia-plugin.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"elysia-plugin.d.cts","names":[],"sources":["../src/elysia-plugin.ts"],"sourcesContent":[],"mappings":";;;;;;UAKiB,kBAAA;WACN;;EADM,YAAA,CAAA,EAAA,OAAkB;EAWnB,YAAA,CAAA,EAAY,MAAA,EAAA;;;;;;iBAAZ,uBAAuB,iBAC7B,2BAYc,MAAC;EA+EqB,SAAA,EAAA,CAAA,CAAA;EAK5B,KAAA,EAAA,CAAA,CAAA;EAEG,MAAA,EAAA,CAAA,CAAA;EAMM,OAAA,EAAA,CAAA,CAAA;CAAY,EAAA;EAAR,OAAA,EAAA,CAAA,CAAA;EACZ,KAAA,EAAA,CAAA,CAAA;CAAR,EAAA;EAdmC,MAAA,EAAA,CAAA,CAAA;EAK5B,gBAAA,EAAA,CAAA,CAAA;EAEG,KAAA,EAAA,CAAA,CAAA;EAMM,OAAA,EAAA,CAAA,CAAA;EAAY,MAAA,EAAA,CAAA,CAAA;EAAR,QAAA,EAAA,CAAA,CAAA;CACZ,EAAA,CAAA,CAAA,EAAA;EAAR,MAAA,EAAA,CAAA,CAAA;EAAO,OAAA,EAAA,CAAA,CAAA;EA7FO,MAAA,EAAA,CAAA,CAAA;EAAA,gBAAA,EAAA,CAAA,CAAA;EA4GZ,QAAA,EAAA,CAAA,CAAA;;;;;;;;;;;mDA7BiC;iDAK5B,kBAEG;2EAMM,MAAI,QAAQ,SAC5B,QAAQ;;;;;YAAD,OAAA,CAAA;mDAd4B;iDAK5B,kBAEG;2EAMM,MAAI,QAAQ,SAC5B,QAAQ;;;cAeN,2BAAkB"}
1
+ {"version":3,"file":"elysia-plugin.d.mts","names":[],"sources":["../src/elysia-plugin.ts"],"sourcesContent":[],"mappings":";;;;;;UAKiB,kBAAA;WACN;;EADM,YAAA,CAAA,EAAA,OAAkB;EAWnB,YAAA,CAAA,EAAY,MAAA,EAAA;;;;;;iBAAZ,uBAAuB,iBAC7B,2BAYc,MAAC;EA+EqB,SAAA,EAAA,CAAA,CAAA;EAK5B,KAAA,EAAA,CAAA,CAAA;EAEG,MAAA,EAAA,CAAA,CAAA;EAMM,OAAA,EAAA,CAAA,CAAA;CAAY,EAAA;EAAR,OAAA,EAAA,CAAA,CAAA;EACZ,KAAA,EAAA,CAAA,CAAA;CAAR,EAAA;EAdmC,MAAA,EAAA,CAAA,CAAA;EAK5B,gBAAA,EAAA,CAAA,CAAA;EAEG,KAAA,EAAA,CAAA,CAAA;EAMM,OAAA,EAAA,CAAA,CAAA;EAAY,MAAA,EAAA,CAAA,CAAA;EAAR,QAAA,EAAA,CAAA,CAAA;CACZ,EAAA,CAAA,CAAA,EAAA;EAAR,MAAA,EAAA,CAAA,CAAA;EAAO,OAAA,EAAA,CAAA,CAAA;EA7FO,MAAA,EAAA,CAAA,CAAA;EAAA,gBAAA,EAAA,CAAA,CAAA;EA4GZ,QAAA,EAAA,CAAA,CAAA;;;;;;;;;;;mDA7BiC;iDAK5B,kBAEG;2EAMM,MAAI,QAAQ,SAC5B,QAAQ;;;;;YAAD,OAAA,CAAA;mDAd4B;iDAK5B,kBAEG;2EAMM,MAAI,QAAQ,SAC5B,QAAQ;;;cAeN,2BAAkB"}
@@ -0,0 +1,2 @@
1
+ import{LogContext as e}from"./context.mjs";import{Logger as t}from"./logger.mjs";import{Elysia as n}from"elysia";function r(n={}){let{logger:r=new t,logRequests:i=!0,logResponses:a=!0,excludePaths:o=[`/health`,`/metrics`]}=n,s=e.getInstance();return function(e){return e.derive(e=>{let{request:t,path:n}=e;if(o.some(e=>n.startsWith(e)))return{logger:r};let a=new URL(t.url),c={requestId:s.generateId(),method:t.method,url:t.url,path:a.pathname,userAgent:t.headers.get(`user-agent`)||void 0,timestamp:new Date().toISOString()},l=performance.now();return s.run(c,()=>{i&&r.info(`→ ${t.method} ${n}`,{method:t.method,path:n,userAgent:c.userAgent,requestId:c.requestId})}),{logger:r,requestContext:c,startTime:l}}).onAfterHandle(e=>{let{request:t,startTime:n,requestContext:r,logger:i}=e;if(!n||!r)return;let o=performance.now()-n,s=new URL(t.url).pathname;a&&i.info(`← 200 ${t.method} ${s}`,{method:t.method,path:s,duration:`${o.toFixed(2)}ms`,requestId:r.requestId})}).onError(e=>{let{request:t,error:n,code:r,startTime:i,requestContext:a,logger:o}=e;if(!i||!a)return;let s=performance.now()-i,c=new URL(t.url).pathname;o?.error(`✖ ${r} ${t.method} ${c}`,{method:t.method,path:c,error:n?.toString?.()||`Unknown error`,code:r,duration:`${s.toFixed(2)}ms`,requestId:a.requestId})}).derive(()=>({logInfo:(e,t)=>{r.info(e,t)},logError:(e,t,n)=>{r.error(e,n,t)},traceOperation:async(e,t)=>r.trace({operationType:`custom`,operationName:e,autoTiming:!0},t)}))}}const i=r;export{i as createElysiaLogger,r as elysiaLogger};
2
+ //# sourceMappingURL=elysia-plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elysia-plugin.mjs","names":["requestContext: ContextData"],"sources":["../src/elysia-plugin.ts"],"sourcesContent":["import { Logger } from './logger';\nimport { LogContext } from './context';\nimport type { ContextData } from './types';\nimport { Elysia } from 'elysia';\n\nexport interface ElysiaLoggerConfig {\n logger?: Logger;\n logRequests?: boolean;\n logResponses?: boolean;\n excludePaths?: string[];\n}\n\n/**\n * Simple ElysiaJS Logger Plugin\n * Provides automatic request logging and tracing\n */\nexport function elysiaLogger<T extends Elysia>(\n config: ElysiaLoggerConfig = {}\n) {\n const {\n logger = new Logger(),\n logRequests = true,\n logResponses = true,\n excludePaths = ['/health', '/metrics'],\n } = config;\n\n const context = LogContext.getInstance();\n\n // For type compatibility, we use a factory function\n return function (app: T) {\n return app\n .derive((ctx) => {\n const { request, path } = ctx;\n\n // Skip excluded paths\n if (excludePaths.some((excludePath) => path.startsWith(excludePath))) {\n return { logger };\n }\n\n // Create request context\n const url = new URL(request.url);\n const requestContext: ContextData = {\n requestId: context.generateId(),\n method: request.method,\n url: request.url,\n path: url.pathname,\n userAgent: request.headers.get('user-agent') || undefined,\n timestamp: new Date().toISOString(),\n };\n\n const startTime = performance.now();\n\n // Run in context\n context.run(requestContext, () => {\n // Log request\n if (logRequests) {\n logger.info(`→ ${request.method} ${path}`, {\n method: request.method,\n path,\n userAgent: requestContext.userAgent,\n requestId: requestContext.requestId,\n });\n }\n });\n\n return {\n logger,\n requestContext,\n startTime,\n };\n })\n .onAfterHandle((ctx) => {\n const { request, startTime, requestContext, logger } = ctx;\n\n if (!startTime || !requestContext) return;\n\n const duration = performance.now() - startTime;\n const path = new URL(request.url).pathname;\n\n if (logResponses) {\n logger.info(`← 200 ${request.method} ${path}`, {\n method: request.method,\n path,\n duration: `${duration.toFixed(2)}ms`,\n requestId: requestContext.requestId,\n });\n }\n })\n .onError((ctx) => {\n const { request, error, code, startTime, requestContext, logger } = ctx;\n\n if (!startTime || !requestContext) return;\n\n const duration = performance.now() - startTime;\n const path = new URL(request.url).pathname;\n\n logger?.error(`✖ ${code} ${request.method} ${path}`, {\n method: request.method,\n path,\n error: error?.toString?.() || 'Unknown error',\n code,\n duration: `${duration.toFixed(2)}ms`,\n requestId: requestContext.requestId,\n });\n })\n .derive(() => ({\n // Helper functions available in route handlers\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n logInfo: (message: string, metadata?: Record<string, any>) => {\n logger.info(message, metadata);\n },\n logError: (\n message: string,\n error?: Error,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metadata?: Record<string, any>\n ) => {\n logger.error(message, metadata, error);\n },\n traceOperation: async <T>(\n operationName: string,\n operation: () => T | Promise<T>\n ): Promise<T> => {\n return logger.trace(\n {\n operationType: 'custom',\n operationName,\n autoTiming: true,\n },\n operation\n );\n },\n }));\n };\n}\n\n// Export convenience functions\nexport const createElysiaLogger = elysiaLogger;\n"],"mappings":"iHAgBA,SAAgB,EACd,EAA6B,EAAE,CAC/B,CACA,GAAM,CACJ,SAAS,IAAI,EACb,cAAc,GACd,eAAe,GACf,eAAe,CAAC,UAAW,WAAW,EACpC,EAEE,EAAU,EAAW,aAAa,CAGxC,OAAO,SAAU,EAAQ,CACvB,OAAO,EACJ,OAAQ,GAAQ,CACf,GAAM,CAAE,UAAS,QAAS,EAG1B,GAAI,EAAa,KAAM,GAAgB,EAAK,WAAW,EAAY,CAAC,CAClE,MAAO,CAAE,SAAQ,CAInB,IAAM,EAAM,IAAI,IAAI,EAAQ,IAAI,CAC1BA,EAA8B,CAClC,UAAW,EAAQ,YAAY,CAC/B,OAAQ,EAAQ,OAChB,IAAK,EAAQ,IACb,KAAM,EAAI,SACV,UAAW,EAAQ,QAAQ,IAAI,aAAa,EAAI,IAAA,GAChD,UAAW,IAAI,MAAM,CAAC,aAAa,CACpC,CAEK,EAAY,YAAY,KAAK,CAenC,OAZA,EAAQ,IAAI,MAAsB,CAE5B,GACF,EAAO,KAAK,KAAK,EAAQ,OAAO,GAAG,IAAQ,CACzC,OAAQ,EAAQ,OAChB,OACA,UAAW,EAAe,UAC1B,UAAW,EAAe,UAC3B,CAAC,EAEJ,CAEK,CACL,SACA,iBACA,YACD,EACD,CACD,cAAe,GAAQ,CACtB,GAAM,CAAE,UAAS,YAAW,iBAAgB,OAAA,GAAW,EAEvD,GAAI,CAAC,GAAa,CAAC,EAAgB,OAEnC,IAAM,EAAW,YAAY,KAAK,CAAG,EAC/B,EAAO,IAAI,IAAI,EAAQ,IAAI,CAAC,SAE9B,GACF,EAAO,KAAK,SAAS,EAAQ,OAAO,GAAG,IAAQ,CAC7C,OAAQ,EAAQ,OAChB,OACA,SAAU,GAAG,EAAS,QAAQ,EAAE,CAAC,IACjC,UAAW,EAAe,UAC3B,CAAC,EAEJ,CACD,QAAS,GAAQ,CAChB,GAAM,CAAE,UAAS,QAAO,OAAM,YAAW,iBAAgB,OAAA,GAAW,EAEpE,GAAI,CAAC,GAAa,CAAC,EAAgB,OAEnC,IAAM,EAAW,YAAY,KAAK,CAAG,EAC/B,EAAO,IAAI,IAAI,EAAQ,IAAI,CAAC,SAElC,GAAQ,MAAM,KAAK,EAAK,GAAG,EAAQ,OAAO,GAAG,IAAQ,CACnD,OAAQ,EAAQ,OAChB,OACA,MAAO,GAAO,YAAY,EAAI,gBAC9B,OACA,SAAU,GAAG,EAAS,QAAQ,EAAE,CAAC,IACjC,UAAW,EAAe,UAC3B,CAAC,EACF,CACD,YAAc,CAGb,SAAU,EAAiB,IAAmC,CAC5D,EAAO,KAAK,EAAS,EAAS,EAEhC,UACE,EACA,EAEA,IACG,CACH,EAAO,MAAM,EAAS,EAAU,EAAM,EAExC,eAAgB,MACd,EACA,IAEO,EAAO,MACZ,CACE,cAAe,SACf,gBACA,WAAY,GACb,CACD,EACD,CAEJ,EAAE,EAKT,MAAa,EAAqB"}
@@ -1,4 +1,4 @@
1
- import { Formatter, LogEntry } from "./types.cjs";
1
+ import { Formatter, LogEntry } from "./types.mjs";
2
2
 
3
3
  //#region src/formatters.d.ts
4
4
  declare class DevFormatter implements Formatter {
@@ -26,4 +26,4 @@ declare class CustomFormatter implements Formatter {
26
26
  }
27
27
  //#endregion
28
28
  export { CustomFormatter, DevFormatter, ProductionFormatter };
29
- //# sourceMappingURL=formatters.d.cts.map
29
+ //# sourceMappingURL=formatters.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatters.d.cts","names":[],"sources":["../src/formatters.ts"],"sourcesContent":[],"mappings":";;;cAkCa,YAAA,YAAwB;;EAAxB,WAAA,CAAA,YAOG,CAPU,EAOV,OAAA;EAkJH,MAAA,CAAA,KAAA,EAlJG,QAkJiB,CAAA,EAAA,MAAA;EAkDpB,QAAA,eAAgB;EAML,QAAA,eAAA;EAMR,QAAA,cAAA;EAZwB,QAAA,aAAA;EAAS,QAAA,cAAA;;;;;;cAlDpC,mBAAA,YAA+B;gBAC5B;;cAiDH,eAAA,YAA2B;;;qDAMhB;gBAMR"}
1
+ {"version":3,"file":"formatters.d.mts","names":[],"sources":["../src/formatters.ts"],"sourcesContent":[],"mappings":";;;cAkCa,YAAA,YAAwB;;EAAxB,WAAA,CAAA,YAOG,CAPU,EAOV,OAAA;EAkJH,MAAA,CAAA,KAAA,EAlJG,QAkJiB,CAAA,EAAA,MAAA;EAkDpB,QAAA,eAAgB;EAML,QAAA,eAAA;EAMR,QAAA,cAAA;EAZwB,QAAA,aAAA;EAAS,QAAA,cAAA;;;;;;cAlDpC,mBAAA,YAA+B;gBAC5B;;cAiDH,eAAA,YAA2B;;;qDAMhB;gBAMR"}