evlog 1.6.0 → 1.8.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 +96 -0
- package/dist/_http-DVDwNag0.mjs +76 -0
- package/dist/_http-DVDwNag0.mjs.map +1 -0
- package/dist/_severity-CXfyvxQi.mjs +17 -0
- package/dist/_severity-CXfyvxQi.mjs.map +1 -0
- package/dist/adapters/axiom.d.mts +17 -15
- package/dist/adapters/axiom.d.mts.map +1 -0
- package/dist/adapters/axiom.mjs +91 -50
- package/dist/adapters/axiom.mjs.map +1 -0
- package/dist/adapters/better-stack.d.mts +63 -0
- package/dist/adapters/better-stack.d.mts.map +1 -0
- package/dist/adapters/better-stack.mjs +98 -0
- package/dist/adapters/better-stack.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +32 -30
- package/dist/adapters/otlp.d.mts.map +1 -0
- package/dist/adapters/otlp.mjs +181 -181
- package/dist/adapters/otlp.mjs.map +1 -0
- package/dist/adapters/posthog.d.mts +54 -19
- package/dist/adapters/posthog.d.mts.map +1 -0
- package/dist/adapters/posthog.mjs +156 -63
- package/dist/adapters/posthog.mjs.map +1 -0
- package/dist/adapters/sentry.d.mts +25 -23
- package/dist/adapters/sentry.d.mts.map +1 -0
- package/dist/adapters/sentry.mjs +198 -153
- package/dist/adapters/sentry.mjs.map +1 -0
- package/dist/browser.d.mts +63 -0
- package/dist/browser.d.mts.map +1 -0
- package/dist/browser.mjs +95 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/enrichers.d.mts +74 -0
- package/dist/enrichers.d.mts.map +1 -0
- package/dist/enrichers.mjs +172 -0
- package/dist/enrichers.mjs.map +1 -0
- package/dist/error.d.mts +24 -22
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +107 -76
- package/dist/error.mjs.map +1 -0
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +6 -5
- package/dist/logger.d.mts +11 -5
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs +255 -186
- package/dist/logger.mjs.map +1 -0
- package/dist/nitro/errorHandler.d.mts +4 -2
- package/dist/nitro/errorHandler.d.mts.map +1 -0
- package/dist/nitro/errorHandler.mjs +38 -38
- package/dist/nitro/errorHandler.mjs.map +1 -0
- package/dist/nitro/module.d.mts +11 -0
- package/dist/nitro/module.d.mts.map +1 -0
- package/dist/nitro/module.mjs +23 -0
- package/dist/nitro/module.mjs.map +1 -0
- package/dist/nitro/plugin.d.mts +4 -2
- package/dist/nitro/plugin.d.mts.map +1 -0
- package/dist/nitro/plugin.mjs +135 -140
- package/dist/nitro/plugin.mjs.map +1 -0
- package/dist/nitro/v3/errorHandler.d.mts +24 -0
- package/dist/nitro/v3/errorHandler.d.mts.map +1 -0
- package/dist/nitro/v3/errorHandler.mjs +36 -0
- package/dist/nitro/v3/errorHandler.mjs.map +1 -0
- package/dist/nitro/v3/index.d.mts +4 -0
- package/dist/nitro/v3/index.mjs +4 -0
- package/dist/nitro/v3/module.d.mts +10 -0
- package/dist/nitro/v3/module.d.mts.map +1 -0
- package/dist/nitro/v3/module.mjs +22 -0
- package/dist/nitro/v3/module.mjs.map +1 -0
- package/dist/nitro/v3/plugin.d.mts +14 -0
- package/dist/nitro/v3/plugin.d.mts.map +1 -0
- package/dist/nitro/v3/plugin.mjs +157 -0
- package/dist/nitro/v3/plugin.mjs.map +1 -0
- package/dist/nitro/v3/useLogger.d.mts +24 -0
- package/dist/nitro/v3/useLogger.d.mts.map +1 -0
- package/dist/nitro/v3/useLogger.mjs +27 -0
- package/dist/nitro/v3/useLogger.mjs.map +1 -0
- package/dist/nitro-D57TWGyN.mjs +73 -0
- package/dist/nitro-D57TWGyN.mjs.map +1 -0
- package/dist/nitro-D81NBVPi.d.mts +42 -0
- package/dist/nitro-D81NBVPi.d.mts.map +1 -0
- package/dist/nuxt/module.d.mts +155 -168
- package/dist/nuxt/module.d.mts.map +1 -0
- package/dist/nuxt/module.mjs +75 -65
- package/dist/nuxt/module.mjs.map +1 -0
- package/dist/pipeline.d.mts +46 -0
- package/dist/pipeline.d.mts.map +1 -0
- package/dist/pipeline.mjs +122 -0
- package/dist/pipeline.mjs.map +1 -0
- package/dist/runtime/client/log.d.mts +12 -7
- package/dist/runtime/client/log.d.mts.map +1 -0
- package/dist/runtime/client/log.mjs +72 -64
- package/dist/runtime/client/log.mjs.map +1 -0
- package/dist/runtime/client/plugin.d.mts +3 -1
- package/dist/runtime/client/plugin.d.mts.map +1 -0
- package/dist/runtime/client/plugin.mjs +14 -12
- package/dist/runtime/client/plugin.mjs.map +1 -0
- package/dist/runtime/server/routes/_evlog/ingest.post.d.mts +4 -2
- package/dist/runtime/server/routes/_evlog/ingest.post.d.mts.map +1 -0
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs +113 -76
- package/dist/runtime/server/routes/_evlog/ingest.post.mjs.map +1 -0
- package/dist/runtime/server/useLogger.d.mts +14 -3
- package/dist/runtime/server/useLogger.d.mts.map +1 -0
- package/dist/runtime/server/useLogger.mjs +39 -10
- package/dist/runtime/server/useLogger.mjs.map +1 -0
- package/dist/runtime/utils/parseError.d.mts +5 -3
- package/dist/runtime/utils/parseError.d.mts.map +1 -0
- package/dist/runtime/utils/parseError.mjs +25 -26
- package/dist/runtime/utils/parseError.mjs.map +1 -0
- package/dist/types.d.mts +378 -246
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +1 -1
- package/dist/utils.d.mts +19 -14
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +59 -50
- package/dist/utils.mjs.map +1 -0
- package/dist/workers.d.mts +10 -9
- package/dist/workers.d.mts.map +1 -0
- package/dist/workers.mjs +68 -39
- package/dist/workers.mjs.map +1 -0
- package/package.json +55 -10
- package/dist/adapters/axiom.d.ts +0 -62
- package/dist/adapters/otlp.d.ts +0 -83
- package/dist/adapters/posthog.d.ts +0 -72
- package/dist/adapters/sentry.d.ts +0 -78
- package/dist/error.d.ts +0 -63
- package/dist/index.d.ts +0 -5
- package/dist/logger.d.ts +0 -40
- package/dist/nitro/errorHandler.d.ts +0 -13
- package/dist/nitro/plugin.d.ts +0 -5
- package/dist/nuxt/module.d.ts +0 -171
- package/dist/runtime/client/log.d.ts +0 -10
- package/dist/runtime/client/plugin.d.ts +0 -3
- package/dist/runtime/server/routes/_evlog/ingest.post.d.ts +0 -5
- package/dist/runtime/server/useLogger.d.ts +0 -28
- package/dist/runtime/utils/parseError.d.ts +0 -5
- package/dist/shared/evlog.Bc35pxiY.mjs +0 -10
- package/dist/types.d.ts +0 -364
- package/dist/utils.d.ts +0 -29
- package/dist/workers.d.ts +0 -45
package/dist/logger.mjs
CHANGED
|
@@ -1,218 +1,287 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from "./utils.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/logger.ts
|
|
3
4
|
function isPlainObject(val) {
|
|
4
|
-
|
|
5
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
5
6
|
}
|
|
6
7
|
function deepDefaults(base, defaults) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return result;
|
|
8
|
+
const result = { ...base };
|
|
9
|
+
for (const key in defaults) {
|
|
10
|
+
const baseVal = result[key];
|
|
11
|
+
const defaultVal = defaults[key];
|
|
12
|
+
if (baseVal === void 0 || baseVal === null) result[key] = defaultVal;
|
|
13
|
+
else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) result[key] = deepDefaults(baseVal, defaultVal);
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
18
16
|
}
|
|
19
17
|
let globalEnv = {
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
service: "app",
|
|
19
|
+
environment: "development"
|
|
22
20
|
};
|
|
23
21
|
let globalPretty = isDev();
|
|
24
22
|
let globalSampling = {};
|
|
25
23
|
let globalStringify = true;
|
|
24
|
+
let globalDrain;
|
|
25
|
+
let globalEnabled = true;
|
|
26
|
+
/**
|
|
27
|
+
* Initialize the logger with configuration.
|
|
28
|
+
* Call this once at application startup.
|
|
29
|
+
*/
|
|
26
30
|
function initLogger(config = {}) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
globalEnabled = config.enabled ?? true;
|
|
32
|
+
const detected = detectEnvironment();
|
|
33
|
+
globalEnv = {
|
|
34
|
+
service: config.env?.service ?? detected.service ?? "app",
|
|
35
|
+
environment: config.env?.environment ?? detected.environment ?? "development",
|
|
36
|
+
version: config.env?.version ?? detected.version,
|
|
37
|
+
commitHash: config.env?.commitHash ?? detected.commitHash,
|
|
38
|
+
region: config.env?.region ?? detected.region
|
|
39
|
+
};
|
|
40
|
+
globalPretty = config.pretty ?? isDev();
|
|
41
|
+
globalSampling = config.sampling ?? {};
|
|
42
|
+
globalStringify = config.stringify ?? true;
|
|
43
|
+
globalDrain = config.drain;
|
|
38
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if logging is globally enabled.
|
|
47
|
+
*/
|
|
48
|
+
function isEnabled() {
|
|
49
|
+
return globalEnabled;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Determine if a log at the given level should be emitted based on sampling config.
|
|
53
|
+
* Error level defaults to 100% (always logged) unless explicitly configured otherwise.
|
|
54
|
+
*/
|
|
39
55
|
function shouldSample(level) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (percentage >= 100) return true;
|
|
47
|
-
return Math.random() * 100 < percentage;
|
|
56
|
+
const { rates } = globalSampling;
|
|
57
|
+
if (!rates) return true;
|
|
58
|
+
const percentage = level === "error" && rates.error === void 0 ? 100 : rates[level] ?? 100;
|
|
59
|
+
if (percentage <= 0) return false;
|
|
60
|
+
if (percentage >= 100) return true;
|
|
61
|
+
return Math.random() * 100 < percentage;
|
|
48
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Evaluate tail sampling conditions to determine if a log should be force-kept.
|
|
65
|
+
* Returns true if ANY condition matches (OR logic).
|
|
66
|
+
*/
|
|
49
67
|
function shouldKeep(ctx) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
return false;
|
|
63
|
-
});
|
|
68
|
+
const { keep } = globalSampling;
|
|
69
|
+
if (!keep?.length) return false;
|
|
70
|
+
return keep.some((condition) => {
|
|
71
|
+
if (condition.status !== void 0 && ctx.status !== void 0 && ctx.status >= condition.status) return true;
|
|
72
|
+
if (condition.duration !== void 0 && ctx.duration !== void 0 && ctx.duration >= condition.duration) return true;
|
|
73
|
+
if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) return true;
|
|
74
|
+
return false;
|
|
75
|
+
});
|
|
64
76
|
}
|
|
65
77
|
function emitWideEvent(level, event, skipSamplingCheck = false) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
return formatted;
|
|
78
|
+
if (!globalEnabled) return null;
|
|
79
|
+
if (!skipSamplingCheck && !shouldSample(level)) return null;
|
|
80
|
+
const formatted = {
|
|
81
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
82
|
+
level,
|
|
83
|
+
...globalEnv,
|
|
84
|
+
...event
|
|
85
|
+
};
|
|
86
|
+
if (globalPretty) prettyPrintWideEvent(formatted);
|
|
87
|
+
else if (globalStringify) console[getConsoleMethod(level)](JSON.stringify(formatted));
|
|
88
|
+
else console[getConsoleMethod(level)](formatted);
|
|
89
|
+
if (globalDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
|
|
90
|
+
console.error("[evlog] drain failed:", err);
|
|
91
|
+
});
|
|
92
|
+
return formatted;
|
|
83
93
|
}
|
|
84
94
|
function emitTaggedLog(level, tag, message) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
if (!globalEnabled) return;
|
|
96
|
+
if (globalPretty) {
|
|
97
|
+
if (!shouldSample(level)) return;
|
|
98
|
+
const color = getLevelColor(level);
|
|
99
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
100
|
+
console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
emitWideEvent(level, {
|
|
104
|
+
tag,
|
|
105
|
+
message
|
|
106
|
+
});
|
|
95
107
|
}
|
|
96
108
|
function formatValue(value) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
pairs.push(`${k}=${JSON.stringify(v)}`);
|
|
106
|
-
} else {
|
|
107
|
-
pairs.push(`${k}=${v}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return pairs.join(" ");
|
|
112
|
-
}
|
|
113
|
-
return String(value);
|
|
109
|
+
if (value === null || value === void 0) return String(value);
|
|
110
|
+
if (typeof value === "object") {
|
|
111
|
+
const pairs = [];
|
|
112
|
+
for (const [k, v] of Object.entries(value)) if (v !== void 0 && v !== null) if (typeof v === "object") pairs.push(`${k}=${JSON.stringify(v)}`);
|
|
113
|
+
else pairs.push(`${k}=${v}`);
|
|
114
|
+
return pairs.join(" ");
|
|
115
|
+
}
|
|
116
|
+
return String(value);
|
|
114
117
|
}
|
|
115
118
|
function prettyPrintWideEvent(event) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
});
|
|
119
|
+
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
120
|
+
const levelColor = getLevelColor(level);
|
|
121
|
+
const ts = timestamp.slice(11, 23);
|
|
122
|
+
let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${level.toUpperCase()}${colors.reset}`;
|
|
123
|
+
header += ` ${colors.cyan}[${service}]${colors.reset}`;
|
|
124
|
+
if (rest.method && rest.path) {
|
|
125
|
+
header += ` ${rest.method} ${rest.path}`;
|
|
126
|
+
delete rest.method;
|
|
127
|
+
delete rest.path;
|
|
128
|
+
}
|
|
129
|
+
if (rest.status) {
|
|
130
|
+
const statusColor = rest.status >= 400 ? colors.red : colors.green;
|
|
131
|
+
header += ` ${statusColor}${rest.status}${colors.reset}`;
|
|
132
|
+
delete rest.status;
|
|
133
|
+
}
|
|
134
|
+
if (rest.duration) {
|
|
135
|
+
header += ` ${colors.dim}in ${rest.duration}${colors.reset}`;
|
|
136
|
+
delete rest.duration;
|
|
137
|
+
}
|
|
138
|
+
console.log(header);
|
|
139
|
+
const entries = Object.entries(rest).filter(([_, v]) => v !== void 0);
|
|
140
|
+
const lastIndex = entries.length - 1;
|
|
141
|
+
entries.forEach(([key, value], index) => {
|
|
142
|
+
const prefix = index === lastIndex ? "└─" : "├─";
|
|
143
|
+
const formatted = formatValue(value);
|
|
144
|
+
console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`);
|
|
145
|
+
});
|
|
144
146
|
}
|
|
145
147
|
function createLogMethod(level) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
} else {
|
|
152
|
-
emitTaggedLog(level, "log", String(tagOrEvent));
|
|
153
|
-
}
|
|
154
|
-
};
|
|
148
|
+
return function logMethod(tagOrEvent, message) {
|
|
149
|
+
if (typeof tagOrEvent === "string" && message !== void 0) emitTaggedLog(level, tagOrEvent, message);
|
|
150
|
+
else if (typeof tagOrEvent === "object") emitWideEvent(level, tagOrEvent);
|
|
151
|
+
else emitTaggedLog(level, "log", String(tagOrEvent));
|
|
152
|
+
};
|
|
155
153
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Simple logging API - as easy as console.log
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* log.info('auth', 'User logged in')
|
|
160
|
+
* log.error({ action: 'payment', error: 'failed' })
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
const _log = {
|
|
164
|
+
info: createLogMethod("info"),
|
|
165
|
+
error: createLogMethod("error"),
|
|
166
|
+
warn: createLogMethod("warn"),
|
|
167
|
+
debug: createLogMethod("debug")
|
|
168
|
+
};
|
|
169
|
+
const noopLogger = {
|
|
170
|
+
set() {},
|
|
171
|
+
error() {},
|
|
172
|
+
info() {},
|
|
173
|
+
warn() {},
|
|
174
|
+
emit() {
|
|
175
|
+
return null;
|
|
176
|
+
},
|
|
177
|
+
getContext() {
|
|
178
|
+
return {};
|
|
179
|
+
}
|
|
161
180
|
};
|
|
181
|
+
/**
|
|
182
|
+
* Create a request-scoped logger for building wide events.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* const log = createRequestLogger({ method: 'POST', path: '/checkout' })
|
|
187
|
+
* log.set({ user: { id: '123' } })
|
|
188
|
+
* log.set({ cart: { items: 3 } })
|
|
189
|
+
* log.emit()
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
162
192
|
function createRequestLogger(options = {}) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
193
|
+
if (!globalEnabled) return noopLogger;
|
|
194
|
+
const startTime = Date.now();
|
|
195
|
+
let context = {
|
|
196
|
+
method: options.method,
|
|
197
|
+
path: options.path,
|
|
198
|
+
requestId: options.requestId
|
|
199
|
+
};
|
|
200
|
+
let hasError = false;
|
|
201
|
+
let hasWarn = false;
|
|
202
|
+
function addRequestLog(level, message) {
|
|
203
|
+
const entry = {
|
|
204
|
+
level,
|
|
205
|
+
message,
|
|
206
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
207
|
+
};
|
|
208
|
+
const requestLogs = Array.isArray(context.requestLogs) ? [...context.requestLogs, entry] : [entry];
|
|
209
|
+
context = {
|
|
210
|
+
...context,
|
|
211
|
+
requestLogs
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
set(data) {
|
|
216
|
+
context = deepDefaults(data, context);
|
|
217
|
+
},
|
|
218
|
+
error(error, errorContext) {
|
|
219
|
+
hasError = true;
|
|
220
|
+
const err = typeof error === "string" ? new Error(error) : error;
|
|
221
|
+
context = deepDefaults({
|
|
222
|
+
...errorContext,
|
|
223
|
+
error: {
|
|
224
|
+
name: err.name,
|
|
225
|
+
message: err.message,
|
|
226
|
+
stack: err.stack,
|
|
227
|
+
..."status" in err && { status: err.status },
|
|
228
|
+
..."statusText" in err && { statusText: err.statusText },
|
|
229
|
+
..."statusCode" in err && { statusCode: err.statusCode },
|
|
230
|
+
..."statusMessage" in err && { statusMessage: err.statusMessage },
|
|
231
|
+
..."data" in err && { data: err.data },
|
|
232
|
+
..."cause" in err && { cause: err.cause }
|
|
233
|
+
}
|
|
234
|
+
}, context);
|
|
235
|
+
},
|
|
236
|
+
info(message, infoContext) {
|
|
237
|
+
addRequestLog("info", message);
|
|
238
|
+
if (infoContext) {
|
|
239
|
+
const { requestLogs: _, ...rest } = infoContext;
|
|
240
|
+
context = deepDefaults(rest, context);
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
warn(message, warnContext) {
|
|
244
|
+
hasWarn = true;
|
|
245
|
+
addRequestLog("warn", message);
|
|
246
|
+
if (warnContext) {
|
|
247
|
+
const { requestLogs: _, ...rest } = warnContext;
|
|
248
|
+
context = deepDefaults(rest, context);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
emit(overrides) {
|
|
252
|
+
const durationMs = Date.now() - startTime;
|
|
253
|
+
const duration = formatDuration(durationMs);
|
|
254
|
+
const level = hasError ? "error" : hasWarn ? "warn" : "info";
|
|
255
|
+
const { _forceKeep, ...restOverrides } = overrides ?? {};
|
|
256
|
+
const tailCtx = {
|
|
257
|
+
status: context.status ?? restOverrides.status,
|
|
258
|
+
duration: durationMs,
|
|
259
|
+
path: context.path,
|
|
260
|
+
method: context.method,
|
|
261
|
+
context: {
|
|
262
|
+
...context,
|
|
263
|
+
...restOverrides
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
if (!(_forceKeep || shouldKeep(tailCtx)) && !shouldSample(level)) return null;
|
|
267
|
+
return emitWideEvent(level, {
|
|
268
|
+
...context,
|
|
269
|
+
...restOverrides,
|
|
270
|
+
duration
|
|
271
|
+
}, true);
|
|
272
|
+
},
|
|
273
|
+
getContext() {
|
|
274
|
+
return { ...context };
|
|
275
|
+
}
|
|
276
|
+
};
|
|
213
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Get the current environment context.
|
|
280
|
+
*/
|
|
214
281
|
function getEnvironment() {
|
|
215
|
-
|
|
282
|
+
return { ...globalEnv };
|
|
216
283
|
}
|
|
217
284
|
|
|
218
|
-
|
|
285
|
+
//#endregion
|
|
286
|
+
export { createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
|
|
287
|
+
//# sourceMappingURL=logger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = {\n method: options.method,\n path: options.path,\n requestId: options.requestId,\n }\n let hasError = false\n let hasWarn = false\n\n function addRequestLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addRequestLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addRequestLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import * as nitropack from
|
|
1
|
+
import * as nitropack from "nitropack";
|
|
2
2
|
|
|
3
|
+
//#region src/nitro/errorHandler.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* Custom Nitro error handler that properly serializes EvlogError.
|
|
5
6
|
* This ensures that 'data' (containing 'why', 'fix', 'link') is preserved
|
|
@@ -9,5 +10,6 @@ import * as nitropack from 'nitropack';
|
|
|
9
10
|
* sanitizing internal error details in production for 5xx errors.
|
|
10
11
|
*/
|
|
11
12
|
declare const _default: nitropack.NitroErrorHandler;
|
|
12
|
-
|
|
13
|
+
//#endregion
|
|
13
14
|
export { _default as default };
|
|
15
|
+
//# sourceMappingURL=errorHandler.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorHandler.d.mts","names":[],"sources":["../../src/nitro/errorHandler.ts"],"mappings":""}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getRequestURL,
|
|
1
|
+
import { i as serializeEvlogErrorResponse, r as resolveEvlogError, t as extractErrorStatus } from "../nitro-D57TWGyN.mjs";
|
|
2
|
+
import { getRequestURL, send, setResponseHeader, setResponseStatus } from "h3";
|
|
3
|
+
import { defineNitroErrorHandler } from "nitropack/runtime/internal/error/utils";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
error: true,
|
|
37
|
-
...data !== void 0 && { data }
|
|
38
|
-
}));
|
|
5
|
+
//#region src/nitro/errorHandler.ts
|
|
6
|
+
/**
|
|
7
|
+
* Custom Nitro error handler that properly serializes EvlogError.
|
|
8
|
+
* This ensures that 'data' (containing 'why', 'fix', 'link') is preserved
|
|
9
|
+
* in the JSON response regardless of the underlying HTTP framework.
|
|
10
|
+
*
|
|
11
|
+
* For non-EvlogError, it preserves Nitro's default response shape while
|
|
12
|
+
* sanitizing internal error details in production for 5xx errors.
|
|
13
|
+
*/
|
|
14
|
+
var errorHandler_default = defineNitroErrorHandler((error, event) => {
|
|
15
|
+
const evlogError = resolveEvlogError(error);
|
|
16
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
17
|
+
const url = getRequestURL(event, { xForwardedHost: true }).pathname;
|
|
18
|
+
if (!evlogError) {
|
|
19
|
+
const status = extractErrorStatus(error);
|
|
20
|
+
const rawMessage = (error.statusText ?? error.statusMessage ?? error.message) || "Internal Server Error";
|
|
21
|
+
const message = isDev ? rawMessage : status >= 500 ? "Internal Server Error" : rawMessage;
|
|
22
|
+
setResponseStatus(event, status);
|
|
23
|
+
setResponseHeader(event, "Content-Type", "application/json");
|
|
24
|
+
return send(event, JSON.stringify({
|
|
25
|
+
url,
|
|
26
|
+
status,
|
|
27
|
+
statusCode: status,
|
|
28
|
+
statusText: message,
|
|
29
|
+
statusMessage: message,
|
|
30
|
+
message,
|
|
31
|
+
error: true
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
setResponseStatus(event, extractErrorStatus(evlogError));
|
|
35
|
+
setResponseHeader(event, "Content-Type", "application/json");
|
|
36
|
+
return send(event, JSON.stringify(serializeEvlogErrorResponse(evlogError, url)));
|
|
39
37
|
});
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
//#endregion
|
|
40
|
+
export { errorHandler_default as default };
|
|
41
|
+
//# sourceMappingURL=errorHandler.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorHandler.mjs","names":[],"sources":["../../src/nitro/errorHandler.ts"],"sourcesContent":["// Import from specific subpath — the barrel 'nitropack/runtime' re-exports from\n// internal/app.mjs which imports virtual modules that crash outside rollup builds.\nimport { defineNitroErrorHandler } from 'nitropack/runtime/internal/error/utils'\nimport { getRequestURL, setResponseHeader, setResponseStatus, send } from 'h3'\nimport { resolveEvlogError, extractErrorStatus, serializeEvlogErrorResponse } from '../nitro'\n\n/**\n * Custom Nitro error handler that properly serializes EvlogError.\n * This ensures that 'data' (containing 'why', 'fix', 'link') is preserved\n * in the JSON response regardless of the underlying HTTP framework.\n *\n * For non-EvlogError, it preserves Nitro's default response shape while\n * sanitizing internal error details in production for 5xx errors.\n */\nexport default defineNitroErrorHandler((error, event) => {\n const evlogError = resolveEvlogError(error)\n\n const isDev = process.env.NODE_ENV === 'development'\n const url = getRequestURL(event, { xForwardedHost: true }).pathname\n\n // For non-EvlogError, preserve Nitro's default response shape\n if (!evlogError) {\n const status = extractErrorStatus(error)\n\n // Derive message from statusText/statusMessage/message for cross-version compatibility\n const rawMessage = ((error as { statusText?: string }).statusText\n ?? (error as { statusMessage?: string }).statusMessage\n ?? error.message) || 'Internal Server Error'\n\n // Sanitize internal error details in production for 5xx errors\n const message = isDev\n ? rawMessage\n : (status >= 500 ? 'Internal Server Error' : rawMessage)\n\n setResponseStatus(event, status)\n setResponseHeader(event, 'Content-Type', 'application/json')\n\n return send(event, JSON.stringify({\n url,\n status,\n statusCode: status,\n statusText: message,\n statusMessage: message,\n message,\n error: true,\n }))\n }\n\n const status = extractErrorStatus(evlogError)\n\n setResponseStatus(event, status)\n setResponseHeader(event, 'Content-Type', 'application/json')\n\n return send(event, JSON.stringify(serializeEvlogErrorResponse(evlogError, url)))\n})\n"],"mappings":";;;;;;;;;;;;;AAcA,2BAAe,yBAAyB,OAAO,UAAU;CACvD,MAAM,aAAa,kBAAkB,MAAM;CAE3C,MAAM,QAAQ,QAAQ,IAAI,aAAa;CACvC,MAAM,MAAM,cAAc,OAAO,EAAE,gBAAgB,MAAM,CAAC,CAAC;AAG3D,KAAI,CAAC,YAAY;EACf,MAAM,SAAS,mBAAmB,MAAM;EAGxC,MAAM,cAAe,MAAkC,cACjD,MAAqC,iBACtC,MAAM,YAAY;EAGvB,MAAM,UAAU,QACZ,aACC,UAAU,MAAM,0BAA0B;AAE/C,oBAAkB,OAAO,OAAO;AAChC,oBAAkB,OAAO,gBAAgB,mBAAmB;AAE5D,SAAO,KAAK,OAAO,KAAK,UAAU;GAChC;GACA;GACA,YAAY;GACZ,YAAY;GACZ,eAAe;GACf;GACA,OAAO;GACR,CAAC,CAAC;;AAKL,mBAAkB,OAFH,mBAAmB,WAAW,CAEb;AAChC,mBAAkB,OAAO,gBAAgB,mBAAmB;AAE5D,QAAO,KAAK,OAAO,KAAK,UAAU,4BAA4B,YAAY,IAAI,CAAC,CAAC;EAChF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useLogger } from "../runtime/server/useLogger.mjs";
|
|
2
|
+
import { t as NitroModuleOptions } from "../nitro-D81NBVPi.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/nitro/module.d.ts
|
|
5
|
+
declare function evlog(options?: NitroModuleOptions): {
|
|
6
|
+
name: string;
|
|
7
|
+
setup(nitro: any): void;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { type NitroModuleOptions, evlog as default, useLogger };
|
|
11
|
+
//# sourceMappingURL=module.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.mts","names":[],"sources":["../../src/nitro/module.ts"],"mappings":";;;;iBAQwB,KAAA,CAAM,OAAA,GAAU,kBAAA"}
|