evlog 1.5.0 → 1.6.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 +17 -0
- package/dist/adapters/axiom.mjs +2 -8
- package/dist/adapters/otlp.mjs +2 -8
- package/dist/adapters/posthog.mjs +2 -8
- package/dist/adapters/sentry.d.mts +78 -0
- package/dist/adapters/sentry.d.ts +78 -0
- package/dist/adapters/sentry.mjs +176 -0
- package/dist/index.mjs +0 -1
- package/dist/logger.mjs +18 -3
- package/dist/nitro/plugin.mjs +0 -1
- package/dist/nuxt/module.d.mts +46 -0
- package/dist/nuxt/module.d.ts +46 -0
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +0 -1
- package/dist/shared/evlog.Bc35pxiY.mjs +10 -0
- package/dist/workers.mjs +0 -1
- package/package.json +12 -5
package/README.md
CHANGED
|
@@ -431,6 +431,23 @@ Set environment variables:
|
|
|
431
431
|
NUXT_OTLP_ENDPOINT=http://localhost:4318
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
+
### Sentry
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
// server/plugins/evlog-drain.ts
|
|
438
|
+
import { createSentryDrain } from 'evlog/sentry'
|
|
439
|
+
|
|
440
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
441
|
+
nitroApp.hooks.hook('evlog:drain', createSentryDrain())
|
|
442
|
+
})
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Set environment variables:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
|
|
449
|
+
```
|
|
450
|
+
|
|
434
451
|
### Multiple Destinations
|
|
435
452
|
|
|
436
453
|
Send logs to multiple services:
|
package/dist/adapters/axiom.mjs
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { useRuntimeConfig } = require("nitropack/runtime");
|
|
4
|
-
return useRuntimeConfig();
|
|
5
|
-
} catch {
|
|
6
|
-
return void 0;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
9
3
|
function createAxiomDrain(overrides) {
|
|
10
4
|
return async (ctx) => {
|
|
11
5
|
const runtimeConfig = getRuntimeConfig();
|
package/dist/adapters/otlp.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
1
3
|
const SEVERITY_MAP = {
|
|
2
4
|
debug: 5,
|
|
3
5
|
// DEBUG
|
|
@@ -14,14 +16,6 @@ const SEVERITY_TEXT_MAP = {
|
|
|
14
16
|
warn: "WARN",
|
|
15
17
|
error: "ERROR"
|
|
16
18
|
};
|
|
17
|
-
function getRuntimeConfig() {
|
|
18
|
-
try {
|
|
19
|
-
const { useRuntimeConfig } = require("nitropack/runtime");
|
|
20
|
-
return useRuntimeConfig();
|
|
21
|
-
} catch {
|
|
22
|
-
return void 0;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
19
|
function toAttributeValue(value) {
|
|
26
20
|
if (typeof value === "boolean") {
|
|
27
21
|
return { boolValue: value };
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { useRuntimeConfig } = require("nitropack/runtime");
|
|
4
|
-
return useRuntimeConfig();
|
|
5
|
-
} catch {
|
|
6
|
-
return void 0;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
9
3
|
function toPostHogEvent(event, config) {
|
|
10
4
|
const { timestamp, level, service, ...rest } = event;
|
|
11
5
|
return {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.mjs';
|
|
2
|
+
|
|
3
|
+
interface SentryConfig {
|
|
4
|
+
/** Sentry DSN */
|
|
5
|
+
dsn: string;
|
|
6
|
+
/** Environment override (defaults to event.environment) */
|
|
7
|
+
environment?: string;
|
|
8
|
+
/** Release version override (defaults to event.version) */
|
|
9
|
+
release?: string;
|
|
10
|
+
/** Additional tags to attach as attributes */
|
|
11
|
+
tags?: Record<string, string>;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** Sentry Log attribute value with type annotation */
|
|
16
|
+
interface SentryAttributeValue {
|
|
17
|
+
value: string | number | boolean;
|
|
18
|
+
type: 'string' | 'integer' | 'double' | 'boolean';
|
|
19
|
+
}
|
|
20
|
+
/** Sentry Structured Log payload */
|
|
21
|
+
interface SentryLog {
|
|
22
|
+
timestamp: number;
|
|
23
|
+
trace_id: string;
|
|
24
|
+
level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
25
|
+
body: string;
|
|
26
|
+
severity_number: number;
|
|
27
|
+
attributes?: Record<string, SentryAttributeValue>;
|
|
28
|
+
}
|
|
29
|
+
declare function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog;
|
|
30
|
+
/**
|
|
31
|
+
* Create a drain function for sending logs to Sentry.
|
|
32
|
+
*
|
|
33
|
+
* Sends wide events as Sentry Structured Logs, visible in Explore > Logs
|
|
34
|
+
* in the Sentry dashboard.
|
|
35
|
+
*
|
|
36
|
+
* Configuration priority (highest to lowest):
|
|
37
|
+
* 1. Overrides passed to createSentryDrain()
|
|
38
|
+
* 2. runtimeConfig.evlog.sentry
|
|
39
|
+
* 3. runtimeConfig.sentry
|
|
40
|
+
* 4. Environment variables: NUXT_SENTRY_*, SENTRY_*
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // Zero config - just set NUXT_SENTRY_DSN env var
|
|
45
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain())
|
|
46
|
+
*
|
|
47
|
+
* // With overrides
|
|
48
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain({
|
|
49
|
+
* dsn: 'https://public@o0.ingest.sentry.io/123',
|
|
50
|
+
* }))
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare function createSentryDrain(overrides?: Partial<SentryConfig>): (ctx: DrainContext) => Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Send a single event to Sentry as a structured log.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* await sendToSentry(event, {
|
|
60
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function sendToSentry(event: WideEvent, config: SentryConfig): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Send a batch of events to Sentry as structured logs via the Envelope endpoint.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* await sendBatchToSentry(events, {
|
|
71
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
72
|
+
* })
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function sendBatchToSentry(events: WideEvent[], config: SentryConfig): Promise<void>;
|
|
76
|
+
|
|
77
|
+
export { createSentryDrain, sendBatchToSentry, sendToSentry, toSentryLog };
|
|
78
|
+
export type { SentryAttributeValue, SentryConfig, SentryLog };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DrainContext, WideEvent } from '../types.js';
|
|
2
|
+
|
|
3
|
+
interface SentryConfig {
|
|
4
|
+
/** Sentry DSN */
|
|
5
|
+
dsn: string;
|
|
6
|
+
/** Environment override (defaults to event.environment) */
|
|
7
|
+
environment?: string;
|
|
8
|
+
/** Release version override (defaults to event.version) */
|
|
9
|
+
release?: string;
|
|
10
|
+
/** Additional tags to attach as attributes */
|
|
11
|
+
tags?: Record<string, string>;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
/** Sentry Log attribute value with type annotation */
|
|
16
|
+
interface SentryAttributeValue {
|
|
17
|
+
value: string | number | boolean;
|
|
18
|
+
type: 'string' | 'integer' | 'double' | 'boolean';
|
|
19
|
+
}
|
|
20
|
+
/** Sentry Structured Log payload */
|
|
21
|
+
interface SentryLog {
|
|
22
|
+
timestamp: number;
|
|
23
|
+
trace_id: string;
|
|
24
|
+
level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
25
|
+
body: string;
|
|
26
|
+
severity_number: number;
|
|
27
|
+
attributes?: Record<string, SentryAttributeValue>;
|
|
28
|
+
}
|
|
29
|
+
declare function toSentryLog(event: WideEvent, config: SentryConfig): SentryLog;
|
|
30
|
+
/**
|
|
31
|
+
* Create a drain function for sending logs to Sentry.
|
|
32
|
+
*
|
|
33
|
+
* Sends wide events as Sentry Structured Logs, visible in Explore > Logs
|
|
34
|
+
* in the Sentry dashboard.
|
|
35
|
+
*
|
|
36
|
+
* Configuration priority (highest to lowest):
|
|
37
|
+
* 1. Overrides passed to createSentryDrain()
|
|
38
|
+
* 2. runtimeConfig.evlog.sentry
|
|
39
|
+
* 3. runtimeConfig.sentry
|
|
40
|
+
* 4. Environment variables: NUXT_SENTRY_*, SENTRY_*
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // Zero config - just set NUXT_SENTRY_DSN env var
|
|
45
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain())
|
|
46
|
+
*
|
|
47
|
+
* // With overrides
|
|
48
|
+
* nitroApp.hooks.hook('evlog:drain', createSentryDrain({
|
|
49
|
+
* dsn: 'https://public@o0.ingest.sentry.io/123',
|
|
50
|
+
* }))
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare function createSentryDrain(overrides?: Partial<SentryConfig>): (ctx: DrainContext) => Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Send a single event to Sentry as a structured log.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* await sendToSentry(event, {
|
|
60
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function sendToSentry(event: WideEvent, config: SentryConfig): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Send a batch of events to Sentry as structured logs via the Envelope endpoint.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* await sendBatchToSentry(events, {
|
|
71
|
+
* dsn: process.env.SENTRY_DSN!,
|
|
72
|
+
* })
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function sendBatchToSentry(events: WideEvent[], config: SentryConfig): Promise<void>;
|
|
76
|
+
|
|
77
|
+
export { createSentryDrain, sendBatchToSentry, sendToSentry, toSentryLog };
|
|
78
|
+
export type { SentryAttributeValue, SentryConfig, SentryLog };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { g as getRuntimeConfig } from '../shared/evlog.Bc35pxiY.mjs';
|
|
2
|
+
|
|
3
|
+
const SEVERITY_MAP = {
|
|
4
|
+
debug: 5,
|
|
5
|
+
info: 9,
|
|
6
|
+
warn: 13,
|
|
7
|
+
error: 17
|
|
8
|
+
};
|
|
9
|
+
function parseSentryDsn(dsn) {
|
|
10
|
+
const url = new URL(dsn);
|
|
11
|
+
const publicKey = url.username;
|
|
12
|
+
if (!publicKey) {
|
|
13
|
+
throw new Error("Invalid Sentry DSN: missing public key");
|
|
14
|
+
}
|
|
15
|
+
const secretKey = url.password || void 0;
|
|
16
|
+
const pathParts = url.pathname.split("/").filter(Boolean);
|
|
17
|
+
const projectId = pathParts.pop();
|
|
18
|
+
if (!projectId) {
|
|
19
|
+
throw new Error("Invalid Sentry DSN: missing project ID");
|
|
20
|
+
}
|
|
21
|
+
const basePath = pathParts.length > 0 ? `/${pathParts.join("/")}` : "";
|
|
22
|
+
return {
|
|
23
|
+
publicKey,
|
|
24
|
+
secretKey,
|
|
25
|
+
projectId,
|
|
26
|
+
origin: `${url.protocol}//${url.host}`,
|
|
27
|
+
basePath
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function getSentryEnvelopeUrl(dsn) {
|
|
31
|
+
const { publicKey, secretKey, projectId, origin, basePath } = parseSentryDsn(dsn);
|
|
32
|
+
const url = `${origin}${basePath}/api/${projectId}/envelope/`;
|
|
33
|
+
let authHeader = `Sentry sentry_version=7, sentry_key=${publicKey}, sentry_client=evlog`;
|
|
34
|
+
if (secretKey) {
|
|
35
|
+
authHeader += `, sentry_secret=${secretKey}`;
|
|
36
|
+
}
|
|
37
|
+
return { url, authHeader };
|
|
38
|
+
}
|
|
39
|
+
function createTraceId() {
|
|
40
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
41
|
+
return globalThis.crypto.randomUUID().replace(/-/g, "");
|
|
42
|
+
}
|
|
43
|
+
return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
|
|
44
|
+
}
|
|
45
|
+
function getFirstStringValue(event, keys) {
|
|
46
|
+
for (const key of keys) {
|
|
47
|
+
const value = event[key];
|
|
48
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
49
|
+
}
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
function toAttributeValue(value) {
|
|
53
|
+
if (value === null || value === void 0) {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === "string") {
|
|
57
|
+
return { value, type: "string" };
|
|
58
|
+
}
|
|
59
|
+
if (typeof value === "boolean") {
|
|
60
|
+
return { value, type: "boolean" };
|
|
61
|
+
}
|
|
62
|
+
if (typeof value === "number") {
|
|
63
|
+
if (Number.isInteger(value)) {
|
|
64
|
+
return { value, type: "integer" };
|
|
65
|
+
}
|
|
66
|
+
return { value, type: "double" };
|
|
67
|
+
}
|
|
68
|
+
return { value: JSON.stringify(value), type: "string" };
|
|
69
|
+
}
|
|
70
|
+
function toSentryLog(event, config) {
|
|
71
|
+
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
72
|
+
const body = getFirstStringValue(event, ["message", "action", "path"]) ?? "evlog wide event";
|
|
73
|
+
const traceId = typeof event.traceId === "string" && event.traceId.length > 0 ? event.traceId : createTraceId();
|
|
74
|
+
const attributes = {};
|
|
75
|
+
const env = config.environment ?? environment;
|
|
76
|
+
if (env) {
|
|
77
|
+
attributes["sentry.environment"] = { value: env, type: "string" };
|
|
78
|
+
}
|
|
79
|
+
const rel = config.release ?? version;
|
|
80
|
+
if (typeof rel === "string" && rel.length > 0) {
|
|
81
|
+
attributes["sentry.release"] = { value: rel, type: "string" };
|
|
82
|
+
}
|
|
83
|
+
attributes["service"] = { value: service, type: "string" };
|
|
84
|
+
if (config.tags) {
|
|
85
|
+
for (const [key, value] of Object.entries(config.tags)) {
|
|
86
|
+
attributes[key] = { value, type: "string" };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
90
|
+
if (key === "traceId" || key === "spanId") continue;
|
|
91
|
+
if (value === void 0 || value === null) continue;
|
|
92
|
+
const attr = toAttributeValue(value);
|
|
93
|
+
if (attr) {
|
|
94
|
+
attributes[key] = attr;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
timestamp: new Date(timestamp).getTime() / 1e3,
|
|
99
|
+
trace_id: traceId,
|
|
100
|
+
level,
|
|
101
|
+
body,
|
|
102
|
+
severity_number: SEVERITY_MAP[level] ?? 9,
|
|
103
|
+
attributes
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildEnvelopeBody(logs, dsn) {
|
|
107
|
+
const envelopeHeader = JSON.stringify({
|
|
108
|
+
dsn,
|
|
109
|
+
sent_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
110
|
+
});
|
|
111
|
+
const itemHeader = JSON.stringify({
|
|
112
|
+
type: "log",
|
|
113
|
+
item_count: logs.length,
|
|
114
|
+
content_type: "application/vnd.sentry.items.log+json"
|
|
115
|
+
});
|
|
116
|
+
const itemPayload = JSON.stringify({ items: logs });
|
|
117
|
+
return `${envelopeHeader}
|
|
118
|
+
${itemHeader}
|
|
119
|
+
${itemPayload}
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
function createSentryDrain(overrides) {
|
|
123
|
+
return async (ctx) => {
|
|
124
|
+
const runtimeConfig = getRuntimeConfig();
|
|
125
|
+
const evlogSentry = runtimeConfig?.evlog?.sentry;
|
|
126
|
+
const rootSentry = runtimeConfig?.sentry;
|
|
127
|
+
const config = {
|
|
128
|
+
dsn: overrides?.dsn ?? evlogSentry?.dsn ?? rootSentry?.dsn ?? process.env.NUXT_SENTRY_DSN ?? process.env.SENTRY_DSN,
|
|
129
|
+
environment: overrides?.environment ?? evlogSentry?.environment ?? rootSentry?.environment ?? process.env.NUXT_SENTRY_ENVIRONMENT ?? process.env.SENTRY_ENVIRONMENT,
|
|
130
|
+
release: overrides?.release ?? evlogSentry?.release ?? rootSentry?.release ?? process.env.NUXT_SENTRY_RELEASE ?? process.env.SENTRY_RELEASE,
|
|
131
|
+
tags: overrides?.tags ?? evlogSentry?.tags ?? rootSentry?.tags,
|
|
132
|
+
timeout: overrides?.timeout ?? evlogSentry?.timeout ?? rootSentry?.timeout
|
|
133
|
+
};
|
|
134
|
+
if (!config.dsn) {
|
|
135
|
+
console.error("[evlog/sentry] Missing DSN. Set NUXT_SENTRY_DSN/SENTRY_DSN env var or pass to createSentryDrain()");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
await sendToSentry(ctx.event, config);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("[evlog/sentry] Failed to send log:", error);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function sendToSentry(event, config) {
|
|
146
|
+
await sendBatchToSentry([event], config);
|
|
147
|
+
}
|
|
148
|
+
async function sendBatchToSentry(events, config) {
|
|
149
|
+
if (events.length === 0) return;
|
|
150
|
+
const { url, authHeader } = getSentryEnvelopeUrl(config.dsn);
|
|
151
|
+
const timeout = config.timeout ?? 5e3;
|
|
152
|
+
const logs = events.map((event) => toSentryLog(event, config));
|
|
153
|
+
const body = buildEnvelopeBody(logs, config.dsn);
|
|
154
|
+
const controller = new AbortController();
|
|
155
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
156
|
+
try {
|
|
157
|
+
const response = await fetch(url, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: {
|
|
160
|
+
"Content-Type": "application/x-sentry-envelope",
|
|
161
|
+
"X-Sentry-Auth": authHeader
|
|
162
|
+
},
|
|
163
|
+
body,
|
|
164
|
+
signal: controller.signal
|
|
165
|
+
});
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
const text = await response.text().catch(() => "Unknown error");
|
|
168
|
+
const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text;
|
|
169
|
+
throw new Error(`Sentry API error: ${response.status} ${response.statusText} - ${safeText}`);
|
|
170
|
+
}
|
|
171
|
+
} finally {
|
|
172
|
+
clearTimeout(timeoutId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { createSentryDrain, sendBatchToSentry, sendToSentry, toSentryLog };
|
package/dist/index.mjs
CHANGED
package/dist/logger.mjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import { defu } from 'defu';
|
|
2
1
|
import { isDev, detectEnvironment, formatDuration, matchesPattern, getConsoleMethod, colors, getLevelColor } from './utils.mjs';
|
|
3
2
|
|
|
3
|
+
function isPlainObject(val) {
|
|
4
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
5
|
+
}
|
|
6
|
+
function deepDefaults(base, defaults) {
|
|
7
|
+
const result = { ...base };
|
|
8
|
+
for (const key in defaults) {
|
|
9
|
+
const baseVal = result[key];
|
|
10
|
+
const defaultVal = defaults[key];
|
|
11
|
+
if (baseVal === void 0 || baseVal === null) {
|
|
12
|
+
result[key] = defaultVal;
|
|
13
|
+
} else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {
|
|
14
|
+
result[key] = deepDefaults(baseVal, defaultVal);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
4
19
|
let globalEnv = {
|
|
5
20
|
service: "app",
|
|
6
21
|
environment: "development"
|
|
@@ -154,7 +169,7 @@ function createRequestLogger(options = {}) {
|
|
|
154
169
|
let hasError = false;
|
|
155
170
|
return {
|
|
156
171
|
set(data) {
|
|
157
|
-
context =
|
|
172
|
+
context = deepDefaults(data, context);
|
|
158
173
|
},
|
|
159
174
|
error(error, errorContext) {
|
|
160
175
|
hasError = true;
|
|
@@ -167,7 +182,7 @@ function createRequestLogger(options = {}) {
|
|
|
167
182
|
stack: err.stack
|
|
168
183
|
}
|
|
169
184
|
};
|
|
170
|
-
context =
|
|
185
|
+
context = deepDefaults(errorData, context);
|
|
171
186
|
},
|
|
172
187
|
emit(overrides) {
|
|
173
188
|
const durationMs = Date.now() - startTime;
|
package/dist/nitro/plugin.mjs
CHANGED
|
@@ -2,7 +2,6 @@ import { defineNitroPlugin, useRuntimeConfig } from 'nitropack/runtime';
|
|
|
2
2
|
import { getHeaders } from 'h3';
|
|
3
3
|
import { initLogger, createRequestLogger } from '../logger.mjs';
|
|
4
4
|
import { matchesPattern } from '../utils.mjs';
|
|
5
|
-
import 'defu';
|
|
6
5
|
|
|
7
6
|
function shouldLog(path, include, exclude) {
|
|
8
7
|
if (exclude && exclude.length > 0) {
|
package/dist/nuxt/module.d.mts
CHANGED
|
@@ -118,6 +118,52 @@ interface ModuleOptions {
|
|
|
118
118
|
/** Request timeout in milliseconds. Default: 5000 */
|
|
119
119
|
timeout?: number;
|
|
120
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* PostHog adapter configuration.
|
|
123
|
+
* When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* posthog: {
|
|
128
|
+
* apiKey: process.env.POSTHOG_API_KEY,
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
posthog?: {
|
|
133
|
+
/** PostHog project API key */
|
|
134
|
+
apiKey: string;
|
|
135
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
136
|
+
host?: string;
|
|
137
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
138
|
+
eventName?: string;
|
|
139
|
+
/** Override distinct_id (defaults to event.service) */
|
|
140
|
+
distinctId?: string;
|
|
141
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
142
|
+
timeout?: number;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Sentry adapter configuration.
|
|
146
|
+
* When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* sentry: {
|
|
151
|
+
* dsn: process.env.SENTRY_DSN,
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
sentry?: {
|
|
156
|
+
/** Sentry DSN */
|
|
157
|
+
dsn: string;
|
|
158
|
+
/** Environment override (defaults to event.environment) */
|
|
159
|
+
environment?: string;
|
|
160
|
+
/** Release version override (defaults to event.version) */
|
|
161
|
+
release?: string;
|
|
162
|
+
/** Additional tags to attach as attributes */
|
|
163
|
+
tags?: Record<string, string>;
|
|
164
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
165
|
+
timeout?: number;
|
|
166
|
+
};
|
|
121
167
|
}
|
|
122
168
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
123
169
|
|
package/dist/nuxt/module.d.ts
CHANGED
|
@@ -118,6 +118,52 @@ interface ModuleOptions {
|
|
|
118
118
|
/** Request timeout in milliseconds. Default: 5000 */
|
|
119
119
|
timeout?: number;
|
|
120
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* PostHog adapter configuration.
|
|
123
|
+
* When configured, use `createPostHogDrain()` from `evlog/posthog` to send logs.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* posthog: {
|
|
128
|
+
* apiKey: process.env.POSTHOG_API_KEY,
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
posthog?: {
|
|
133
|
+
/** PostHog project API key */
|
|
134
|
+
apiKey: string;
|
|
135
|
+
/** PostHog host URL. Default: https://us.i.posthog.com */
|
|
136
|
+
host?: string;
|
|
137
|
+
/** PostHog event name. Default: evlog_wide_event */
|
|
138
|
+
eventName?: string;
|
|
139
|
+
/** Override distinct_id (defaults to event.service) */
|
|
140
|
+
distinctId?: string;
|
|
141
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
142
|
+
timeout?: number;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Sentry adapter configuration.
|
|
146
|
+
* When configured, use `createSentryDrain()` from `evlog/sentry` to send logs.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* sentry: {
|
|
151
|
+
* dsn: process.env.SENTRY_DSN,
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
sentry?: {
|
|
156
|
+
/** Sentry DSN */
|
|
157
|
+
dsn: string;
|
|
158
|
+
/** Environment override (defaults to event.environment) */
|
|
159
|
+
environment?: string;
|
|
160
|
+
/** Release version override (defaults to event.version) */
|
|
161
|
+
release?: string;
|
|
162
|
+
/** Additional tags to attach as attributes */
|
|
163
|
+
tags?: Record<string, string>;
|
|
164
|
+
/** Request timeout in milliseconds. Default: 5000 */
|
|
165
|
+
timeout?: number;
|
|
166
|
+
};
|
|
121
167
|
}
|
|
122
168
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
123
169
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler, readBody, setResponseStatus, getHeader, getRequestHost, createError } from 'h3';
|
|
2
2
|
import { useNitroApp } from 'nitropack/runtime';
|
|
3
3
|
import { getEnvironment } from '../../../../logger.mjs';
|
|
4
|
-
import 'defu';
|
|
5
4
|
import '../../../../utils.mjs';
|
|
6
5
|
|
|
7
6
|
const VALID_LEVELS = ["info", "error", "warn", "debug"];
|
package/dist/workers.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evlog",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.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",
|
|
@@ -50,6 +50,10 @@
|
|
|
50
50
|
"./posthog": {
|
|
51
51
|
"types": "./dist/adapters/posthog.d.mts",
|
|
52
52
|
"import": "./dist/adapters/posthog.mjs"
|
|
53
|
+
},
|
|
54
|
+
"./sentry": {
|
|
55
|
+
"types": "./dist/adapters/sentry.d.mts",
|
|
56
|
+
"import": "./dist/adapters/sentry.mjs"
|
|
53
57
|
}
|
|
54
58
|
},
|
|
55
59
|
"main": "./dist/index.mjs",
|
|
@@ -76,6 +80,9 @@
|
|
|
76
80
|
],
|
|
77
81
|
"posthog": [
|
|
78
82
|
"./dist/adapters/posthog.d.mts"
|
|
83
|
+
],
|
|
84
|
+
"sentry": [
|
|
85
|
+
"./dist/adapters/sentry.d.mts"
|
|
79
86
|
]
|
|
80
87
|
}
|
|
81
88
|
},
|
|
@@ -94,10 +101,6 @@
|
|
|
94
101
|
"test:coverage": "vitest run --coverage",
|
|
95
102
|
"typecheck": "echo 'Typecheck handled by build'"
|
|
96
103
|
},
|
|
97
|
-
"dependencies": {
|
|
98
|
-
"@nuxt/kit": "^4.3.1",
|
|
99
|
-
"defu": "^6.1.4"
|
|
100
|
-
},
|
|
101
104
|
"devDependencies": {
|
|
102
105
|
"@nuxt/devtools": "^3.1.1",
|
|
103
106
|
"@nuxt/schema": "^4.3.1",
|
|
@@ -110,11 +113,15 @@
|
|
|
110
113
|
"unbuild": "^3.6.1"
|
|
111
114
|
},
|
|
112
115
|
"peerDependencies": {
|
|
116
|
+
"@nuxt/kit": "^4.3.1",
|
|
113
117
|
"h3": "^1.15.5",
|
|
114
118
|
"nitropack": "^2.13.1",
|
|
115
119
|
"ofetch": "^1.5.1"
|
|
116
120
|
},
|
|
117
121
|
"peerDependenciesMeta": {
|
|
122
|
+
"@nuxt/kit": {
|
|
123
|
+
"optional": true
|
|
124
|
+
},
|
|
118
125
|
"h3": {
|
|
119
126
|
"optional": true
|
|
120
127
|
},
|