evlog 1.8.0 → 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.
- package/README.md +257 -62
- package/dist/nuxt/module.d.mts +6 -0
- package/dist/nuxt/module.d.mts.map +1 -1
- package/dist/nuxt/module.mjs +8 -2
- package/dist/nuxt/module.mjs.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -4,13 +4,12 @@
|
|
|
4
4
|
[](https://npm.chart.dev/evlog)
|
|
5
5
|
[](https://github.com/HugoRCD/evlog/actions/workflows/ci.yml)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
|
-
[](https://nuxt.com/)
|
|
8
7
|
[](https://evlog.dev)
|
|
9
8
|
[](https://github.com/HugoRCD/evlog/blob/main/LICENSE)
|
|
10
9
|
|
|
11
10
|
**Your logs are lying to you.**
|
|
12
11
|
|
|
13
|
-
A single request generates 10+ log lines. When production breaks at 3am, you're grep-ing through noise, praying you'll find signal. Your errors say "Something went wrong"
|
|
12
|
+
A single request generates 10+ log lines. When production breaks at 3am, you're grep-ing through noise, praying you'll find signal. Your errors say "Something went wrong" -- thanks, very helpful.
|
|
14
13
|
|
|
15
14
|
**evlog fixes this.** One log per request. All context included. Errors that explain themselves.
|
|
16
15
|
|
|
@@ -21,13 +20,13 @@ A single request generates 10+ log lines. When production breaks at 3am, you're
|
|
|
21
20
|
```typescript
|
|
22
21
|
// server/api/checkout.post.ts
|
|
23
22
|
|
|
24
|
-
//
|
|
23
|
+
// Scattered logs - impossible to debug
|
|
25
24
|
console.log('Request received')
|
|
26
25
|
console.log('User:', user.id)
|
|
27
26
|
console.log('Cart loaded')
|
|
28
27
|
console.log('Payment failed') // Good luck finding this at 3am
|
|
29
28
|
|
|
30
|
-
throw new Error('Something went wrong')
|
|
29
|
+
throw new Error('Something went wrong')
|
|
31
30
|
```
|
|
32
31
|
|
|
33
32
|
### The Solution
|
|
@@ -36,7 +35,7 @@ throw new Error('Something went wrong') // 🤷♂️
|
|
|
36
35
|
// server/api/checkout.post.ts
|
|
37
36
|
import { useLogger } from 'evlog'
|
|
38
37
|
|
|
39
|
-
//
|
|
38
|
+
// One comprehensive event per request
|
|
40
39
|
export default defineEventHandler(async (event) => {
|
|
41
40
|
const log = useLogger(event) // Auto-injected by evlog
|
|
42
41
|
|
|
@@ -176,18 +175,43 @@ The wide event emitted at the end contains **everything**:
|
|
|
176
175
|
|
|
177
176
|
Works with **any framework powered by Nitro**: Nuxt, Analog, Vinxi, SolidStart, TanStack Start, and more.
|
|
178
177
|
|
|
178
|
+
### Nitro v3
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
// nitro.config.ts
|
|
182
|
+
import { defineConfig } from 'nitro'
|
|
183
|
+
import evlog from 'evlog/nitro/v3'
|
|
184
|
+
|
|
185
|
+
export default defineConfig({
|
|
186
|
+
modules: [
|
|
187
|
+
evlog({ env: { service: 'my-api' } })
|
|
188
|
+
],
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Nitro v2
|
|
193
|
+
|
|
179
194
|
```typescript
|
|
180
195
|
// nitro.config.ts
|
|
196
|
+
import { defineNitroConfig } from 'nitropack/config'
|
|
197
|
+
import evlog from 'evlog/nitro'
|
|
198
|
+
|
|
181
199
|
export default defineNitroConfig({
|
|
182
|
-
|
|
200
|
+
modules: [
|
|
201
|
+
evlog({ env: { service: 'my-api' } })
|
|
202
|
+
],
|
|
183
203
|
})
|
|
184
204
|
```
|
|
185
205
|
|
|
186
|
-
|
|
206
|
+
Then use `useLogger` in any route. Import from `evlog/nitro/v3` (v3) or `evlog/nitro` (v2):
|
|
187
207
|
|
|
188
208
|
```typescript
|
|
189
209
|
// routes/api/documents/[id]/export.post.ts
|
|
190
|
-
import { useLogger
|
|
210
|
+
// Nitro v3: import { defineHandler } from 'nitro/h3' + import { useLogger } from 'evlog/nitro/v3'
|
|
211
|
+
// Nitro v2: import { defineEventHandler } from 'h3' + import { useLogger } from 'evlog/nitro'
|
|
212
|
+
import { defineEventHandler } from 'h3'
|
|
213
|
+
import { useLogger } from 'evlog/nitro'
|
|
214
|
+
import { createError } from 'evlog'
|
|
191
215
|
|
|
192
216
|
export default defineEventHandler(async (event) => {
|
|
193
217
|
const log = useLogger(event)
|
|
@@ -248,47 +272,6 @@ Output when the export completes:
|
|
|
248
272
|
}
|
|
249
273
|
```
|
|
250
274
|
|
|
251
|
-
## Structured Errors
|
|
252
|
-
|
|
253
|
-
Errors should tell you **what** happened, **why**, and **how to fix it**.
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
// server/api/repos/sync.post.ts
|
|
257
|
-
import { useLogger, createError } from 'evlog'
|
|
258
|
-
|
|
259
|
-
export default defineEventHandler(async (event) => {
|
|
260
|
-
const log = useLogger(event)
|
|
261
|
-
|
|
262
|
-
log.set({ repo: { owner: 'acme', name: 'my-project' } })
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
const result = await syncWithGitHub()
|
|
266
|
-
log.set({ sync: { commits: result.commits, files: result.files } })
|
|
267
|
-
return result
|
|
268
|
-
} catch (error) {
|
|
269
|
-
log.error(error, { step: 'github-sync' })
|
|
270
|
-
|
|
271
|
-
throw createError({
|
|
272
|
-
message: 'Failed to sync repository',
|
|
273
|
-
status: 503,
|
|
274
|
-
why: 'GitHub API rate limit exceeded',
|
|
275
|
-
fix: 'Wait 1 hour or use a different token',
|
|
276
|
-
link: 'https://docs.github.com/en/rest/rate-limit',
|
|
277
|
-
cause: error,
|
|
278
|
-
})
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Console output (development):
|
|
284
|
-
|
|
285
|
-
```
|
|
286
|
-
Error: Failed to sync repository
|
|
287
|
-
Why: GitHub API rate limit exceeded
|
|
288
|
-
Fix: Wait 1 hour or use a different token
|
|
289
|
-
More info: https://docs.github.com/en/rest/rate-limit
|
|
290
|
-
```
|
|
291
|
-
|
|
292
275
|
## Standalone TypeScript
|
|
293
276
|
|
|
294
277
|
For scripts, workers, or any TypeScript project:
|
|
@@ -390,6 +373,130 @@ Notes:
|
|
|
390
373
|
- `request.cf` is included (colo, country, asn) unless disabled
|
|
391
374
|
- Use `headerAllowlist` to avoid logging sensitive headers
|
|
392
375
|
|
|
376
|
+
## Hono
|
|
377
|
+
|
|
378
|
+
Use the standalone API to create one wide event per request from a Hono middleware.
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
// src/index.ts
|
|
382
|
+
import { serve } from '@hono/node-server'
|
|
383
|
+
import { Hono } from 'hono'
|
|
384
|
+
import { createRequestLogger, initLogger } from 'evlog'
|
|
385
|
+
|
|
386
|
+
initLogger({
|
|
387
|
+
env: { service: 'hono-api' },
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
const app = new Hono()
|
|
391
|
+
|
|
392
|
+
app.use('*', async (c, next) => {
|
|
393
|
+
const startedAt = Date.now()
|
|
394
|
+
const log = createRequestLogger({ method: c.req.method, path: c.req.path })
|
|
395
|
+
|
|
396
|
+
try {
|
|
397
|
+
await next()
|
|
398
|
+
} catch (error) {
|
|
399
|
+
log.error(error as Error)
|
|
400
|
+
throw error
|
|
401
|
+
} finally {
|
|
402
|
+
log.emit({
|
|
403
|
+
status: c.res.status,
|
|
404
|
+
duration: Date.now() - startedAt,
|
|
405
|
+
})
|
|
406
|
+
}
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
app.get('/health', (c) => c.json({ ok: true }))
|
|
410
|
+
|
|
411
|
+
serve({ fetch: app.fetch, port: 3000 })
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
See the full [hono example](https://github.com/HugoRCD/evlog/tree/main/examples/hono) for a complete working project.
|
|
415
|
+
|
|
416
|
+
## Browser
|
|
417
|
+
|
|
418
|
+
Use the `log` API on the client side for structured browser logging:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
import { log } from 'evlog/browser'
|
|
422
|
+
|
|
423
|
+
log.info('checkout', 'User initiated checkout')
|
|
424
|
+
log.error({ action: 'payment', error: 'validation_failed' })
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
In Nuxt, `log` is auto-imported -- no import needed in Vue components:
|
|
428
|
+
|
|
429
|
+
```vue
|
|
430
|
+
<script setup>
|
|
431
|
+
log.info('checkout', 'User initiated checkout')
|
|
432
|
+
</script>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Client logs output to the browser console with colored tags in development.
|
|
436
|
+
|
|
437
|
+
### Client Transport
|
|
438
|
+
|
|
439
|
+
To send client logs to the server for centralized logging, enable the transport:
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// nuxt.config.ts
|
|
443
|
+
export default defineNuxtConfig({
|
|
444
|
+
modules: ['evlog/nuxt'],
|
|
445
|
+
evlog: {
|
|
446
|
+
transport: {
|
|
447
|
+
enabled: true, // Send client logs to server
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
})
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
When enabled:
|
|
454
|
+
1. Client logs are sent to `/api/_evlog/ingest` via POST
|
|
455
|
+
2. Server enriches with environment context (service, version, etc.)
|
|
456
|
+
3. `evlog:drain` hook is called with `source: 'client'`
|
|
457
|
+
4. External services receive the log
|
|
458
|
+
|
|
459
|
+
## Structured Errors
|
|
460
|
+
|
|
461
|
+
Errors should tell you **what** happened, **why**, and **how to fix it**.
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
// server/api/repos/sync.post.ts
|
|
465
|
+
import { useLogger, createError } from 'evlog'
|
|
466
|
+
|
|
467
|
+
export default defineEventHandler(async (event) => {
|
|
468
|
+
const log = useLogger(event)
|
|
469
|
+
|
|
470
|
+
log.set({ repo: { owner: 'acme', name: 'my-project' } })
|
|
471
|
+
|
|
472
|
+
try {
|
|
473
|
+
const result = await syncWithGitHub()
|
|
474
|
+
log.set({ sync: { commits: result.commits, files: result.files } })
|
|
475
|
+
return result
|
|
476
|
+
} catch (error) {
|
|
477
|
+
log.error(error, { step: 'github-sync' })
|
|
478
|
+
|
|
479
|
+
throw createError({
|
|
480
|
+
message: 'Failed to sync repository',
|
|
481
|
+
status: 503,
|
|
482
|
+
why: 'GitHub API rate limit exceeded',
|
|
483
|
+
fix: 'Wait 1 hour or use a different token',
|
|
484
|
+
link: 'https://docs.github.com/en/rest/rate-limit',
|
|
485
|
+
cause: error,
|
|
486
|
+
})
|
|
487
|
+
}
|
|
488
|
+
})
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Console output (development):
|
|
492
|
+
|
|
493
|
+
```
|
|
494
|
+
Error: Failed to sync repository
|
|
495
|
+
Why: GitHub API rate limit exceeded
|
|
496
|
+
Fix: Wait 1 hour or use a different token
|
|
497
|
+
More info: https://docs.github.com/en/rest/rate-limit
|
|
498
|
+
```
|
|
499
|
+
|
|
393
500
|
## Enrichment Hook
|
|
394
501
|
|
|
395
502
|
Use the `evlog:enrich` hook to add derived context after emit, before drain.
|
|
@@ -428,6 +535,58 @@ export default defineNitroPlugin((nitroApp) => {
|
|
|
428
535
|
})
|
|
429
536
|
```
|
|
430
537
|
|
|
538
|
+
Each enricher adds a specific field to the event:
|
|
539
|
+
|
|
540
|
+
| Enricher | Event Field | Shape |
|
|
541
|
+
|----------|-------------|-------|
|
|
542
|
+
| `createUserAgentEnricher()` | `event.userAgent` | `{ raw, browser?: { name, version? }, os?: { name, version? }, device?: { type } }` |
|
|
543
|
+
| `createGeoEnricher()` | `event.geo` | `{ country?, region?, regionCode?, city?, latitude?, longitude? }` |
|
|
544
|
+
| `createRequestSizeEnricher()` | `event.requestSize` | `{ requestBytes?, responseBytes? }` |
|
|
545
|
+
| `createTraceContextEnricher()` | `event.traceContext` + `event.traceId` + `event.spanId` | `{ traceparent?, tracestate?, traceId?, spanId? }` |
|
|
546
|
+
|
|
547
|
+
All enrichers accept an optional `{ overwrite?: boolean }` option. By default (`overwrite: false`), user-provided data on the event takes precedence over enricher-computed values. Set `overwrite: true` to always replace existing fields.
|
|
548
|
+
|
|
549
|
+
> **Cloudflare geo note:** Only `cf-ipcountry` is a real Cloudflare HTTP header. The `cf-region`, `cf-city`, `cf-latitude`, `cf-longitude` headers are NOT standard -- they are properties of `request.cf`. For full geo data on Cloudflare, write a custom enricher that reads `request.cf`, or use a Workers middleware to forward `cf` properties as custom headers.
|
|
550
|
+
|
|
551
|
+
### Custom Enrichers
|
|
552
|
+
|
|
553
|
+
The `evlog:enrich` hook receives an `EnrichContext` with these fields:
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
interface EnrichContext {
|
|
557
|
+
event: WideEvent // The emitted wide event (mutable -- modify it directly)
|
|
558
|
+
request?: { // Request metadata
|
|
559
|
+
method?: string
|
|
560
|
+
path?: string
|
|
561
|
+
requestId?: string
|
|
562
|
+
}
|
|
563
|
+
headers?: Record<string, string> // Safe HTTP headers (sensitive headers filtered)
|
|
564
|
+
response?: { // Response metadata
|
|
565
|
+
status?: number
|
|
566
|
+
headers?: Record<string, string>
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Example custom enricher:
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
// server/plugins/evlog-enrich.ts
|
|
575
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
576
|
+
nitroApp.hooks.hook('evlog:enrich', (ctx) => {
|
|
577
|
+
// Add deployment metadata
|
|
578
|
+
ctx.event.deploymentId = process.env.DEPLOYMENT_ID
|
|
579
|
+
ctx.event.region = process.env.FLY_REGION
|
|
580
|
+
|
|
581
|
+
// Extract data from headers
|
|
582
|
+
const tenantId = ctx.headers?.['x-tenant-id']
|
|
583
|
+
if (tenantId) {
|
|
584
|
+
ctx.event.tenantId = tenantId
|
|
585
|
+
}
|
|
586
|
+
})
|
|
587
|
+
})
|
|
588
|
+
```
|
|
589
|
+
|
|
431
590
|
## Adapters
|
|
432
591
|
|
|
433
592
|
Send your logs to external observability platforms with built-in adapters.
|
|
@@ -469,6 +628,24 @@ Set environment variables:
|
|
|
469
628
|
NUXT_OTLP_ENDPOINT=http://localhost:4318
|
|
470
629
|
```
|
|
471
630
|
|
|
631
|
+
### PostHog
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
// server/plugins/evlog-drain.ts
|
|
635
|
+
import { createPostHogDrain } from 'evlog/posthog'
|
|
636
|
+
|
|
637
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
638
|
+
nitroApp.hooks.hook('evlog:drain', createPostHogDrain())
|
|
639
|
+
})
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
Set environment variables:
|
|
643
|
+
|
|
644
|
+
```bash
|
|
645
|
+
NUXT_POSTHOG_API_KEY=phc_your-key
|
|
646
|
+
NUXT_POSTHOG_HOST=https://us.i.posthog.com # Optional: for EU or self-hosted
|
|
647
|
+
```
|
|
648
|
+
|
|
472
649
|
### Sentry
|
|
473
650
|
|
|
474
651
|
```typescript
|
|
@@ -486,6 +663,23 @@ Set environment variables:
|
|
|
486
663
|
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
|
|
487
664
|
```
|
|
488
665
|
|
|
666
|
+
### Better Stack
|
|
667
|
+
|
|
668
|
+
```typescript
|
|
669
|
+
// server/plugins/evlog-drain.ts
|
|
670
|
+
import { createBetterStackDrain } from 'evlog/better-stack'
|
|
671
|
+
|
|
672
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
673
|
+
nitroApp.hooks.hook('evlog:drain', createBetterStackDrain())
|
|
674
|
+
})
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
Set environment variables:
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
NUXT_BETTER_STACK_SOURCE_TOKEN=your-source-token
|
|
681
|
+
```
|
|
682
|
+
|
|
489
683
|
### Multiple Destinations
|
|
490
684
|
|
|
491
685
|
Send logs to multiple services:
|
|
@@ -571,15 +765,15 @@ export default defineNitroPlugin((nitroApp) => {
|
|
|
571
765
|
| `retry.initialDelayMs` | `1000` | Base delay for first retry |
|
|
572
766
|
| `retry.maxDelayMs` | `30000` | Upper bound for any retry delay |
|
|
573
767
|
| `maxBufferSize` | `1000` | Max buffered events before dropping oldest |
|
|
574
|
-
| `onDropped` |
|
|
768
|
+
| `onDropped` | -- | Callback when events are dropped |
|
|
575
769
|
|
|
576
770
|
### Returned drain function
|
|
577
771
|
|
|
578
772
|
The function returned by `pipeline(drain)` is hook-compatible and exposes:
|
|
579
773
|
|
|
580
|
-
- **`drain(ctx)`**
|
|
581
|
-
- **`drain.flush()`**
|
|
582
|
-
- **`drain.pending`**
|
|
774
|
+
- **`drain(ctx)`** -- Push a single event into the buffer
|
|
775
|
+
- **`drain.flush()`** -- Force-flush all buffered events (call on server shutdown)
|
|
776
|
+
- **`drain.pending`** -- Number of events currently buffered
|
|
583
777
|
|
|
584
778
|
## API Reference
|
|
585
779
|
|
|
@@ -589,7 +783,7 @@ Initialize the logger. Required for standalone usage, automatic with Nuxt/Nitro
|
|
|
589
783
|
|
|
590
784
|
```typescript
|
|
591
785
|
initLogger({
|
|
592
|
-
enabled: boolean //
|
|
786
|
+
enabled: boolean // Optional. Enable/disable all logging (default: true)
|
|
593
787
|
env: {
|
|
594
788
|
service: string // Service name
|
|
595
789
|
environment: string // 'production' | 'development' | 'test'
|
|
@@ -680,9 +874,9 @@ In development, evlog uses a compact tree format:
|
|
|
680
874
|
|
|
681
875
|
```
|
|
682
876
|
16:45:31.060 INFO [my-app] GET /api/checkout 200 in 234ms
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
877
|
+
|- user: id=123 plan=premium
|
|
878
|
+
|- cart: items=3 total=9999
|
|
879
|
+
+- payment: id=pay_xyz method=card
|
|
686
880
|
```
|
|
687
881
|
|
|
688
882
|
In production (`pretty: false`), logs are emitted as JSON for machine parsing.
|
|
@@ -798,11 +992,12 @@ evlog works with any framework powered by [Nitro](https://nitro.unjs.io/):
|
|
|
798
992
|
| Framework | Integration |
|
|
799
993
|
|-----------|-------------|
|
|
800
994
|
| **Nuxt** | `modules: ['evlog/nuxt']` |
|
|
801
|
-
| **
|
|
802
|
-
| **
|
|
803
|
-
| **
|
|
804
|
-
| **
|
|
805
|
-
| **
|
|
995
|
+
| **Nitro v3** | `modules: [evlog()]` with `import evlog from 'evlog/nitro/v3'` |
|
|
996
|
+
| **Nitro v2** | `modules: [evlog()]` with `import evlog from 'evlog/nitro'` |
|
|
997
|
+
| **Analog** | Nitro v2 module setup |
|
|
998
|
+
| **Vinxi** | Nitro v2 module setup |
|
|
999
|
+
| **SolidStart** | Nitro v2 module setup ([example](./examples/solidstart)) |
|
|
1000
|
+
| **TanStack Start** | Nitro v2 module setup |
|
|
806
1001
|
|
|
807
1002
|
## Agent Skills
|
|
808
1003
|
|
package/dist/nuxt/module.d.mts
CHANGED
|
@@ -151,6 +151,12 @@ interface ModuleOptions {
|
|
|
151
151
|
tags?: Record<string, string>; /** Request timeout in milliseconds. Default: 5000 */
|
|
152
152
|
timeout?: number;
|
|
153
153
|
};
|
|
154
|
+
/**
|
|
155
|
+
* How long to retain events before cleanup (used by @evlog/nuxthub).
|
|
156
|
+
* Supports "30d" (days), "24h" (hours), "60m" (minutes).
|
|
157
|
+
* @default '30d'
|
|
158
|
+
*/
|
|
159
|
+
retention?: string;
|
|
154
160
|
}
|
|
155
161
|
declare const _default: _nuxt_schema0.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
156
162
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nuxt/module.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nuxt/module.ts"],"mappings":";;;;UAaiB,aAAA;;;AAAjB;;;EAME,OAAA;EAKM;;;EAAN,GAAA,GAAM,OAAA,CAAQ,kBAAA;EAoEF;;;;EA9DZ,MAAA;EA+Je;;;;;;EAvJf,OAAA;EAQA;;;;;;EAAA,OAAA;EA8CY;;;;;;;;;;;;;EA/BZ,MAAA,GAAS,MAAA,SAAe,WAAA;EAkFtB;;;;;;;;;;;;;;;;EAhEF,QAAA,GAAW,cAAA;EAyHZ;;;;;;;;;;;EA5GC,SAAA,GAAY,eAAA;;;;;;;;;;;;;EAcZ,KAAA;6BAEE,OAAA;IAEA,KAAA;IAEA,KAAA;IAEA,OAAA;IAEA,OAAA;EAAA;;;;;;;;;;;;;;;EAiBF,IAAA;2DAEE,QAAA;IAEA,WAAA;IAEA,kBAAA,GAAqB,MAAA;IAErB,OAAA,GAAU,MAAA;IAEV,OAAA;EAAA;;;;;;;;;;;;EAcF,OAAA;kCAEE,MAAA;IAEA,IAAA;IAEA,SAAA;IAEA,UAAA;IAEA,OAAA;EAAA;;;;;;;;;;;;EAcF,MAAA;qBAEE,GAAA;IAEA,WAAA;IAEA,OAAA;IAEA,IAAA,GAAO,MAAA;IAEP,OAAA;EAAA;;;;;;EAQF,SAAA;AAAA;AAAA,cACD,QAAA"}
|
package/dist/nuxt/module.mjs
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { addImports, addPlugin, addServerHandler, addServerImports, addServerPlugin, createResolver, defineNuxtModule } from "@nuxt/kit";
|
|
2
2
|
|
|
3
|
+
//#region package.json
|
|
4
|
+
var name = "evlog";
|
|
5
|
+
var version = "1.9.0";
|
|
6
|
+
|
|
7
|
+
//#endregion
|
|
3
8
|
//#region src/nuxt/module.ts
|
|
4
9
|
var module_default = defineNuxtModule({
|
|
5
10
|
meta: {
|
|
6
|
-
name
|
|
7
|
-
|
|
11
|
+
name,
|
|
12
|
+
version,
|
|
13
|
+
configKey: name,
|
|
8
14
|
docs: "https://evlog.dev"
|
|
9
15
|
},
|
|
10
16
|
defaults: {},
|
package/dist/nuxt/module.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":[],"sources":["../../src/nuxt/module.ts"],"sourcesContent":["import {\n addImports,\n addPlugin,\n addServerHandler,\n addServerImports,\n addServerPlugin,\n createResolver,\n defineNuxtModule,\n} from '@nuxt/kit'\nimport type { NitroConfig } from 'nitropack'\nimport type { EnvironmentContext, RouteConfig, SamplingConfig, TransportConfig } from '../types'\n\nexport interface ModuleOptions {\n /**\n * Enable or disable all logging globally.\n * When false, all emits, tagged logs, and request logger operations become no-ops.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n * @example ['/api/**', '/auth/**']\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/api/_nuxt_icon/**'.\n * Exclusions take precedence over inclusions.\n * @example ['/api/_nuxt_icon/**', '/health']\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n * Allows setting different service names for different routes.\n * Patterns are matched using glob syntax.\n *\n * @example\n * ```ts\n * routes: {\n * '/api/foo/**': { service: 'service1' },\n * '/api/bar/**': { service: 'service2' }\n * }\n * ```\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n * Allows configuring what percentage of logs to keep per level.\n *\n * @example\n * ```ts\n * sampling: {\n * rates: {\n * info: 10, // Keep 10% of info logs\n * warn: 50, // Keep 50% of warning logs\n * debug: 5, // Keep 5% of debug logs\n * error: 100, // Always keep errors (default)\n * }\n * }\n * ```\n */\n sampling?: SamplingConfig\n\n /**\n * Transport configuration for sending client logs to the server.\n *\n * @example\n * ```ts\n * transport: {\n * enabled: true, // Send logs to server API\n * endpoint: '/api/_evlog/ingest' // Custom endpoint\n * }\n * ```\n */\n transport?: TransportConfig\n\n /**\n * Axiom adapter configuration.\n * When configured, use `createAxiomDrain()` from `evlog/axiom` to send logs.\n *\n * @example\n * ```ts\n * axiom: {\n * dataset: 'my-app-logs',\n * token: process.env.AXIOM_TOKEN,\n * }\n * ```\n */\n axiom?: {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Base URL for Axiom API. Default: https://api.axiom.co */\n baseUrl?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * OTLP adapter configuration.\n * When configured, use `createOTLPDrain()` from `evlog/otlp` to send logs.\n *\n * @example\n * ```ts\n * otlp: {\n * endpoint: 'http://localhost:4318',\n * headers: {\n * 'Authorization': `Basic ${process.env.GRAFANA_TOKEN}`,\n * },\n * }\n * ```\n */\n otlp?: {\n /** OTLP HTTP endpoint (e.g., http://localhost:4318) */\n endpoint: string\n /** Override service name (defaults to event.service) */\n serviceName?: string\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Custom headers (e.g., for authentication) */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * PostHog adapter configuration.\n * When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs.\n *\n * @example\n * ```ts\n * posthog: {\n * apiKey: process.env.POSTHOG_API_KEY,\n * }\n * ```\n */\n posthog?: {\n /** PostHog project API key */\n apiKey: string\n /** PostHog host URL. Default: https://us.i.posthog.com */\n host?: string\n /** PostHog event name. Default: evlog_wide_event */\n eventName?: string\n /** Override distinct_id (defaults to event.service) */\n distinctId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * Sentry adapter configuration.\n * When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.\n *\n * @example\n * ```ts\n * sentry: {\n * dsn: process.env.SENTRY_DSN,\n * }\n * ```\n */\n sentry?: {\n /** Sentry DSN */\n dsn: string\n /** Environment override (defaults to event.environment) */\n environment?: string\n /** Release version override (defaults to event.version) */\n release?: string\n /** Additional tags to attach as attributes */\n tags?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n}\n\nexport default defineNuxtModule<ModuleOptions>({\n meta: {\n name
|
|
1
|
+
{"version":3,"file":"module.mjs","names":[],"sources":["../../package.json","../../src/nuxt/module.ts"],"sourcesContent":["","import {\n addImports,\n addPlugin,\n addServerHandler,\n addServerImports,\n addServerPlugin,\n createResolver,\n defineNuxtModule,\n} from '@nuxt/kit'\nimport type { NitroConfig } from 'nitropack'\nimport type { EnvironmentContext, RouteConfig, SamplingConfig, TransportConfig } from '../types'\nimport { name, version } from '../../package.json'\n\nexport interface ModuleOptions {\n /**\n * Enable or disable all logging globally.\n * When false, all emits, tagged logs, and request logger operations become no-ops.\n * @default true\n */\n enabled?: boolean\n\n /**\n * Environment context overrides.\n */\n env?: Partial<EnvironmentContext>\n\n /**\n * Enable pretty printing.\n * @default true in development, false in production\n */\n pretty?: boolean\n\n /**\n * Route patterns to include in logging.\n * Supports glob patterns like '/api/**'.\n * If not set, all routes are logged.\n * @example ['/api/**', '/auth/**']\n */\n include?: string[]\n\n /**\n * Route patterns to exclude from logging.\n * Supports glob patterns like '/api/_nuxt_icon/**'.\n * Exclusions take precedence over inclusions.\n * @example ['/api/_nuxt_icon/**', '/health']\n */\n exclude?: string[]\n\n /**\n * Route-specific service configuration.\n * Allows setting different service names for different routes.\n * Patterns are matched using glob syntax.\n *\n * @example\n * ```ts\n * routes: {\n * '/api/foo/**': { service: 'service1' },\n * '/api/bar/**': { service: 'service2' }\n * }\n * ```\n */\n routes?: Record<string, RouteConfig>\n\n /**\n * Sampling configuration for filtering logs.\n * Allows configuring what percentage of logs to keep per level.\n *\n * @example\n * ```ts\n * sampling: {\n * rates: {\n * info: 10, // Keep 10% of info logs\n * warn: 50, // Keep 50% of warning logs\n * debug: 5, // Keep 5% of debug logs\n * error: 100, // Always keep errors (default)\n * }\n * }\n * ```\n */\n sampling?: SamplingConfig\n\n /**\n * Transport configuration for sending client logs to the server.\n *\n * @example\n * ```ts\n * transport: {\n * enabled: true, // Send logs to server API\n * endpoint: '/api/_evlog/ingest' // Custom endpoint\n * }\n * ```\n */\n transport?: TransportConfig\n\n /**\n * Axiom adapter configuration.\n * When configured, use `createAxiomDrain()` from `evlog/axiom` to send logs.\n *\n * @example\n * ```ts\n * axiom: {\n * dataset: 'my-app-logs',\n * token: process.env.AXIOM_TOKEN,\n * }\n * ```\n */\n axiom?: {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Base URL for Axiom API. Default: https://api.axiom.co */\n baseUrl?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * OTLP adapter configuration.\n * When configured, use `createOTLPDrain()` from `evlog/otlp` to send logs.\n *\n * @example\n * ```ts\n * otlp: {\n * endpoint: 'http://localhost:4318',\n * headers: {\n * 'Authorization': `Basic ${process.env.GRAFANA_TOKEN}`,\n * },\n * }\n * ```\n */\n otlp?: {\n /** OTLP HTTP endpoint (e.g., http://localhost:4318) */\n endpoint: string\n /** Override service name (defaults to event.service) */\n serviceName?: string\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Custom headers (e.g., for authentication) */\n headers?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * PostHog adapter configuration.\n * When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs.\n *\n * @example\n * ```ts\n * posthog: {\n * apiKey: process.env.POSTHOG_API_KEY,\n * }\n * ```\n */\n posthog?: {\n /** PostHog project API key */\n apiKey: string\n /** PostHog host URL. Default: https://us.i.posthog.com */\n host?: string\n /** PostHog event name. Default: evlog_wide_event */\n eventName?: string\n /** Override distinct_id (defaults to event.service) */\n distinctId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * Sentry adapter configuration.\n * When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.\n *\n * @example\n * ```ts\n * sentry: {\n * dsn: process.env.SENTRY_DSN,\n * }\n * ```\n */\n sentry?: {\n /** Sentry DSN */\n dsn: string\n /** Environment override (defaults to event.environment) */\n environment?: string\n /** Release version override (defaults to event.version) */\n release?: string\n /** Additional tags to attach as attributes */\n tags?: Record<string, string>\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n }\n\n /**\n * How long to retain events before cleanup (used by @evlog/nuxthub).\n * Supports \"30d\" (days), \"24h\" (hours), \"60m\" (minutes).\n * @default '30d'\n */\n retention?: string\n}\n\nexport default defineNuxtModule<ModuleOptions>({\n meta: {\n name,\n version,\n configKey: name,\n docs: 'https://evlog.dev',\n },\n defaults: {},\n setup(options, nuxt) {\n const resolver = createResolver(import.meta.url)\n\n const transportEnabled = options.transport?.enabled ?? false\n const transportEndpoint = options.transport?.endpoint ?? '/api/_evlog/ingest'\n\n // Register custom error handler for proper EvlogError serialization\n // Only set if not already configured to avoid overwriting user's custom handler\n // @ts-expect-error nitro:config hook exists but is not in NuxtHooks type\n nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => {\n nitroConfig.errorHandler = nitroConfig.errorHandler || resolver.resolve('../nitro/errorHandler')\n })\n\n nuxt.options.runtimeConfig.evlog = options\n nuxt.options.runtimeConfig.public.evlog = {\n enabled: options.enabled ?? true,\n pretty: options.pretty,\n transport: {\n enabled: transportEnabled,\n endpoint: transportEndpoint,\n },\n }\n\n if (transportEnabled) {\n addServerHandler({\n route: transportEndpoint,\n method: 'post',\n handler: resolver.resolve('../runtime/server/routes/_evlog/ingest.post'),\n })\n }\n\n addServerPlugin(resolver.resolve('../nitro/plugin'))\n\n addPlugin({\n src: resolver.resolve('../runtime/client/plugin'),\n mode: 'client',\n })\n\n addImports([\n {\n name: 'log',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'setIdentity',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'clearIdentity',\n from: resolver.resolve('../runtime/client/log'),\n },\n {\n name: 'createEvlogError',\n from: resolver.resolve('../error'),\n },\n {\n name: 'parseError',\n from: resolver.resolve('../runtime/utils/parseError'),\n },\n ])\n\n addServerImports([\n {\n name: 'useLogger',\n from: resolver.resolve('../runtime/server/useLogger'),\n },\n {\n name: 'log',\n from: resolver.resolve('../logger'),\n },\n {\n name: 'createEvlogError',\n from: resolver.resolve('../error'),\n },\n ])\n },\n})\n"],"mappings":";;;;;;;;AC0MA,qBAAe,iBAAgC;CAC7C,MAAM;EACJ;EACA;EACA,WAAW;EACX,MAAM;EACP;CACD,UAAU,EAAE;CACZ,MAAM,SAAS,MAAM;EACnB,MAAM,WAAW,eAAe,OAAO,KAAK,IAAI;EAEhD,MAAM,mBAAmB,QAAQ,WAAW,WAAW;EACvD,MAAM,oBAAoB,QAAQ,WAAW,YAAY;AAKzD,OAAK,KAAK,iBAAiB,gBAA6B;AACtD,eAAY,eAAe,YAAY,gBAAgB,SAAS,QAAQ,wBAAwB;IAChG;AAEF,OAAK,QAAQ,cAAc,QAAQ;AACnC,OAAK,QAAQ,cAAc,OAAO,QAAQ;GACxC,SAAS,QAAQ,WAAW;GAC5B,QAAQ,QAAQ;GAChB,WAAW;IACT,SAAS;IACT,UAAU;IACX;GACF;AAED,MAAI,iBACF,kBAAiB;GACf,OAAO;GACP,QAAQ;GACR,SAAS,SAAS,QAAQ,8CAA8C;GACzE,CAAC;AAGJ,kBAAgB,SAAS,QAAQ,kBAAkB,CAAC;AAEpD,YAAU;GACR,KAAK,SAAS,QAAQ,2BAA2B;GACjD,MAAM;GACP,CAAC;AAEF,aAAW;GACT;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,wBAAwB;IAChD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,wBAAwB;IAChD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,wBAAwB;IAChD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,WAAW;IACnC;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,8BAA8B;IACtD;GACF,CAAC;AAEF,mBAAiB;GACf;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,8BAA8B;IACtD;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,YAAY;IACpC;GACD;IACE,MAAM;IACN,MAAM,SAAS,QAAQ,WAAW;IACnC;GACF,CAAC;;CAEL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evlog",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Wide event logging library with structured error handling. Inspired by LoggingSucks.",
|
|
5
5
|
"author": "HugoRCD <contact@hrcd.fr>",
|
|
6
6
|
"homepage": "https://evlog.dev",
|
|
@@ -130,7 +130,6 @@
|
|
|
130
130
|
"build": "tsdown",
|
|
131
131
|
"dev": "tsdown --watch",
|
|
132
132
|
"dev:prepare": "tsdown",
|
|
133
|
-
"release": "bun run lint && bun run test && bun run build && changelogen --release && npm publish && git push --follow-tags",
|
|
134
133
|
"lint": "eslint .",
|
|
135
134
|
"lint:fix": "eslint . --fix",
|
|
136
135
|
"test": "vitest run",
|