evlog 1.3.0 → 1.5.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 +81 -1
- package/dist/adapters/posthog.d.mts +72 -0
- package/dist/adapters/posthog.d.ts +72 -0
- package/dist/adapters/posthog.mjs +79 -0
- package/dist/nitro/plugin.mjs +30 -9
- package/dist/nuxt/module.d.mts +15 -1
- package/dist/nuxt/module.d.ts +15 -1
- package/dist/runtime/server/useLogger.d.mts +10 -1
- package/dist/runtime/server/useLogger.d.ts +10 -1
- package/dist/runtime/server/useLogger.mjs +4 -1
- package/dist/types.d.mts +18 -2
- package/dist/types.d.ts +18 -2
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
[](https://npmjs.com/package/evlog)
|
|
4
4
|
[](https://npm.chart.dev/evlog)
|
|
5
5
|
[](https://github.com/HugoRCD/evlog/actions/workflows/ci.yml)
|
|
6
|
-
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://nuxt.com/)
|
|
8
|
+
[](https://evlog.dev)
|
|
8
9
|
[](https://github.com/HugoRCD/evlog/blob/main/LICENSE)
|
|
9
10
|
|
|
10
11
|
**Your logs are lying to you.**
|
|
@@ -389,6 +390,85 @@ Notes:
|
|
|
389
390
|
- `request.cf` is included (colo, country, asn) unless disabled
|
|
390
391
|
- Use `headerAllowlist` to avoid logging sensitive headers
|
|
391
392
|
|
|
393
|
+
## Adapters
|
|
394
|
+
|
|
395
|
+
Send your logs to external observability platforms with built-in adapters.
|
|
396
|
+
|
|
397
|
+
### Axiom
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
// server/plugins/evlog-drain.ts
|
|
401
|
+
import { createAxiomDrain } from 'evlog/axiom'
|
|
402
|
+
|
|
403
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
404
|
+
nitroApp.hooks.hook('evlog:drain', createAxiomDrain())
|
|
405
|
+
})
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Set environment variables:
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
NUXT_AXIOM_TOKEN=xaat-your-token
|
|
412
|
+
NUXT_AXIOM_DATASET=your-dataset
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### OTLP (OpenTelemetry)
|
|
416
|
+
|
|
417
|
+
Works with Grafana, Datadog, Honeycomb, and any OTLP-compatible backend.
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// server/plugins/evlog-drain.ts
|
|
421
|
+
import { createOTLPDrain } from 'evlog/otlp'
|
|
422
|
+
|
|
423
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
424
|
+
nitroApp.hooks.hook('evlog:drain', createOTLPDrain())
|
|
425
|
+
})
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Set environment variables:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
NUXT_OTLP_ENDPOINT=http://localhost:4318
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Multiple Destinations
|
|
435
|
+
|
|
436
|
+
Send logs to multiple services:
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
// server/plugins/evlog-drain.ts
|
|
440
|
+
import { createAxiomDrain } from 'evlog/axiom'
|
|
441
|
+
import { createOTLPDrain } from 'evlog/otlp'
|
|
442
|
+
|
|
443
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
444
|
+
const axiom = createAxiomDrain()
|
|
445
|
+
const otlp = createOTLPDrain()
|
|
446
|
+
|
|
447
|
+
nitroApp.hooks.hook('evlog:drain', async (ctx) => {
|
|
448
|
+
await Promise.allSettled([axiom(ctx), otlp(ctx)])
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Custom Adapters
|
|
454
|
+
|
|
455
|
+
Build your own adapter for any destination:
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// server/plugins/evlog-drain.ts
|
|
459
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
460
|
+
nitroApp.hooks.hook('evlog:drain', async (ctx) => {
|
|
461
|
+
await fetch('https://your-service.com/logs', {
|
|
462
|
+
method: 'POST',
|
|
463
|
+
headers: { 'Content-Type': 'application/json' },
|
|
464
|
+
body: JSON.stringify(ctx.event),
|
|
465
|
+
})
|
|
466
|
+
})
|
|
467
|
+
})
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
> See the [full documentation](https://evlog.hrcd.fr/adapters/overview) for adapter configuration options, troubleshooting, and advanced patterns.
|
|
471
|
+
|
|
392
472
|
## API Reference
|
|
393
473
|
|
|
394
474
|
### `initLogger(config)`
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.mjs';
|
|
2
|
+
|
|
3
|
+
interface PostHogConfig {
|
|
4
|
+
/** PostHog project API key */
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
7
|
+
host?: string;
|
|
8
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
9
|
+
eventName?: string;
|
|
10
|
+
/** Override distinct_id (defaults to event.service) */
|
|
11
|
+
distinctId?: string;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** PostHog event structure for the batch API */
|
|
16
|
+
interface PostHogEvent {
|
|
17
|
+
event: string;
|
|
18
|
+
distinct_id: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
properties: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert a WideEvent to a PostHog event format.
|
|
24
|
+
*/
|
|
25
|
+
declare function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHogEvent;
|
|
26
|
+
/**
|
|
27
|
+
* Create a drain function for sending logs to PostHog.
|
|
28
|
+
*
|
|
29
|
+
* Configuration priority (highest to lowest):
|
|
30
|
+
* 1. Overrides passed to createPostHogDrain()
|
|
31
|
+
* 2. runtimeConfig.evlog.posthog
|
|
32
|
+
* 3. runtimeConfig.posthog
|
|
33
|
+
* 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Zero config - just set NUXT_POSTHOG_API_KEY env var
|
|
38
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain())
|
|
39
|
+
*
|
|
40
|
+
* // With overrides
|
|
41
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain({
|
|
42
|
+
* apiKey: 'phc_...',
|
|
43
|
+
* host: 'https://eu.i.posthog.com',
|
|
44
|
+
* }))
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function createPostHogDrain(overrides?: Partial<PostHogConfig>): (ctx: DrainContext) => Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Send a single event to PostHog.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* await sendToPostHog(event, {
|
|
54
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function sendToPostHog(event: WideEvent, config: PostHogConfig): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Send a batch of events to PostHog.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* await sendBatchToPostHog(events, {
|
|
65
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function sendBatchToPostHog(events: WideEvent[], config: PostHogConfig): Promise<void>;
|
|
70
|
+
|
|
71
|
+
export { createPostHogDrain, sendBatchToPostHog, sendToPostHog, toPostHogEvent };
|
|
72
|
+
export type { PostHogConfig, PostHogEvent };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.js';
|
|
2
|
+
|
|
3
|
+
interface PostHogConfig {
|
|
4
|
+
/** PostHog project API key */
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
7
|
+
host?: string;
|
|
8
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
9
|
+
eventName?: string;
|
|
10
|
+
/** Override distinct_id (defaults to event.service) */
|
|
11
|
+
distinctId?: string;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** PostHog event structure for the batch API */
|
|
16
|
+
interface PostHogEvent {
|
|
17
|
+
event: string;
|
|
18
|
+
distinct_id: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
properties: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert a WideEvent to a PostHog event format.
|
|
24
|
+
*/
|
|
25
|
+
declare function toPostHogEvent(event: WideEvent, config: PostHogConfig): PostHogEvent;
|
|
26
|
+
/**
|
|
27
|
+
* Create a drain function for sending logs to PostHog.
|
|
28
|
+
*
|
|
29
|
+
* Configuration priority (highest to lowest):
|
|
30
|
+
* 1. Overrides passed to createPostHogDrain()
|
|
31
|
+
* 2. runtimeConfig.evlog.posthog
|
|
32
|
+
* 3. runtimeConfig.posthog
|
|
33
|
+
* 4. Environment variables: NUXT_POSTHOG_*, POSTHOG_*
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Zero config - just set NUXT_POSTHOG_API_KEY env var
|
|
38
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain())
|
|
39
|
+
*
|
|
40
|
+
* // With overrides
|
|
41
|
+
* nitroApp.hooks.hook('evlog:drain', createPostHogDrain({
|
|
42
|
+
* apiKey: 'phc_...',
|
|
43
|
+
* host: 'https://eu.i.posthog.com',
|
|
44
|
+
* }))
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function createPostHogDrain(overrides?: Partial<PostHogConfig>): (ctx: DrainContext) => Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Send a single event to PostHog.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* await sendToPostHog(event, {
|
|
54
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function sendToPostHog(event: WideEvent, config: PostHogConfig): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Send a batch of events to PostHog.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* await sendBatchToPostHog(events, {
|
|
65
|
+
* apiKey: process.env.POSTHOG_API_KEY!,
|
|
66
|
+
* })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function sendBatchToPostHog(events: WideEvent[], config: PostHogConfig): Promise<void>;
|
|
70
|
+
|
|
71
|
+
export { createPostHogDrain, sendBatchToPostHog, sendToPostHog, toPostHogEvent };
|
|
72
|
+
export type { PostHogConfig, PostHogEvent };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
function getRuntimeConfig() {
|
|
2
|
+
try {
|
|
3
|
+
const { useRuntimeConfig } = require("nitropack/runtime");
|
|
4
|
+
return useRuntimeConfig();
|
|
5
|
+
} catch {
|
|
6
|
+
return void 0;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function toPostHogEvent(event, config) {
|
|
10
|
+
const { timestamp, level, service, ...rest } = event;
|
|
11
|
+
return {
|
|
12
|
+
event: config.eventName ?? "evlog_wide_event",
|
|
13
|
+
distinct_id: config.distinctId ?? service,
|
|
14
|
+
timestamp,
|
|
15
|
+
properties: {
|
|
16
|
+
level,
|
|
17
|
+
service,
|
|
18
|
+
...rest
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function createPostHogDrain(overrides) {
|
|
23
|
+
return async (ctx) => {
|
|
24
|
+
const runtimeConfig = getRuntimeConfig();
|
|
25
|
+
const evlogPostHog = runtimeConfig?.evlog?.posthog;
|
|
26
|
+
const rootPostHog = runtimeConfig?.posthog;
|
|
27
|
+
const config = {
|
|
28
|
+
apiKey: overrides?.apiKey ?? evlogPostHog?.apiKey ?? rootPostHog?.apiKey ?? process.env.NUXT_POSTHOG_API_KEY ?? process.env.POSTHOG_API_KEY,
|
|
29
|
+
host: overrides?.host ?? evlogPostHog?.host ?? rootPostHog?.host ?? process.env.NUXT_POSTHOG_HOST ?? process.env.POSTHOG_HOST,
|
|
30
|
+
eventName: overrides?.eventName ?? evlogPostHog?.eventName ?? rootPostHog?.eventName,
|
|
31
|
+
distinctId: overrides?.distinctId ?? evlogPostHog?.distinctId ?? rootPostHog?.distinctId,
|
|
32
|
+
timeout: overrides?.timeout ?? evlogPostHog?.timeout ?? rootPostHog?.timeout
|
|
33
|
+
};
|
|
34
|
+
if (!config.apiKey) {
|
|
35
|
+
console.error("[evlog/posthog] Missing apiKey. Set NUXT_POSTHOG_API_KEY/POSTHOG_API_KEY env var or pass to createPostHogDrain()");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
await sendToPostHog(ctx.event, config);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error("[evlog/posthog] Failed to send event:", error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function sendToPostHog(event, config) {
|
|
46
|
+
await sendBatchToPostHog([event], config);
|
|
47
|
+
}
|
|
48
|
+
async function sendBatchToPostHog(events, config) {
|
|
49
|
+
if (events.length === 0) return;
|
|
50
|
+
const host = (config.host ?? "https://us.i.posthog.com").replace(/\/$/, "");
|
|
51
|
+
const timeout = config.timeout ?? 5e3;
|
|
52
|
+
const url = `${host}/batch/`;
|
|
53
|
+
const batch = events.map((event) => toPostHogEvent(event, config));
|
|
54
|
+
const payload = {
|
|
55
|
+
api_key: config.apiKey,
|
|
56
|
+
batch
|
|
57
|
+
};
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetch(url, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: {
|
|
64
|
+
"Content-Type": "application/json"
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify(payload),
|
|
67
|
+
signal: controller.signal
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
const text = await response.text().catch(() => "Unknown error");
|
|
71
|
+
const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text;
|
|
72
|
+
throw new Error(`PostHog API error: ${response.status} ${response.statusText} - ${safeText}`);
|
|
73
|
+
}
|
|
74
|
+
} finally {
|
|
75
|
+
clearTimeout(timeoutId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { createPostHogDrain, sendBatchToPostHog, sendToPostHog, toPostHogEvent };
|
package/dist/nitro/plugin.mjs
CHANGED
|
@@ -15,6 +15,15 @@ function shouldLog(path, include, exclude) {
|
|
|
15
15
|
}
|
|
16
16
|
return include.some((pattern) => matchesPattern(path, pattern));
|
|
17
17
|
}
|
|
18
|
+
function getServiceForPath(path, routes) {
|
|
19
|
+
if (!routes) return void 0;
|
|
20
|
+
for (const [pattern, config] of Object.entries(routes)) {
|
|
21
|
+
if (matchesPattern(path, pattern)) {
|
|
22
|
+
return config.service;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return void 0;
|
|
26
|
+
}
|
|
18
27
|
const SENSITIVE_HEADERS = [
|
|
19
28
|
"authorization",
|
|
20
29
|
"cookie",
|
|
@@ -46,14 +55,17 @@ function getResponseStatus(event) {
|
|
|
46
55
|
return 200;
|
|
47
56
|
}
|
|
48
57
|
function callDrainHook(nitroApp, emittedEvent, event) {
|
|
49
|
-
if (emittedEvent)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
if (!emittedEvent) return;
|
|
59
|
+
const drainPromise = nitroApp.hooks.callHook("evlog:drain", {
|
|
60
|
+
event: emittedEvent,
|
|
61
|
+
request: { method: event.method, path: event.path, requestId: event.context.requestId },
|
|
62
|
+
headers: getSafeHeaders(event)
|
|
63
|
+
}).catch((err) => {
|
|
64
|
+
console.error("[evlog] drain failed:", err);
|
|
65
|
+
});
|
|
66
|
+
const waitUntilCtx = event.context.cloudflare?.context ?? event.context;
|
|
67
|
+
if (typeof waitUntilCtx?.waitUntil === "function") {
|
|
68
|
+
waitUntilCtx.waitUntil(drainPromise);
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
const plugin = defineNitroPlugin((nitroApp) => {
|
|
@@ -70,11 +82,20 @@ const plugin = defineNitroPlugin((nitroApp) => {
|
|
|
70
82
|
return;
|
|
71
83
|
}
|
|
72
84
|
e.context._evlogStartTime = Date.now();
|
|
85
|
+
let requestIdOverride = void 0;
|
|
86
|
+
if (globalThis.navigator?.userAgent === "Cloudflare-Workers") {
|
|
87
|
+
const cfRay = getSafeHeaders(event)?.["cf-ray"];
|
|
88
|
+
if (cfRay) requestIdOverride = cfRay;
|
|
89
|
+
}
|
|
73
90
|
const log = createRequestLogger({
|
|
74
91
|
method: e.method,
|
|
75
92
|
path: e.path,
|
|
76
|
-
requestId: e.context.requestId || crypto.randomUUID()
|
|
93
|
+
requestId: requestIdOverride || e.context.requestId || crypto.randomUUID()
|
|
77
94
|
});
|
|
95
|
+
const routeService = getServiceForPath(e.path, evlogConfig?.routes);
|
|
96
|
+
if (routeService) {
|
|
97
|
+
log.set({ service: routeService });
|
|
98
|
+
}
|
|
78
99
|
e.context.log = log;
|
|
79
100
|
});
|
|
80
101
|
nitroApp.hooks.hook("error", async (error, { event }) => {
|
package/dist/nuxt/module.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { EnvironmentContext, SamplingConfig, TransportConfig } from '../types.mjs';
|
|
2
|
+
import { EnvironmentContext, RouteConfig, SamplingConfig, TransportConfig } from '../types.mjs';
|
|
3
3
|
|
|
4
4
|
interface ModuleOptions {
|
|
5
5
|
/**
|
|
@@ -25,6 +25,20 @@ interface ModuleOptions {
|
|
|
25
25
|
* @example ['/api/_nuxt_icon/**', '/health']
|
|
26
26
|
*/
|
|
27
27
|
exclude?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Route-specific service configuration.
|
|
30
|
+
* Allows setting different service names for different routes.
|
|
31
|
+
* Patterns are matched using glob syntax.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* routes: {
|
|
36
|
+
* '/api/foo/**': { service: 'service1' },
|
|
37
|
+
* '/api/bar/**': { service: 'service2' }
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
routes?: Record<string, RouteConfig>;
|
|
28
42
|
/**
|
|
29
43
|
* Sampling configuration for filtering logs.
|
|
30
44
|
* Allows configuring what percentage of logs to keep per level.
|
package/dist/nuxt/module.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { EnvironmentContext, SamplingConfig, TransportConfig } from '../types.js';
|
|
2
|
+
import { EnvironmentContext, RouteConfig, SamplingConfig, TransportConfig } from '../types.js';
|
|
3
3
|
|
|
4
4
|
interface ModuleOptions {
|
|
5
5
|
/**
|
|
@@ -25,6 +25,20 @@ interface ModuleOptions {
|
|
|
25
25
|
* @example ['/api/_nuxt_icon/**', '/health']
|
|
26
26
|
*/
|
|
27
27
|
exclude?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Route-specific service configuration.
|
|
30
|
+
* Allows setting different service names for different routes.
|
|
31
|
+
* Patterns are matched using glob syntax.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* routes: {
|
|
36
|
+
* '/api/foo/**': { service: 'service1' },
|
|
37
|
+
* '/api/bar/**': { service: 'service2' }
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
routes?: Record<string, RouteConfig>;
|
|
28
42
|
/**
|
|
29
43
|
* Sampling configuration for filtering logs.
|
|
30
44
|
* Allows configuring what percentage of logs to keep per level.
|
|
@@ -4,6 +4,7 @@ import { ServerEvent, RequestLogger } from '../../types.mjs';
|
|
|
4
4
|
* Returns the request logger attached to the given server event.
|
|
5
5
|
*
|
|
6
6
|
* @param event - The current server event containing the context with the logger.
|
|
7
|
+
* @param service - Optional service name to override the default service.
|
|
7
8
|
* @returns The request-scoped logger.
|
|
8
9
|
* @throws Error if the logger is not initialized on the event context.
|
|
9
10
|
*
|
|
@@ -13,7 +14,15 @@ import { ServerEvent, RequestLogger } from '../../types.mjs';
|
|
|
13
14
|
* log.set({ foo: 'bar' })
|
|
14
15
|
* // ...
|
|
15
16
|
* })
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Override service name for specific routes
|
|
20
|
+
* export default defineEventHandler((event) => {
|
|
21
|
+
* const log = useLogger(event, 'payment-service')
|
|
22
|
+
* log.set({ foo: 'bar' })
|
|
23
|
+
* // ...
|
|
24
|
+
* })
|
|
16
25
|
*/
|
|
17
|
-
declare function useLogger(event: ServerEvent): RequestLogger;
|
|
26
|
+
declare function useLogger(event: ServerEvent, service?: string): RequestLogger;
|
|
18
27
|
|
|
19
28
|
export { useLogger };
|
|
@@ -4,6 +4,7 @@ import { ServerEvent, RequestLogger } from '../../types.js';
|
|
|
4
4
|
* Returns the request logger attached to the given server event.
|
|
5
5
|
*
|
|
6
6
|
* @param event - The current server event containing the context with the logger.
|
|
7
|
+
* @param service - Optional service name to override the default service.
|
|
7
8
|
* @returns The request-scoped logger.
|
|
8
9
|
* @throws Error if the logger is not initialized on the event context.
|
|
9
10
|
*
|
|
@@ -13,7 +14,15 @@ import { ServerEvent, RequestLogger } from '../../types.js';
|
|
|
13
14
|
* log.set({ foo: 'bar' })
|
|
14
15
|
* // ...
|
|
15
16
|
* })
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Override service name for specific routes
|
|
20
|
+
* export default defineEventHandler((event) => {
|
|
21
|
+
* const log = useLogger(event, 'payment-service')
|
|
22
|
+
* log.set({ foo: 'bar' })
|
|
23
|
+
* // ...
|
|
24
|
+
* })
|
|
16
25
|
*/
|
|
17
|
-
declare function useLogger(event: ServerEvent): RequestLogger;
|
|
26
|
+
declare function useLogger(event: ServerEvent, service?: string): RequestLogger;
|
|
18
27
|
|
|
19
28
|
export { useLogger };
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
function useLogger(event) {
|
|
1
|
+
function useLogger(event, service) {
|
|
2
2
|
const log = event.context.log;
|
|
3
3
|
if (!log) {
|
|
4
4
|
throw new Error(
|
|
5
5
|
'[evlog] Logger not initialized. Make sure the evlog Nitro plugin is registered. If using Nuxt, add "evlog" to your modules.'
|
|
6
6
|
);
|
|
7
7
|
}
|
|
8
|
+
if (service) {
|
|
9
|
+
log.set({ service });
|
|
10
|
+
}
|
|
8
11
|
return log;
|
|
9
12
|
}
|
|
10
13
|
|
package/dist/types.d.mts
CHANGED
|
@@ -160,6 +160,13 @@ interface SamplingConfig {
|
|
|
160
160
|
*/
|
|
161
161
|
keep?: TailSamplingCondition[];
|
|
162
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Route-based service configuration
|
|
165
|
+
*/
|
|
166
|
+
interface RouteConfig {
|
|
167
|
+
/** Service name to use for routes matching this pattern */
|
|
168
|
+
service: string;
|
|
169
|
+
}
|
|
163
170
|
/**
|
|
164
171
|
* Environment context automatically included in every log event
|
|
165
172
|
*/
|
|
@@ -325,7 +332,16 @@ interface H3EventContext {
|
|
|
325
332
|
interface ServerEvent {
|
|
326
333
|
method: string;
|
|
327
334
|
path: string;
|
|
328
|
-
context: H3EventContext
|
|
335
|
+
context: H3EventContext & {
|
|
336
|
+
/** Cloudflare Workers context (available when deployed to CF Workers) */
|
|
337
|
+
cloudflare?: {
|
|
338
|
+
context: {
|
|
339
|
+
waitUntil: (promise: Promise<unknown>) => void;
|
|
340
|
+
};
|
|
341
|
+
};
|
|
342
|
+
/** Vercel Edge context (available when deployed to Vercel Edge) */
|
|
343
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
344
|
+
};
|
|
329
345
|
node?: {
|
|
330
346
|
res?: {
|
|
331
347
|
statusCode?: number;
|
|
@@ -345,4 +361,4 @@ interface ParsedError {
|
|
|
345
361
|
raw: unknown;
|
|
346
362
|
}
|
|
347
363
|
|
|
348
|
-
export type { BaseWideEvent, DrainContext, EnvironmentContext, ErrorOptions, H3EventContext, IngestPayload, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent };
|
|
364
|
+
export type { BaseWideEvent, DrainContext, EnvironmentContext, ErrorOptions, H3EventContext, IngestPayload, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, RouteConfig, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent };
|
package/dist/types.d.ts
CHANGED
|
@@ -160,6 +160,13 @@ interface SamplingConfig {
|
|
|
160
160
|
*/
|
|
161
161
|
keep?: TailSamplingCondition[];
|
|
162
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Route-based service configuration
|
|
165
|
+
*/
|
|
166
|
+
interface RouteConfig {
|
|
167
|
+
/** Service name to use for routes matching this pattern */
|
|
168
|
+
service: string;
|
|
169
|
+
}
|
|
163
170
|
/**
|
|
164
171
|
* Environment context automatically included in every log event
|
|
165
172
|
*/
|
|
@@ -325,7 +332,16 @@ interface H3EventContext {
|
|
|
325
332
|
interface ServerEvent {
|
|
326
333
|
method: string;
|
|
327
334
|
path: string;
|
|
328
|
-
context: H3EventContext
|
|
335
|
+
context: H3EventContext & {
|
|
336
|
+
/** Cloudflare Workers context (available when deployed to CF Workers) */
|
|
337
|
+
cloudflare?: {
|
|
338
|
+
context: {
|
|
339
|
+
waitUntil: (promise: Promise<unknown>) => void;
|
|
340
|
+
};
|
|
341
|
+
};
|
|
342
|
+
/** Vercel Edge context (available when deployed to Vercel Edge) */
|
|
343
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
344
|
+
};
|
|
329
345
|
node?: {
|
|
330
346
|
res?: {
|
|
331
347
|
statusCode?: number;
|
|
@@ -345,4 +361,4 @@ interface ParsedError {
|
|
|
345
361
|
raw: unknown;
|
|
346
362
|
}
|
|
347
363
|
|
|
348
|
-
export type { BaseWideEvent, DrainContext, EnvironmentContext, ErrorOptions, H3EventContext, IngestPayload, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent };
|
|
364
|
+
export type { BaseWideEvent, DrainContext, EnvironmentContext, ErrorOptions, H3EventContext, IngestPayload, Log, LogLevel, LoggerConfig, ParsedError, RequestLogger, RequestLoggerOptions, RouteConfig, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evlog",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.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",
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
"./otlp": {
|
|
47
47
|
"types": "./dist/adapters/otlp.d.mts",
|
|
48
48
|
"import": "./dist/adapters/otlp.mjs"
|
|
49
|
+
},
|
|
50
|
+
"./posthog": {
|
|
51
|
+
"types": "./dist/adapters/posthog.d.mts",
|
|
52
|
+
"import": "./dist/adapters/posthog.mjs"
|
|
49
53
|
}
|
|
50
54
|
},
|
|
51
55
|
"main": "./dist/index.mjs",
|
|
@@ -69,6 +73,9 @@
|
|
|
69
73
|
],
|
|
70
74
|
"otlp": [
|
|
71
75
|
"./dist/adapters/otlp.d.mts"
|
|
76
|
+
],
|
|
77
|
+
"posthog": [
|
|
78
|
+
"./dist/adapters/posthog.d.mts"
|
|
72
79
|
]
|
|
73
80
|
}
|
|
74
81
|
},
|
|
@@ -88,17 +95,17 @@
|
|
|
88
95
|
"typecheck": "echo 'Typecheck handled by build'"
|
|
89
96
|
},
|
|
90
97
|
"dependencies": {
|
|
91
|
-
"@nuxt/kit": "^4.3.
|
|
98
|
+
"@nuxt/kit": "^4.3.1",
|
|
92
99
|
"defu": "^6.1.4"
|
|
93
100
|
},
|
|
94
101
|
"devDependencies": {
|
|
95
102
|
"@nuxt/devtools": "^3.1.1",
|
|
96
|
-
"@nuxt/schema": "^4.3.
|
|
103
|
+
"@nuxt/schema": "^4.3.1",
|
|
97
104
|
"@nuxt/test-utils": "^3.23.0",
|
|
98
105
|
"changelogen": "^0.6.2",
|
|
99
106
|
"h3": "^1.15.5",
|
|
100
107
|
"nitropack": "^2.13.1",
|
|
101
|
-
"nuxt": "^4.3.
|
|
108
|
+
"nuxt": "^4.3.1",
|
|
102
109
|
"typescript": "^5.9.3",
|
|
103
110
|
"unbuild": "^3.6.1"
|
|
104
111
|
},
|