evlog 0.1.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -12
- package/dist/error.d.mts +21 -11
- package/dist/error.d.ts +21 -11
- package/dist/error.mjs +12 -8
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +3 -2
- package/dist/logger.d.mts +1 -6
- package/dist/logger.d.ts +1 -6
- package/dist/logger.mjs +32 -16
- package/dist/nitro/plugin.mjs +41 -10
- package/dist/nuxt/module.d.mts +7 -0
- package/dist/nuxt/module.d.ts +7 -0
- package/dist/nuxt/module.mjs +11 -7
- package/dist/runtime/client/log.d.mts +9 -0
- package/dist/runtime/client/log.d.ts +9 -0
- package/dist/runtime/{composables → client}/log.mjs +2 -3
- package/dist/runtime/{plugin.client.mjs → client/plugin.mjs} +4 -3
- package/dist/runtime/server/useLogger.d.mts +5 -0
- package/dist/runtime/server/useLogger.d.ts +5 -0
- package/dist/runtime/utils/parseError.d.mts +5 -0
- package/dist/runtime/utils/parseError.d.ts +5 -0
- package/dist/runtime/utils/parseError.mjs +28 -0
- package/dist/types.d.mts +40 -2
- package/dist/types.d.ts +40 -2
- package/dist/utils.d.mts +3 -22
- package/dist/utils.d.ts +3 -22
- package/dist/utils.mjs +4 -1
- package/package.json +12 -8
- package/dist/runtime/composables/index.d.mts +0 -4
- package/dist/runtime/composables/index.d.ts +0 -4
- package/dist/runtime/composables/index.mjs +0 -2
- package/dist/runtime/composables/log.d.mts +0 -18
- package/dist/runtime/composables/log.d.ts +0 -18
- package/dist/runtime/composables/useLogger.d.mts +0 -21
- package/dist/runtime/composables/useLogger.d.ts +0 -21
- /package/dist/runtime/{plugin.client.d.mts → client/plugin.d.mts} +0 -0
- /package/dist/runtime/{plugin.client.d.ts → client/plugin.d.ts} +0 -0
- /package/dist/runtime/{composables → server}/useLogger.mjs +0 -0
package/README.md
CHANGED
|
@@ -96,6 +96,8 @@ export default defineNuxtConfig({
|
|
|
96
96
|
service: 'my-app',
|
|
97
97
|
environment: process.env.NODE_ENV,
|
|
98
98
|
},
|
|
99
|
+
// Optional: only log specific routes (supports glob patterns)
|
|
100
|
+
include: ['/api/**'],
|
|
99
101
|
},
|
|
100
102
|
})
|
|
101
103
|
```
|
|
@@ -104,7 +106,7 @@ That's it. Now use `useLogger(event)` in any API route:
|
|
|
104
106
|
|
|
105
107
|
```typescript
|
|
106
108
|
// server/api/checkout.post.ts
|
|
107
|
-
import { useLogger,
|
|
109
|
+
import { useLogger, createError } from 'evlog'
|
|
108
110
|
|
|
109
111
|
export default defineEventHandler(async (event) => {
|
|
110
112
|
const log = useLogger(event)
|
|
@@ -124,8 +126,9 @@ export default defineEventHandler(async (event) => {
|
|
|
124
126
|
} catch (error) {
|
|
125
127
|
log.error(error, { step: 'payment' })
|
|
126
128
|
|
|
127
|
-
throw
|
|
129
|
+
throw createError({
|
|
128
130
|
message: 'Payment failed',
|
|
131
|
+
status: 402,
|
|
129
132
|
why: error.message,
|
|
130
133
|
fix: 'Try a different payment method or contact your bank',
|
|
131
134
|
})
|
|
@@ -173,7 +176,7 @@ Same API, same wide events:
|
|
|
173
176
|
|
|
174
177
|
```typescript
|
|
175
178
|
// routes/api/documents/[id]/export.post.ts
|
|
176
|
-
import { useLogger,
|
|
179
|
+
import { useLogger, createError } from 'evlog'
|
|
177
180
|
|
|
178
181
|
export default defineEventHandler(async (event) => {
|
|
179
182
|
const log = useLogger(event)
|
|
@@ -189,8 +192,9 @@ export default defineEventHandler(async (event) => {
|
|
|
189
192
|
// Load document from database
|
|
190
193
|
const document = await db.documents.findUnique({ where: { id: documentId } })
|
|
191
194
|
if (!document) {
|
|
192
|
-
throw
|
|
195
|
+
throw createError({
|
|
193
196
|
message: 'Document not found',
|
|
197
|
+
status: 404,
|
|
194
198
|
why: `No document with ID "${documentId}" exists`,
|
|
195
199
|
fix: 'Check the document ID and try again',
|
|
196
200
|
})
|
|
@@ -206,8 +210,9 @@ export default defineEventHandler(async (event) => {
|
|
|
206
210
|
} catch (error) {
|
|
207
211
|
log.error(error, { step: 'export-generation' })
|
|
208
212
|
|
|
209
|
-
throw
|
|
213
|
+
throw createError({
|
|
210
214
|
message: 'Export failed',
|
|
215
|
+
status: 500,
|
|
211
216
|
why: `Failed to generate ${body.format} export: ${error.message}`,
|
|
212
217
|
fix: 'Try a different format or contact support',
|
|
213
218
|
})
|
|
@@ -238,7 +243,7 @@ Errors should tell you **what** happened, **why**, and **how to fix it**.
|
|
|
238
243
|
|
|
239
244
|
```typescript
|
|
240
245
|
// server/api/repos/sync.post.ts
|
|
241
|
-
import { useLogger,
|
|
246
|
+
import { useLogger, createError } from 'evlog'
|
|
242
247
|
|
|
243
248
|
export default defineEventHandler(async (event) => {
|
|
244
249
|
const log = useLogger(event)
|
|
@@ -252,8 +257,9 @@ export default defineEventHandler(async (event) => {
|
|
|
252
257
|
} catch (error) {
|
|
253
258
|
log.error(error, { step: 'github-sync' })
|
|
254
259
|
|
|
255
|
-
throw
|
|
260
|
+
throw createError({
|
|
256
261
|
message: 'Failed to sync repository',
|
|
262
|
+
status: 503,
|
|
257
263
|
why: 'GitHub API rate limit exceeded',
|
|
258
264
|
fix: 'Wait 1 hour or use a different token',
|
|
259
265
|
link: 'https://docs.github.com/en/rest/rate-limit',
|
|
@@ -302,7 +308,7 @@ migrationLog.emit()
|
|
|
302
308
|
|
|
303
309
|
```typescript
|
|
304
310
|
// workers/sync-job.ts
|
|
305
|
-
import { initLogger, createRequestLogger,
|
|
311
|
+
import { initLogger, createRequestLogger, createError } from 'evlog'
|
|
306
312
|
|
|
307
313
|
initLogger({
|
|
308
314
|
env: {
|
|
@@ -346,9 +352,23 @@ initLogger({
|
|
|
346
352
|
region?: string // Deployment region
|
|
347
353
|
},
|
|
348
354
|
pretty?: boolean // Pretty print (default: true in dev)
|
|
355
|
+
include?: string[] // Route patterns to log (glob), e.g. ['/api/**']
|
|
349
356
|
})
|
|
350
357
|
```
|
|
351
358
|
|
|
359
|
+
### Pretty Output Format
|
|
360
|
+
|
|
361
|
+
In development, evlog uses a compact tree format:
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
16:45:31.060 INFO [my-app] GET /api/checkout 200 in 234ms
|
|
365
|
+
├─ user: id=123 plan=premium
|
|
366
|
+
├─ cart: items=3 total=9999
|
|
367
|
+
└─ payment: id=pay_xyz method=card
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
In production (`pretty: false`), logs are emitted as JSON for machine parsing.
|
|
371
|
+
|
|
352
372
|
### `log`
|
|
353
373
|
|
|
354
374
|
Simple logging API.
|
|
@@ -378,13 +398,18 @@ log.emit() // Emit final event
|
|
|
378
398
|
log.getContext() // Get current context
|
|
379
399
|
```
|
|
380
400
|
|
|
381
|
-
### `
|
|
401
|
+
### `createError(options)`
|
|
402
|
+
|
|
403
|
+
Create a structured error with HTTP status support. Import from `evlog` directly to avoid conflicts with Nuxt/Nitro's `createError`.
|
|
382
404
|
|
|
383
|
-
|
|
405
|
+
> **Note**: `createEvlogError` is also available as an auto-imported alias in Nuxt/Nitro to avoid conflicts.
|
|
384
406
|
|
|
385
407
|
```typescript
|
|
386
|
-
|
|
408
|
+
import { createError } from 'evlog'
|
|
409
|
+
|
|
410
|
+
createError({
|
|
387
411
|
message: string // What happened
|
|
412
|
+
status?: number // HTTP status code (default: 500)
|
|
388
413
|
why?: string // Why it happened
|
|
389
414
|
fix?: string // How to fix it
|
|
390
415
|
link?: string // Documentation URL
|
|
@@ -392,6 +417,34 @@ defineError({
|
|
|
392
417
|
})
|
|
393
418
|
```
|
|
394
419
|
|
|
420
|
+
### `parseError(error)`
|
|
421
|
+
|
|
422
|
+
Parse a caught error into a flat structure with all evlog fields. Auto-imported in Nuxt.
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { parseError } from 'evlog'
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
await $fetch('/api/checkout')
|
|
429
|
+
} catch (err) {
|
|
430
|
+
const error = parseError(err)
|
|
431
|
+
|
|
432
|
+
// Direct access to all fields
|
|
433
|
+
console.log(error.message) // "Payment failed"
|
|
434
|
+
console.log(error.status) // 402
|
|
435
|
+
console.log(error.why) // "Card declined"
|
|
436
|
+
console.log(error.fix) // "Try another card"
|
|
437
|
+
console.log(error.link) // "https://docs.example.com/..."
|
|
438
|
+
|
|
439
|
+
// Use with toast
|
|
440
|
+
toast.add({
|
|
441
|
+
title: error.message,
|
|
442
|
+
description: error.why,
|
|
443
|
+
color: 'error',
|
|
444
|
+
})
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
395
448
|
## Framework Support
|
|
396
449
|
|
|
397
450
|
evlog works with any framework powered by [Nitro](https://nitro.unjs.io/):
|
|
@@ -405,9 +458,35 @@ evlog works with any framework powered by [Nitro](https://nitro.unjs.io/):
|
|
|
405
458
|
| **TanStack Start** | `plugins: ['evlog/nitro']` |
|
|
406
459
|
| **Standalone Nitro** | `plugins: ['evlog/nitro']` |
|
|
407
460
|
|
|
461
|
+
## Agent Skills
|
|
462
|
+
|
|
463
|
+
evlog provides [Agent Skills](https://github.com/boristane/agent-skills) to help AI coding assistants understand and implement proper logging patterns in your codebase.
|
|
464
|
+
|
|
465
|
+
### Installation
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
npx add-skill hugorcd/evlog
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### What it does
|
|
472
|
+
|
|
473
|
+
Once installed, your AI assistant will:
|
|
474
|
+
- Review your logging code and suggest wide event patterns
|
|
475
|
+
- Help refactor scattered `console.log` calls into structured events
|
|
476
|
+
- Guide you to use `createError()` for self-documenting errors
|
|
477
|
+
- Ensure proper use of `useLogger(event)` in Nuxt/Nitro routes
|
|
478
|
+
|
|
479
|
+
### Examples
|
|
480
|
+
|
|
481
|
+
```
|
|
482
|
+
Add logging to this endpoint
|
|
483
|
+
Review my logging code
|
|
484
|
+
Help me set up logging for this service
|
|
485
|
+
```
|
|
486
|
+
|
|
408
487
|
## Philosophy
|
|
409
488
|
|
|
410
|
-
Inspired by [Logging Sucks](https://loggingsucks.com/) by [Boris Tane](https://
|
|
489
|
+
Inspired by [Logging Sucks](https://loggingsucks.com/) by [Boris Tane](https://x.com/boristane).
|
|
411
490
|
|
|
412
491
|
1. **Wide Events**: One log per request with all context
|
|
413
492
|
2. **Structured Errors**: Errors that explain themselves
|
package/dist/error.d.mts
CHANGED
|
@@ -7,6 +7,7 @@ import { ErrorOptions } from './types.mjs';
|
|
|
7
7
|
* ```ts
|
|
8
8
|
* throw new EvlogError({
|
|
9
9
|
* message: 'Failed to sync repository',
|
|
10
|
+
* status: 503,
|
|
10
11
|
* why: 'GitHub API rate limit exceeded',
|
|
11
12
|
* fix: 'Wait 1 hour or use a different token',
|
|
12
13
|
* link: 'https://docs.github.com/en/rest/rate-limit',
|
|
@@ -15,33 +16,42 @@ import { ErrorOptions } from './types.mjs';
|
|
|
15
16
|
* ```
|
|
16
17
|
*/
|
|
17
18
|
declare class EvlogError extends Error {
|
|
19
|
+
readonly status: number;
|
|
18
20
|
readonly why?: string;
|
|
19
21
|
readonly fix?: string;
|
|
20
22
|
readonly link?: string;
|
|
21
23
|
constructor(options: ErrorOptions | string);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
get statusCode(): number;
|
|
25
|
+
get data(): {
|
|
26
|
+
why: string | undefined;
|
|
27
|
+
fix: string | undefined;
|
|
28
|
+
link: string | undefined;
|
|
29
|
+
} | undefined;
|
|
25
30
|
toString(): string;
|
|
26
|
-
/**
|
|
27
|
-
* Convert to plain object for JSON serialization
|
|
28
|
-
*/
|
|
29
31
|
toJSON(): Record<string, unknown>;
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
|
-
* Create
|
|
34
|
+
* Create a structured error with context for debugging and user-facing messages.
|
|
33
35
|
*
|
|
34
|
-
*
|
|
36
|
+
* @param options - Error message string or full options object
|
|
37
|
+
* @returns EvlogError instance compatible with Nitro's error handling
|
|
35
38
|
*
|
|
36
39
|
* @example
|
|
37
40
|
* ```ts
|
|
38
|
-
*
|
|
41
|
+
* // Simple error
|
|
42
|
+
* throw createError('Something went wrong')
|
|
43
|
+
*
|
|
44
|
+
* // Structured error with context
|
|
45
|
+
* throw createError({
|
|
39
46
|
* message: 'Payment failed',
|
|
47
|
+
* status: 402,
|
|
40
48
|
* why: 'Card declined by issuer',
|
|
41
49
|
* fix: 'Try a different payment method',
|
|
50
|
+
* link: 'https://docs.example.com/payments',
|
|
42
51
|
* })
|
|
43
52
|
* ```
|
|
44
53
|
*/
|
|
45
|
-
declare function
|
|
54
|
+
declare function createError(options: ErrorOptions | string): EvlogError;
|
|
55
|
+
declare const createEvlogError: typeof createError;
|
|
46
56
|
|
|
47
|
-
export { EvlogError,
|
|
57
|
+
export { EvlogError, createError, createEvlogError };
|
package/dist/error.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { ErrorOptions } from './types.js';
|
|
|
7
7
|
* ```ts
|
|
8
8
|
* throw new EvlogError({
|
|
9
9
|
* message: 'Failed to sync repository',
|
|
10
|
+
* status: 503,
|
|
10
11
|
* why: 'GitHub API rate limit exceeded',
|
|
11
12
|
* fix: 'Wait 1 hour or use a different token',
|
|
12
13
|
* link: 'https://docs.github.com/en/rest/rate-limit',
|
|
@@ -15,33 +16,42 @@ import { ErrorOptions } from './types.js';
|
|
|
15
16
|
* ```
|
|
16
17
|
*/
|
|
17
18
|
declare class EvlogError extends Error {
|
|
19
|
+
readonly status: number;
|
|
18
20
|
readonly why?: string;
|
|
19
21
|
readonly fix?: string;
|
|
20
22
|
readonly link?: string;
|
|
21
23
|
constructor(options: ErrorOptions | string);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
get statusCode(): number;
|
|
25
|
+
get data(): {
|
|
26
|
+
why: string | undefined;
|
|
27
|
+
fix: string | undefined;
|
|
28
|
+
link: string | undefined;
|
|
29
|
+
} | undefined;
|
|
25
30
|
toString(): string;
|
|
26
|
-
/**
|
|
27
|
-
* Convert to plain object for JSON serialization
|
|
28
|
-
*/
|
|
29
31
|
toJSON(): Record<string, unknown>;
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
|
-
* Create
|
|
34
|
+
* Create a structured error with context for debugging and user-facing messages.
|
|
33
35
|
*
|
|
34
|
-
*
|
|
36
|
+
* @param options - Error message string or full options object
|
|
37
|
+
* @returns EvlogError instance compatible with Nitro's error handling
|
|
35
38
|
*
|
|
36
39
|
* @example
|
|
37
40
|
* ```ts
|
|
38
|
-
*
|
|
41
|
+
* // Simple error
|
|
42
|
+
* throw createError('Something went wrong')
|
|
43
|
+
*
|
|
44
|
+
* // Structured error with context
|
|
45
|
+
* throw createError({
|
|
39
46
|
* message: 'Payment failed',
|
|
47
|
+
* status: 402,
|
|
40
48
|
* why: 'Card declined by issuer',
|
|
41
49
|
* fix: 'Try a different payment method',
|
|
50
|
+
* link: 'https://docs.example.com/payments',
|
|
42
51
|
* })
|
|
43
52
|
* ```
|
|
44
53
|
*/
|
|
45
|
-
declare function
|
|
54
|
+
declare function createError(options: ErrorOptions | string): EvlogError;
|
|
55
|
+
declare const createEvlogError: typeof createError;
|
|
46
56
|
|
|
47
|
-
export { EvlogError,
|
|
57
|
+
export { EvlogError, createError, createEvlogError };
|
package/dist/error.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { colors, isServer } from './utils.mjs';
|
|
2
2
|
|
|
3
3
|
class EvlogError extends Error {
|
|
4
|
+
status;
|
|
4
5
|
why;
|
|
5
6
|
fix;
|
|
6
7
|
link;
|
|
@@ -8,6 +9,7 @@ class EvlogError extends Error {
|
|
|
8
9
|
const opts = typeof options === "string" ? { message: options } : options;
|
|
9
10
|
super(opts.message, { cause: opts.cause });
|
|
10
11
|
this.name = "EvlogError";
|
|
12
|
+
this.status = opts.status ?? 500;
|
|
11
13
|
this.why = opts.why;
|
|
12
14
|
this.fix = opts.fix;
|
|
13
15
|
this.link = opts.link;
|
|
@@ -15,9 +17,12 @@ class EvlogError extends Error {
|
|
|
15
17
|
Error.captureStackTrace(this, EvlogError);
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
get statusCode() {
|
|
21
|
+
return this.status;
|
|
22
|
+
}
|
|
23
|
+
get data() {
|
|
24
|
+
return this.why || this.fix || this.link ? { why: this.why, fix: this.fix, link: this.link } : void 0;
|
|
25
|
+
}
|
|
21
26
|
toString() {
|
|
22
27
|
const useColors = isServer();
|
|
23
28
|
const red = useColors ? colors.red : "";
|
|
@@ -42,13 +47,11 @@ class EvlogError extends Error {
|
|
|
42
47
|
}
|
|
43
48
|
return lines.join("\n");
|
|
44
49
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Convert to plain object for JSON serialization
|
|
47
|
-
*/
|
|
48
50
|
toJSON() {
|
|
49
51
|
return {
|
|
50
52
|
name: this.name,
|
|
51
53
|
message: this.message,
|
|
54
|
+
status: this.status,
|
|
52
55
|
why: this.why,
|
|
53
56
|
fix: this.fix,
|
|
54
57
|
link: this.link,
|
|
@@ -57,8 +60,9 @@ class EvlogError extends Error {
|
|
|
57
60
|
};
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
|
-
function
|
|
63
|
+
function createError(options) {
|
|
61
64
|
return new EvlogError(options);
|
|
62
65
|
}
|
|
66
|
+
const createEvlogError = createError;
|
|
63
67
|
|
|
64
|
-
export { EvlogError,
|
|
68
|
+
export { EvlogError, createError, createEvlogError };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { EvlogError,
|
|
1
|
+
export { EvlogError, createError, createEvlogError } from './error.mjs';
|
|
2
2
|
export { createRequestLogger, getEnvironment, initLogger, log } from './logger.mjs';
|
|
3
|
-
export { useLogger } from './runtime/
|
|
4
|
-
export {
|
|
5
|
-
|
|
3
|
+
export { useLogger } from './runtime/server/useLogger.mjs';
|
|
4
|
+
export { parseError } from './runtime/utils/parseError.mjs';
|
|
5
|
+
export { BaseWideEvent, EnvironmentContext, ErrorOptions, H3EventContext, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, ServerEvent, WideEvent } from './types.mjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { EvlogError,
|
|
1
|
+
export { EvlogError, createError, createEvlogError } from './error.js';
|
|
2
2
|
export { createRequestLogger, getEnvironment, initLogger, log } from './logger.js';
|
|
3
|
-
export { useLogger } from './runtime/
|
|
4
|
-
export {
|
|
5
|
-
|
|
3
|
+
export { useLogger } from './runtime/server/useLogger.js';
|
|
4
|
+
export { parseError } from './runtime/utils/parseError.js';
|
|
5
|
+
export { BaseWideEvent, EnvironmentContext, ErrorOptions, H3EventContext, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, ServerEvent, WideEvent } from './types.js';
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { EvlogError,
|
|
1
|
+
export { EvlogError, createError, createEvlogError } from './error.mjs';
|
|
2
2
|
export { createRequestLogger, getEnvironment, initLogger, log } from './logger.mjs';
|
|
3
|
-
export { useLogger } from './runtime/
|
|
3
|
+
export { useLogger } from './runtime/server/useLogger.mjs';
|
|
4
|
+
export { parseError } from './runtime/utils/parseError.mjs';
|
|
4
5
|
import './utils.mjs';
|
package/dist/logger.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RequestLogger, EnvironmentContext, LoggerConfig, Log } from './types.mjs';
|
|
1
|
+
import { RequestLoggerOptions, RequestLogger, EnvironmentContext, LoggerConfig, Log } from './types.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Initialize the logger with configuration.
|
|
@@ -15,11 +15,6 @@ declare function initLogger(config?: LoggerConfig): void;
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
declare const log: Log;
|
|
18
|
-
interface RequestLoggerOptions {
|
|
19
|
-
method?: string;
|
|
20
|
-
path?: string;
|
|
21
|
-
requestId?: string;
|
|
22
|
-
}
|
|
23
18
|
/**
|
|
24
19
|
* Create a request-scoped logger for building wide events.
|
|
25
20
|
*
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RequestLogger, EnvironmentContext, LoggerConfig, Log } from './types.js';
|
|
1
|
+
import { RequestLoggerOptions, RequestLogger, EnvironmentContext, LoggerConfig, Log } from './types.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Initialize the logger with configuration.
|
|
@@ -15,11 +15,6 @@ declare function initLogger(config?: LoggerConfig): void;
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
declare const log: Log;
|
|
18
|
-
interface RequestLoggerOptions {
|
|
19
|
-
method?: string;
|
|
20
|
-
path?: string;
|
|
21
|
-
requestId?: string;
|
|
22
|
-
}
|
|
23
18
|
/**
|
|
24
19
|
* Create a request-scoped logger for building wide events.
|
|
25
20
|
*
|
package/dist/logger.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isDev, detectEnvironment, formatDuration, colors, getLevelColor } from './utils.mjs';
|
|
1
|
+
import { isDev, detectEnvironment, formatDuration, getConsoleMethod, colors, getLevelColor } from './utils.mjs';
|
|
2
2
|
|
|
3
3
|
let globalEnv = {
|
|
4
4
|
service: "app",
|
|
@@ -16,9 +16,6 @@ function initLogger(config = {}) {
|
|
|
16
16
|
};
|
|
17
17
|
globalPretty = config.pretty ?? isDev();
|
|
18
18
|
}
|
|
19
|
-
function getConsoleMethod(level) {
|
|
20
|
-
return level === "error" ? "error" : level === "warn" ? "warn" : "log";
|
|
21
|
-
}
|
|
22
19
|
function emitWideEvent(level, event) {
|
|
23
20
|
const formatted = {
|
|
24
21
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -41,6 +38,25 @@ function emitTaggedLog(level, tag, message) {
|
|
|
41
38
|
emitWideEvent(level, { tag, message });
|
|
42
39
|
}
|
|
43
40
|
}
|
|
41
|
+
function formatValue(value) {
|
|
42
|
+
if (value === null || value === void 0) {
|
|
43
|
+
return String(value);
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "object") {
|
|
46
|
+
const pairs = [];
|
|
47
|
+
for (const [k, v] of Object.entries(value)) {
|
|
48
|
+
if (v !== void 0 && v !== null) {
|
|
49
|
+
if (typeof v === "object") {
|
|
50
|
+
pairs.push(`${k}=${JSON.stringify(v)}`);
|
|
51
|
+
} else {
|
|
52
|
+
pairs.push(`${k}=${v}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return pairs.join(" ");
|
|
57
|
+
}
|
|
58
|
+
return String(value);
|
|
59
|
+
}
|
|
44
60
|
function prettyPrintWideEvent(event) {
|
|
45
61
|
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
46
62
|
const levelColor = getLevelColor(level);
|
|
@@ -52,24 +68,24 @@ function prettyPrintWideEvent(event) {
|
|
|
52
68
|
delete rest.method;
|
|
53
69
|
delete rest.path;
|
|
54
70
|
}
|
|
55
|
-
if (rest.duration) {
|
|
56
|
-
header += ` ${colors.dim}${rest.duration}${colors.reset}`;
|
|
57
|
-
delete rest.duration;
|
|
58
|
-
}
|
|
59
71
|
if (rest.status) {
|
|
60
72
|
const statusColor = rest.status >= 400 ? colors.red : colors.green;
|
|
61
73
|
header += ` ${statusColor}${rest.status}${colors.reset}`;
|
|
62
74
|
delete rest.status;
|
|
63
75
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (value !== void 0) {
|
|
68
|
-
const formatted = typeof value === "object" ? JSON.stringify(value) : value;
|
|
69
|
-
console.log(` ${colors.dim}${key}:${colors.reset} ${formatted}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
76
|
+
if (rest.duration) {
|
|
77
|
+
header += ` ${colors.dim}in ${rest.duration}${colors.reset}`;
|
|
78
|
+
delete rest.duration;
|
|
72
79
|
}
|
|
80
|
+
console.log(header);
|
|
81
|
+
const entries = Object.entries(rest).filter(([_, v]) => v !== void 0);
|
|
82
|
+
const lastIndex = entries.length - 1;
|
|
83
|
+
entries.forEach(([key, value], index) => {
|
|
84
|
+
const isLast = index === lastIndex;
|
|
85
|
+
const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
|
|
86
|
+
const formatted = formatValue(value);
|
|
87
|
+
console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`);
|
|
88
|
+
});
|
|
73
89
|
}
|
|
74
90
|
function createLogMethod(level) {
|
|
75
91
|
return function logMethod(tagOrEvent, message) {
|
package/dist/nitro/plugin.mjs
CHANGED
|
@@ -1,29 +1,60 @@
|
|
|
1
|
-
import { defineNitroPlugin } from 'nitropack/runtime';
|
|
1
|
+
import { defineNitroPlugin, useRuntimeConfig } from 'nitropack/runtime';
|
|
2
2
|
import { initLogger, createRequestLogger } from '../logger.mjs';
|
|
3
3
|
import '../utils.mjs';
|
|
4
4
|
|
|
5
|
+
function matchesPattern(path, pattern) {
|
|
6
|
+
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/{{GLOBSTAR}}/g, ".*").replace(/\?/g, "[^/]");
|
|
7
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
8
|
+
return regex.test(path);
|
|
9
|
+
}
|
|
10
|
+
function shouldLog(path, include) {
|
|
11
|
+
if (!include || include.length === 0) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return include.some((pattern) => matchesPattern(path, pattern));
|
|
15
|
+
}
|
|
5
16
|
function getResponseStatus(event) {
|
|
6
|
-
|
|
17
|
+
if (event.node?.res?.statusCode) {
|
|
18
|
+
return event.node.res.statusCode;
|
|
19
|
+
}
|
|
20
|
+
if (event.response?.status) {
|
|
21
|
+
return event.response.status;
|
|
22
|
+
}
|
|
23
|
+
if (typeof event.context.status === "number") {
|
|
24
|
+
return event.context.status;
|
|
25
|
+
}
|
|
26
|
+
return 200;
|
|
7
27
|
}
|
|
8
28
|
const plugin = defineNitroPlugin((nitroApp) => {
|
|
9
|
-
|
|
29
|
+
const config = useRuntimeConfig();
|
|
30
|
+
const evlogConfig = config.evlog;
|
|
31
|
+
initLogger({
|
|
32
|
+
env: evlogConfig?.env,
|
|
33
|
+
pretty: evlogConfig?.pretty
|
|
34
|
+
});
|
|
10
35
|
nitroApp.hooks.hook("request", (event) => {
|
|
36
|
+
const e = event;
|
|
37
|
+
if (!shouldLog(e.path, evlogConfig?.include)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
11
40
|
const log = createRequestLogger({
|
|
12
|
-
method:
|
|
13
|
-
path:
|
|
14
|
-
requestId:
|
|
41
|
+
method: e.method,
|
|
42
|
+
path: e.path,
|
|
43
|
+
requestId: e.context.requestId || crypto.randomUUID()
|
|
15
44
|
});
|
|
16
|
-
|
|
45
|
+
e.context.log = log;
|
|
17
46
|
});
|
|
18
47
|
nitroApp.hooks.hook("afterResponse", (event) => {
|
|
19
|
-
const
|
|
48
|
+
const e = event;
|
|
49
|
+
const log = e.context.log;
|
|
20
50
|
if (log) {
|
|
21
|
-
log.set({ status: getResponseStatus(
|
|
51
|
+
log.set({ status: getResponseStatus(e) });
|
|
22
52
|
log.emit();
|
|
23
53
|
}
|
|
24
54
|
});
|
|
25
55
|
nitroApp.hooks.hook("error", (error, { event }) => {
|
|
26
|
-
const
|
|
56
|
+
const e = event;
|
|
57
|
+
const log = e?.context.log;
|
|
27
58
|
if (log) {
|
|
28
59
|
log.error(error);
|
|
29
60
|
}
|
package/dist/nuxt/module.d.mts
CHANGED
|
@@ -11,6 +11,13 @@ interface ModuleOptions {
|
|
|
11
11
|
* @default true in development, false in production
|
|
12
12
|
*/
|
|
13
13
|
pretty?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Route patterns to include in logging.
|
|
16
|
+
* Supports glob patterns like '/api/**'.
|
|
17
|
+
* If not set, all routes are logged.
|
|
18
|
+
* @example ['/api/**', '/auth/**']
|
|
19
|
+
*/
|
|
20
|
+
include?: string[];
|
|
14
21
|
}
|
|
15
22
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
16
23
|
|
package/dist/nuxt/module.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ interface ModuleOptions {
|
|
|
11
11
|
* @default true in development, false in production
|
|
12
12
|
*/
|
|
13
13
|
pretty?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Route patterns to include in logging.
|
|
16
|
+
* Supports glob patterns like '/api/**'.
|
|
17
|
+
* If not set, all routes are logged.
|
|
18
|
+
* @example ['/api/**', '/auth/**']
|
|
19
|
+
*/
|
|
20
|
+
include?: string[];
|
|
14
21
|
}
|
|
15
22
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
16
23
|
|
package/dist/nuxt/module.mjs
CHANGED
|
@@ -4,7 +4,7 @@ const module$1 = defineNuxtModule({
|
|
|
4
4
|
meta: {
|
|
5
5
|
name: "evlog",
|
|
6
6
|
configKey: "evlog",
|
|
7
|
-
docs: "https://
|
|
7
|
+
docs: "https://evlog.dev"
|
|
8
8
|
},
|
|
9
9
|
defaults: {},
|
|
10
10
|
setup(options, nuxt) {
|
|
@@ -15,30 +15,34 @@ const module$1 = defineNuxtModule({
|
|
|
15
15
|
};
|
|
16
16
|
addServerPlugin(resolver.resolve("../nitro/plugin"));
|
|
17
17
|
addPlugin({
|
|
18
|
-
src: resolver.resolve("../runtime/plugin
|
|
18
|
+
src: resolver.resolve("../runtime/client/plugin"),
|
|
19
19
|
mode: "client"
|
|
20
20
|
});
|
|
21
21
|
addImports([
|
|
22
22
|
{
|
|
23
23
|
name: "log",
|
|
24
|
-
from: resolver.resolve("../runtime/
|
|
24
|
+
from: resolver.resolve("../runtime/client/log")
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
name: "
|
|
27
|
+
name: "createEvlogError",
|
|
28
28
|
from: resolver.resolve("../error")
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "parseError",
|
|
32
|
+
from: resolver.resolve("../runtime/utils/parseError")
|
|
29
33
|
}
|
|
30
34
|
]);
|
|
31
35
|
addServerImports([
|
|
32
36
|
{
|
|
33
37
|
name: "useLogger",
|
|
34
|
-
from: resolver.resolve("../runtime/
|
|
38
|
+
from: resolver.resolve("../runtime/server/useLogger")
|
|
35
39
|
},
|
|
36
40
|
{
|
|
37
41
|
name: "log",
|
|
38
|
-
from: resolver.resolve("../runtime/
|
|
42
|
+
from: resolver.resolve("../runtime/client/log")
|
|
39
43
|
},
|
|
40
44
|
{
|
|
41
|
-
name: "
|
|
45
|
+
name: "createEvlogError",
|
|
42
46
|
from: resolver.resolve("../error")
|
|
43
47
|
}
|
|
44
48
|
]);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getConsoleMethod } from '../../utils.mjs';
|
|
2
|
+
|
|
1
3
|
const IS_CLIENT = typeof window !== "undefined";
|
|
2
4
|
let clientPretty = true;
|
|
3
5
|
let clientService = "client";
|
|
@@ -11,9 +13,6 @@ function initLog(options = {}) {
|
|
|
11
13
|
clientPretty = options.pretty ?? true;
|
|
12
14
|
clientService = options.service ?? "client";
|
|
13
15
|
}
|
|
14
|
-
function getConsoleMethod(level) {
|
|
15
|
-
return level === "error" ? "error" : level === "warn" ? "warn" : "log";
|
|
16
|
-
}
|
|
17
16
|
function emitClientWideEvent(level, event) {
|
|
18
17
|
const formatted = {
|
|
19
18
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { initLog } from './
|
|
1
|
+
import { initLog } from './log.mjs';
|
|
2
2
|
import { defineNuxtPlugin, useRuntimeConfig } from '#app';
|
|
3
|
+
import '../../utils.mjs';
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
+
const plugin = defineNuxtPlugin(() => {
|
|
5
6
|
const config = useRuntimeConfig();
|
|
6
7
|
const evlogConfig = config.public?.evlog;
|
|
7
8
|
initLog({
|
|
@@ -10,4 +11,4 @@ const plugin_client = defineNuxtPlugin((_nuxtApp) => {
|
|
|
10
11
|
});
|
|
11
12
|
});
|
|
12
13
|
|
|
13
|
-
export {
|
|
14
|
+
export { plugin as default };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function parseError(error) {
|
|
2
|
+
if (error && typeof error === "object" && "data" in error) {
|
|
3
|
+
const { data, message: fetchMessage, statusCode: fetchStatusCode } = error;
|
|
4
|
+
const evlogData = data?.data;
|
|
5
|
+
return {
|
|
6
|
+
message: data?.message || fetchMessage || "An error occurred",
|
|
7
|
+
status: data?.statusCode || fetchStatusCode || 500,
|
|
8
|
+
why: evlogData?.why,
|
|
9
|
+
fix: evlogData?.fix,
|
|
10
|
+
link: evlogData?.link,
|
|
11
|
+
raw: error
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (error instanceof Error) {
|
|
15
|
+
return {
|
|
16
|
+
message: error.message,
|
|
17
|
+
status: 500,
|
|
18
|
+
raw: error
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
message: String(error),
|
|
23
|
+
status: 500,
|
|
24
|
+
raw: error
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { parseError };
|
package/dist/types.d.mts
CHANGED
|
@@ -116,6 +116,8 @@ interface Log {
|
|
|
116
116
|
interface ErrorOptions {
|
|
117
117
|
/** What actually happened */
|
|
118
118
|
message: string;
|
|
119
|
+
/** HTTP status code (default: 500) */
|
|
120
|
+
status?: number;
|
|
119
121
|
/** Why this error occurred */
|
|
120
122
|
why?: string;
|
|
121
123
|
/** How to fix this issue */
|
|
@@ -125,11 +127,47 @@ interface ErrorOptions {
|
|
|
125
127
|
/** The original error that caused this */
|
|
126
128
|
cause?: Error;
|
|
127
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Options for creating a request logger
|
|
132
|
+
*/
|
|
133
|
+
interface RequestLoggerOptions {
|
|
134
|
+
method?: string;
|
|
135
|
+
path?: string;
|
|
136
|
+
requestId?: string;
|
|
137
|
+
}
|
|
128
138
|
/**
|
|
129
139
|
* H3 event context with evlog logger attached
|
|
130
140
|
*/
|
|
131
|
-
interface
|
|
141
|
+
interface H3EventContext {
|
|
132
142
|
log?: RequestLogger;
|
|
143
|
+
requestId?: string;
|
|
144
|
+
status?: number;
|
|
145
|
+
[key: string]: unknown;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Server event type for Nitro/h3 handlers
|
|
149
|
+
*/
|
|
150
|
+
interface ServerEvent {
|
|
151
|
+
method: string;
|
|
152
|
+
path: string;
|
|
153
|
+
context: H3EventContext;
|
|
154
|
+
node?: {
|
|
155
|
+
res?: {
|
|
156
|
+
statusCode?: number;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
response?: Response;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Parsed evlog error with all fields at the top level
|
|
163
|
+
*/
|
|
164
|
+
interface ParsedError {
|
|
165
|
+
message: string;
|
|
166
|
+
status: number;
|
|
167
|
+
why?: string;
|
|
168
|
+
fix?: string;
|
|
169
|
+
link?: string;
|
|
170
|
+
raw: unknown;
|
|
133
171
|
}
|
|
134
172
|
|
|
135
|
-
export type { BaseWideEvent, EnvironmentContext, ErrorOptions,
|
|
173
|
+
export type { BaseWideEvent, EnvironmentContext, ErrorOptions, H3EventContext, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, ServerEvent, WideEvent };
|
package/dist/types.d.ts
CHANGED
|
@@ -116,6 +116,8 @@ interface Log {
|
|
|
116
116
|
interface ErrorOptions {
|
|
117
117
|
/** What actually happened */
|
|
118
118
|
message: string;
|
|
119
|
+
/** HTTP status code (default: 500) */
|
|
120
|
+
status?: number;
|
|
119
121
|
/** Why this error occurred */
|
|
120
122
|
why?: string;
|
|
121
123
|
/** How to fix this issue */
|
|
@@ -125,11 +127,47 @@ interface ErrorOptions {
|
|
|
125
127
|
/** The original error that caused this */
|
|
126
128
|
cause?: Error;
|
|
127
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Options for creating a request logger
|
|
132
|
+
*/
|
|
133
|
+
interface RequestLoggerOptions {
|
|
134
|
+
method?: string;
|
|
135
|
+
path?: string;
|
|
136
|
+
requestId?: string;
|
|
137
|
+
}
|
|
128
138
|
/**
|
|
129
139
|
* H3 event context with evlog logger attached
|
|
130
140
|
*/
|
|
131
|
-
interface
|
|
141
|
+
interface H3EventContext {
|
|
132
142
|
log?: RequestLogger;
|
|
143
|
+
requestId?: string;
|
|
144
|
+
status?: number;
|
|
145
|
+
[key: string]: unknown;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Server event type for Nitro/h3 handlers
|
|
149
|
+
*/
|
|
150
|
+
interface ServerEvent {
|
|
151
|
+
method: string;
|
|
152
|
+
path: string;
|
|
153
|
+
context: H3EventContext;
|
|
154
|
+
node?: {
|
|
155
|
+
res?: {
|
|
156
|
+
statusCode?: number;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
response?: Response;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Parsed evlog error with all fields at the top level
|
|
163
|
+
*/
|
|
164
|
+
interface ParsedError {
|
|
165
|
+
message: string;
|
|
166
|
+
status: number;
|
|
167
|
+
why?: string;
|
|
168
|
+
fix?: string;
|
|
169
|
+
link?: string;
|
|
170
|
+
raw: unknown;
|
|
133
171
|
}
|
|
134
172
|
|
|
135
|
-
export type { BaseWideEvent, EnvironmentContext, ErrorOptions,
|
|
173
|
+
export type { BaseWideEvent, EnvironmentContext, ErrorOptions, H3EventContext, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, ServerEvent, WideEvent };
|
package/dist/utils.d.mts
CHANGED
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
import { EnvironmentContext } from './types.mjs';
|
|
1
|
+
import { EnvironmentContext, LogLevel } from './types.mjs';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Format duration for display
|
|
5
|
-
* < 1s: shows milliseconds (e.g., "42ms")
|
|
6
|
-
* >= 1s: shows seconds (e.g., "1.5s")
|
|
7
|
-
*/
|
|
8
3
|
declare function formatDuration(ms: number): string;
|
|
9
|
-
/**
|
|
10
|
-
* Check if running on server
|
|
11
|
-
*/
|
|
12
4
|
declare function isServer(): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Check if running on client
|
|
15
|
-
*/
|
|
16
5
|
declare function isClient(): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Check if in development mode
|
|
19
|
-
*/
|
|
20
6
|
declare function isDev(): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Auto-detect environment context from env variables
|
|
23
|
-
*/
|
|
24
7
|
declare function detectEnvironment(): Partial<EnvironmentContext>;
|
|
8
|
+
declare function getConsoleMethod(level: LogLevel): 'log' | 'error' | 'warn';
|
|
25
9
|
declare const colors: {
|
|
26
10
|
readonly reset: "\u001B[0m";
|
|
27
11
|
readonly bold: "\u001B[1m";
|
|
@@ -35,9 +19,6 @@ declare const colors: {
|
|
|
35
19
|
readonly white: "\u001B[37m";
|
|
36
20
|
readonly gray: "\u001B[90m";
|
|
37
21
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Get color for log level
|
|
40
|
-
*/
|
|
41
22
|
declare function getLevelColor(level: string): string;
|
|
42
23
|
|
|
43
|
-
export { colors, detectEnvironment, formatDuration, getLevelColor, isClient, isDev, isServer };
|
|
24
|
+
export { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isClient, isDev, isServer };
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
import { EnvironmentContext } from './types.js';
|
|
1
|
+
import { EnvironmentContext, LogLevel } from './types.js';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Format duration for display
|
|
5
|
-
* < 1s: shows milliseconds (e.g., "42ms")
|
|
6
|
-
* >= 1s: shows seconds (e.g., "1.5s")
|
|
7
|
-
*/
|
|
8
3
|
declare function formatDuration(ms: number): string;
|
|
9
|
-
/**
|
|
10
|
-
* Check if running on server
|
|
11
|
-
*/
|
|
12
4
|
declare function isServer(): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Check if running on client
|
|
15
|
-
*/
|
|
16
5
|
declare function isClient(): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Check if in development mode
|
|
19
|
-
*/
|
|
20
6
|
declare function isDev(): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Auto-detect environment context from env variables
|
|
23
|
-
*/
|
|
24
7
|
declare function detectEnvironment(): Partial<EnvironmentContext>;
|
|
8
|
+
declare function getConsoleMethod(level: LogLevel): 'log' | 'error' | 'warn';
|
|
25
9
|
declare const colors: {
|
|
26
10
|
readonly reset: "\u001B[0m";
|
|
27
11
|
readonly bold: "\u001B[1m";
|
|
@@ -35,9 +19,6 @@ declare const colors: {
|
|
|
35
19
|
readonly white: "\u001B[37m";
|
|
36
20
|
readonly gray: "\u001B[90m";
|
|
37
21
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Get color for log level
|
|
40
|
-
*/
|
|
41
22
|
declare function getLevelColor(level: string): string;
|
|
42
23
|
|
|
43
|
-
export { colors, detectEnvironment, formatDuration, getLevelColor, isClient, isDev, isServer };
|
|
24
|
+
export { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isClient, isDev, isServer };
|
package/dist/utils.mjs
CHANGED
|
@@ -26,6 +26,9 @@ function detectEnvironment() {
|
|
|
26
26
|
region: env.VERCEL_REGION || env.AWS_REGION || env.FLY_REGION || env.CF_REGION
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
+
function getConsoleMethod(level) {
|
|
30
|
+
return level === "error" ? "error" : level === "warn" ? "warn" : "log";
|
|
31
|
+
}
|
|
29
32
|
const colors = {
|
|
30
33
|
reset: "\x1B[0m",
|
|
31
34
|
bold: "\x1B[1m",
|
|
@@ -54,4 +57,4 @@ function getLevelColor(level) {
|
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
export { colors, detectEnvironment, formatDuration, getLevelColor, isClient, isDev, isServer };
|
|
60
|
+
export { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isClient, isDev, isServer };
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evlog",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Wide event logging library with structured error handling. Inspired by LoggingSucks.",
|
|
5
5
|
"author": "HugoRCD <contact@hrcd.fr>",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://evlog.dev",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/HugoRCD/evlog.git"
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
],
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "unbuild",
|
|
60
|
-
"dev:prepare": "unbuild
|
|
60
|
+
"dev:prepare": "unbuild",
|
|
61
61
|
"release": "bun run lint && bun run test && bun run build && changelogen --release && npm publish && git push --follow-tags",
|
|
62
62
|
"lint": "eslint .",
|
|
63
63
|
"lint:fix": "eslint . --fix",
|
|
@@ -74,15 +74,16 @@
|
|
|
74
74
|
"@nuxt/schema": "^4.3.0",
|
|
75
75
|
"@nuxt/test-utils": "^3.23.0",
|
|
76
76
|
"changelogen": "^0.6.2",
|
|
77
|
-
"h3": "^1.15.
|
|
78
|
-
"nitropack": "^2.13.
|
|
77
|
+
"h3": "^1.15.5",
|
|
78
|
+
"nitropack": "^2.13.1",
|
|
79
79
|
"nuxt": "^4.3.0",
|
|
80
80
|
"typescript": "^5.9.3",
|
|
81
|
-
"unbuild": "^3.
|
|
81
|
+
"unbuild": "^3.6.1"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
|
-
"h3": "^1.
|
|
85
|
-
"nitropack": "^2.
|
|
84
|
+
"h3": "^1.15.5",
|
|
85
|
+
"nitropack": "^2.13.1",
|
|
86
|
+
"ofetch": "^1.5.1"
|
|
86
87
|
},
|
|
87
88
|
"peerDependenciesMeta": {
|
|
88
89
|
"h3": {
|
|
@@ -90,6 +91,9 @@
|
|
|
90
91
|
},
|
|
91
92
|
"nitropack": {
|
|
92
93
|
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"ofetch": {
|
|
96
|
+
"optional": true
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Log } from '../../types.mjs';
|
|
2
|
-
|
|
3
|
-
declare function initLog(options?: {
|
|
4
|
-
pretty?: boolean;
|
|
5
|
-
service?: string;
|
|
6
|
-
}): void;
|
|
7
|
-
/**
|
|
8
|
-
* Universal logging API - works on both client and server.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* log.info('auth', 'User logged in')
|
|
13
|
-
* log.info({ action: 'checkout', items: 3 })
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
declare const log: Log;
|
|
17
|
-
|
|
18
|
-
export { initLog, log };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Log } from '../../types.js';
|
|
2
|
-
|
|
3
|
-
declare function initLog(options?: {
|
|
4
|
-
pretty?: boolean;
|
|
5
|
-
service?: string;
|
|
6
|
-
}): void;
|
|
7
|
-
/**
|
|
8
|
-
* Universal logging API - works on both client and server.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* log.info('auth', 'User logged in')
|
|
13
|
-
* log.info({ action: 'checkout', items: 3 })
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
declare const log: Log;
|
|
17
|
-
|
|
18
|
-
export { initLog, log };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { H3Event } from 'h3';
|
|
2
|
-
import { RequestLogger } from '../../types.mjs';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Get the request-scoped logger from the event context.
|
|
6
|
-
* Must be called within a server handler with an H3 event.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* export default defineEventHandler((event) => {
|
|
11
|
-
* const logger = useLogger(event)
|
|
12
|
-
* logger.set({ userId: '123' })
|
|
13
|
-
* logger.set({ action: 'checkout' })
|
|
14
|
-
* return { ok: true }
|
|
15
|
-
* // emit() is called automatically by the Nitro plugin
|
|
16
|
-
* })
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
declare function useLogger(event: H3Event): RequestLogger;
|
|
20
|
-
|
|
21
|
-
export { useLogger };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { H3Event } from 'h3';
|
|
2
|
-
import { RequestLogger } from '../../types.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Get the request-scoped logger from the event context.
|
|
6
|
-
* Must be called within a server handler with an H3 event.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* export default defineEventHandler((event) => {
|
|
11
|
-
* const logger = useLogger(event)
|
|
12
|
-
* logger.set({ userId: '123' })
|
|
13
|
-
* logger.set({ action: 'checkout' })
|
|
14
|
-
* return { ok: true }
|
|
15
|
-
* // emit() is called automatically by the Nitro plugin
|
|
16
|
-
* })
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
declare function useLogger(event: H3Event): RequestLogger;
|
|
20
|
-
|
|
21
|
-
export { useLogger };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|