evlog 2.6.0 → 2.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 +27 -0
- package/dist/_drain-C9Nr-6Wc.mjs +18 -0
- package/dist/_drain-C9Nr-6Wc.mjs.map +1 -0
- package/dist/_http-C2UoHWgm.mjs +82 -0
- package/dist/_http-C2UoHWgm.mjs.map +1 -0
- package/dist/{_severity-Q1BuITU_.mjs → _severity-BLiOKoxh.mjs} +1 -1
- package/dist/{_severity-Q1BuITU_.mjs.map → _severity-BLiOKoxh.mjs.map} +1 -1
- package/dist/adapters/axiom.d.mts +3 -1
- package/dist/adapters/axiom.d.mts.map +1 -1
- package/dist/adapters/axiom.mjs +5 -2
- package/dist/adapters/axiom.mjs.map +1 -1
- package/dist/adapters/better-stack.d.mts +3 -1
- package/dist/adapters/better-stack.d.mts.map +1 -1
- package/dist/adapters/better-stack.mjs +5 -2
- package/dist/adapters/better-stack.mjs.map +1 -1
- package/dist/adapters/fs.d.mts +37 -0
- package/dist/adapters/fs.d.mts.map +1 -0
- package/dist/adapters/fs.mjs +106 -0
- package/dist/adapters/fs.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +3 -1
- package/dist/adapters/otlp.d.mts.map +1 -1
- package/dist/adapters/otlp.mjs +6 -3
- package/dist/adapters/otlp.mjs.map +1 -1
- package/dist/adapters/posthog.d.mts +3 -1
- package/dist/adapters/posthog.d.mts.map +1 -1
- package/dist/adapters/posthog.mjs +7 -3
- package/dist/adapters/posthog.mjs.map +1 -1
- package/dist/adapters/sentry.d.mts +3 -1
- package/dist/adapters/sentry.d.mts.map +1 -1
- package/dist/adapters/sentry.mjs +6 -3
- package/dist/adapters/sentry.mjs.map +1 -1
- package/dist/ai/index.d.mts +88 -0
- package/dist/ai/index.d.mts.map +1 -0
- package/dist/ai/index.mjs +199 -0
- package/dist/ai/index.mjs.map +1 -0
- package/dist/browser.d.mts +1 -1
- package/dist/client.d.mts +2 -0
- package/dist/client.mjs +2 -0
- package/dist/{dist-BsWcv7B8.mjs → dist-BFn8qsRC.mjs} +1 -1
- package/dist/{dist-BsWcv7B8.mjs.map → dist-BFn8qsRC.mjs.map} +1 -1
- package/dist/elysia/index.d.mts +2 -2
- package/dist/elysia/index.mjs +1 -1
- package/dist/enrichers.d.mts +1 -1
- package/dist/{error-iV3zJCY3.d.mts → error-BheHTFFB.d.mts} +2 -2
- package/dist/{error-iV3zJCY3.d.mts.map → error-BheHTFFB.d.mts.map} +1 -1
- package/dist/error.d.mts +1 -1
- package/dist/{errors-BJRXUfMg.mjs → errors-BQgyQ9xe.mjs} +1 -1
- package/dist/{errors-BJRXUfMg.mjs.map → errors-BQgyQ9xe.mjs.map} +1 -1
- package/dist/{errors-CKSfdvLa.d.mts → errors-D8WVZclz.d.mts} +2 -2
- package/dist/{errors-CKSfdvLa.d.mts.map → errors-D8WVZclz.d.mts.map} +1 -1
- package/dist/express/index.d.mts +2 -2
- package/dist/express/index.mjs +3 -3
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +2 -2
- package/dist/fastify/index.mjs +2 -2
- package/dist/{headers-Ba1eKT3i.mjs → headers-DJ_YZbxT.mjs} +9 -8
- package/dist/headers-DJ_YZbxT.mjs.map +1 -0
- package/dist/hono/index.d.mts +2 -2
- package/dist/hono/index.mjs +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/{logger-CvDYZUze.d.mts → logger-BkXYNnHP.d.mts} +21 -5
- package/dist/logger-BkXYNnHP.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -2
- package/dist/logger.mjs +111 -109
- package/dist/logger.mjs.map +1 -1
- package/dist/{middleware-hZqyXoSk.d.mts → middleware-B-4hPOVG.d.mts} +2 -2
- package/dist/{middleware-hZqyXoSk.d.mts.map → middleware-B-4hPOVG.d.mts.map} +1 -1
- package/dist/nestjs/index.d.mts +2 -2
- package/dist/nestjs/index.d.mts.map +1 -1
- package/dist/nestjs/index.mjs +3 -3
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/index.d.mts +10 -4
- package/dist/next/index.d.mts.map +1 -1
- package/dist/next/index.mjs +8 -5
- package/dist/next/index.mjs.map +1 -1
- package/dist/nitro/errorHandler.mjs +2 -2
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/plugin.mjs +6 -4
- package/dist/nitro/plugin.mjs.map +1 -1
- package/dist/nitro/v3/errorHandler.mjs +3 -3
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/plugin.mjs +7 -5
- package/dist/nitro/v3/plugin.mjs.map +1 -1
- package/dist/nitro/v3/useLogger.d.mts +1 -1
- package/dist/{nitro-D1pPm37T.mjs → nitro-CzyGROOC.mjs} +2 -2
- package/dist/nitro-CzyGROOC.mjs.map +1 -0
- package/dist/{nitro-CGGTUned.d.mts → nitro-DCNNxY_7.d.mts} +10 -2
- package/dist/nitro-DCNNxY_7.d.mts.map +1 -0
- package/dist/nuxt/module.d.mts +21 -1
- package/dist/nuxt/module.d.mts.map +1 -1
- package/dist/nuxt/module.mjs +7 -2
- package/dist/nuxt/module.mjs.map +1 -1
- package/dist/{parseError-BztqcPwZ.d.mts → parseError-B08FS7EQ.d.mts} +2 -2
- package/dist/parseError-B08FS7EQ.d.mts.map +1 -0
- package/dist/{routes-CE3_c-iZ.mjs → routes-CGPmbzCZ.mjs} +1 -1
- package/dist/{routes-CE3_c-iZ.mjs.map → routes-CGPmbzCZ.mjs.map} +1 -1
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/server/useLogger.d.mts +1 -1
- package/dist/runtime/utils/parseError.d.mts +2 -2
- package/dist/source-location-B1VVgXkh.mjs +1165 -0
- package/dist/source-location-B1VVgXkh.mjs.map +1 -0
- package/dist/{storage-CJBW5Vos.mjs → storage-DsueXspk.mjs} +1 -1
- package/dist/{storage-CJBW5Vos.mjs.map → storage-DsueXspk.mjs.map} +1 -1
- package/dist/sveltekit/index.d.mts +2 -2
- package/dist/sveltekit/index.mjs +4 -4
- package/dist/toolkit.d.mts +3 -3
- package/dist/toolkit.mjs +4 -4
- package/dist/{types-B8-kC2ME.d.mts → types-CBpJBj_7.d.mts} +11 -1
- package/dist/types-CBpJBj_7.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/{useLogger-_Ec6mXoR.d.mts → useLogger-DBPGEDf_.d.mts} +2 -2
- package/dist/{useLogger-_Ec6mXoR.d.mts.map → useLogger-DBPGEDf_.d.mts.map} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs +22 -16
- package/dist/utils.mjs.map +1 -1
- package/dist/vite/index.d.mts +80 -0
- package/dist/vite/index.d.mts.map +1 -0
- package/dist/vite/index.mjs +213 -0
- package/dist/vite/index.mjs.map +1 -0
- package/dist/workers.d.mts +1 -1
- package/package.json +53 -5
- package/dist/_http-DHpGetLZ.mjs +0 -72
- package/dist/_http-DHpGetLZ.mjs.map +0 -1
- package/dist/headers-Ba1eKT3i.mjs.map +0 -1
- package/dist/logger-CvDYZUze.d.mts.map +0 -1
- package/dist/nitro-CGGTUned.d.mts.map +0 -1
- package/dist/nitro-D1pPm37T.mjs.map +0 -1
- package/dist/parseError-BztqcPwZ.d.mts.map +0 -1
- package/dist/types-B8-kC2ME.d.mts.map +0 -1
package/dist/logger.mjs
CHANGED
|
@@ -3,15 +3,19 @@ import { colors, cssColors, detectEnvironment, escapeFormatString, formatDuratio
|
|
|
3
3
|
function isPlainObject(val) {
|
|
4
4
|
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
5
5
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
const _tsDate = /* @__PURE__ */ new Date();
|
|
7
|
+
function isoNow() {
|
|
8
|
+
_tsDate.setTime(Date.now());
|
|
9
|
+
return _tsDate.toISOString();
|
|
10
|
+
}
|
|
11
|
+
function mergeInto(target, source) {
|
|
12
|
+
for (const key in source) {
|
|
13
|
+
const sourceVal = source[key];
|
|
14
|
+
if (sourceVal === void 0 || sourceVal === null) continue;
|
|
15
|
+
const targetVal = target[key];
|
|
16
|
+
if (isPlainObject(sourceVal) && isPlainObject(targetVal)) mergeInto(targetVal, sourceVal);
|
|
17
|
+
else target[key] = sourceVal;
|
|
13
18
|
}
|
|
14
|
-
return result;
|
|
15
19
|
}
|
|
16
20
|
let globalEnv = {
|
|
17
21
|
service: "app",
|
|
@@ -22,6 +26,7 @@ let globalSampling = {};
|
|
|
22
26
|
let globalStringify = true;
|
|
23
27
|
let globalDrain;
|
|
24
28
|
let globalEnabled = true;
|
|
29
|
+
let globalSilent = false;
|
|
25
30
|
/**
|
|
26
31
|
* Initialize the logger with configuration.
|
|
27
32
|
* Call this once at application startup.
|
|
@@ -40,6 +45,8 @@ function initLogger(config = {}) {
|
|
|
40
45
|
globalSampling = config.sampling ?? {};
|
|
41
46
|
globalStringify = config.stringify ?? true;
|
|
42
47
|
globalDrain = config.drain;
|
|
48
|
+
globalSilent = config.silent ?? false;
|
|
49
|
+
if (globalSilent && !globalDrain && !config._suppressDrainWarning) console.warn("[evlog] silent mode is enabled but no drain is configured. Events will be built and sampled but not output anywhere. Set a drain via initLogger({ drain }) or a framework hook (evlog:drain).");
|
|
43
50
|
}
|
|
44
51
|
/**
|
|
45
52
|
* Check if logging is globally enabled.
|
|
@@ -48,6 +55,14 @@ function isEnabled() {
|
|
|
48
55
|
return globalEnabled;
|
|
49
56
|
}
|
|
50
57
|
/**
|
|
58
|
+
* @internal Get the globally configured drain callback.
|
|
59
|
+
* Used by framework middleware to fall back to the global drain
|
|
60
|
+
* when no middleware-level drain is provided.
|
|
61
|
+
*/
|
|
62
|
+
function getGlobalDrain() {
|
|
63
|
+
return globalDrain;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
51
66
|
* Determine if a log at the given level should be emitted based on sampling config.
|
|
52
67
|
* Error level defaults to 100% (always logged) unless explicitly configured otherwise.
|
|
53
68
|
*/
|
|
@@ -73,36 +88,46 @@ function shouldKeep(ctx) {
|
|
|
73
88
|
return false;
|
|
74
89
|
});
|
|
75
90
|
}
|
|
76
|
-
function emitWideEvent(level, event,
|
|
91
|
+
function emitWideEvent(level, event, deferDrain = false, ownsEvent = false) {
|
|
77
92
|
if (!globalEnabled) return null;
|
|
78
|
-
if (!
|
|
79
|
-
|
|
80
|
-
|
|
93
|
+
if (!ownsEvent && !shouldSample(level)) return null;
|
|
94
|
+
let formatted;
|
|
95
|
+
if (ownsEvent) {
|
|
96
|
+
event.timestamp = isoNow();
|
|
97
|
+
event.level = level;
|
|
98
|
+
if (event.service === void 0) event.service = globalEnv.service;
|
|
99
|
+
if (event.environment === void 0) event.environment = globalEnv.environment;
|
|
100
|
+
if (globalEnv.version !== void 0 && event.version === void 0) event.version = globalEnv.version;
|
|
101
|
+
if (globalEnv.commitHash !== void 0 && event.commitHash === void 0) event.commitHash = globalEnv.commitHash;
|
|
102
|
+
if (globalEnv.region !== void 0 && event.region === void 0) event.region = globalEnv.region;
|
|
103
|
+
formatted = event;
|
|
104
|
+
} else formatted = {
|
|
105
|
+
timestamp: isoNow(),
|
|
81
106
|
level,
|
|
82
107
|
...globalEnv,
|
|
83
108
|
...event
|
|
84
109
|
};
|
|
85
|
-
if (globalPretty) prettyPrintWideEvent(formatted);
|
|
110
|
+
if (!globalSilent) if (globalPretty) prettyPrintWideEvent(formatted);
|
|
86
111
|
else if (globalStringify) console[getConsoleMethod(level)](JSON.stringify(formatted));
|
|
87
112
|
else console[getConsoleMethod(level)](formatted);
|
|
88
|
-
if (globalDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
|
|
113
|
+
if (globalDrain && !deferDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
|
|
89
114
|
console.error("[evlog] drain failed:", err);
|
|
90
115
|
});
|
|
91
116
|
return formatted;
|
|
92
117
|
}
|
|
93
118
|
function emitTaggedLog(level, tag, message) {
|
|
94
119
|
if (!globalEnabled) return;
|
|
95
|
-
if (globalPretty) {
|
|
120
|
+
if (globalPretty && !globalSilent) {
|
|
96
121
|
if (!shouldSample(level)) return;
|
|
97
122
|
if (isClient()) {
|
|
98
123
|
const levelColor = getCssLevelColor(level);
|
|
99
|
-
const timestamp = (
|
|
124
|
+
const timestamp = isoNow().slice(11, 23);
|
|
100
125
|
console.log(`%c${timestamp}%c %c[${escapeFormatString(tag)}]%c ${escapeFormatString(message)}`, cssColors.dim, cssColors.reset, levelColor, cssColors.reset);
|
|
101
|
-
|
|
126
|
+
} else {
|
|
127
|
+
const color = getLevelColor(level);
|
|
128
|
+
const timestamp = isoNow().slice(11, 23);
|
|
129
|
+
console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
|
|
102
130
|
}
|
|
103
|
-
const color = getLevelColor(level);
|
|
104
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
105
|
-
console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
|
|
106
131
|
return;
|
|
107
132
|
}
|
|
108
133
|
emitWideEvent(level, {
|
|
@@ -121,60 +146,37 @@ function formatValue(value) {
|
|
|
121
146
|
return String(value);
|
|
122
147
|
}
|
|
123
148
|
function prettyPrintWideEvent(event) {
|
|
124
|
-
if (isClient()) {
|
|
125
|
-
prettyPrintWideEventBrowser(event);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
129
|
-
const levelColor = getLevelColor(level);
|
|
130
|
-
const ts = timestamp.slice(11, 23);
|
|
131
|
-
let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${level.toUpperCase()}${colors.reset}`;
|
|
132
|
-
header += ` ${colors.cyan}[${service}]${colors.reset}`;
|
|
133
|
-
if (rest.method && rest.path) {
|
|
134
|
-
header += ` ${rest.method} ${rest.path}`;
|
|
135
|
-
delete rest.method;
|
|
136
|
-
delete rest.path;
|
|
137
|
-
}
|
|
138
|
-
if (rest.status) {
|
|
139
|
-
const statusColor = rest.status >= 400 ? colors.red : colors.green;
|
|
140
|
-
header += ` ${statusColor}${rest.status}${colors.reset}`;
|
|
141
|
-
delete rest.status;
|
|
142
|
-
}
|
|
143
|
-
if (rest.duration) {
|
|
144
|
-
header += ` ${colors.dim}in ${rest.duration}${colors.reset}`;
|
|
145
|
-
delete rest.duration;
|
|
146
|
-
}
|
|
147
|
-
console.log(header);
|
|
148
|
-
const entries = Object.entries(rest).filter(([_, v]) => v !== void 0);
|
|
149
|
-
const lastIndex = entries.length - 1;
|
|
150
|
-
entries.forEach(([key, value], index) => {
|
|
151
|
-
const prefix = index === lastIndex ? "└─" : "├─";
|
|
152
|
-
const formatted = formatValue(value);
|
|
153
|
-
console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`);
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function prettyPrintWideEventBrowser(event) {
|
|
157
149
|
const { timestamp, level, service, environment, version, ...rest } = event;
|
|
158
|
-
const levelColor = getCssLevelColor(level);
|
|
159
150
|
const ts = timestamp.slice(11, 23);
|
|
151
|
+
const browser = isClient();
|
|
160
152
|
const parts = [];
|
|
161
153
|
const styles = [];
|
|
162
|
-
|
|
163
|
-
|
|
154
|
+
if (browser) {
|
|
155
|
+
const lc = getCssLevelColor(level);
|
|
156
|
+
parts.push(`%c${ts}%c %c${level.toUpperCase()}%c %c[${escapeFormatString(String(service))}]%c`);
|
|
157
|
+
styles.push(cssColors.dim, cssColors.reset, lc, cssColors.reset, cssColors.cyan, cssColors.reset);
|
|
158
|
+
} else {
|
|
159
|
+
const lc = getLevelColor(level);
|
|
160
|
+
parts.push(`${colors.dim}${ts}${colors.reset} ${lc}${level.toUpperCase()}${colors.reset} ${colors.cyan}[${service}]${colors.reset}`);
|
|
161
|
+
}
|
|
164
162
|
if (rest.method && rest.path) {
|
|
165
|
-
parts.push(` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}`);
|
|
163
|
+
parts.push(browser ? ` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}` : ` ${rest.method} ${rest.path}`);
|
|
166
164
|
delete rest.method;
|
|
167
165
|
delete rest.path;
|
|
168
166
|
}
|
|
169
167
|
if (rest.status) {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
const sc = browser ? rest.status >= 400 ? cssColors.red : cssColors.green : rest.status >= 400 ? colors.red : colors.green;
|
|
169
|
+
if (browser) {
|
|
170
|
+
parts.push(` %c${rest.status}%c`);
|
|
171
|
+
styles.push(sc, cssColors.reset);
|
|
172
|
+
} else parts.push(` ${sc}${rest.status}${colors.reset}`);
|
|
173
173
|
delete rest.status;
|
|
174
174
|
}
|
|
175
175
|
if (rest.duration) {
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
if (browser) {
|
|
177
|
+
parts.push(` %c${escapeFormatString(`in ${rest.duration}`)}%c`);
|
|
178
|
+
styles.push(cssColors.dim, cssColors.reset);
|
|
179
|
+
} else parts.push(` ${colors.dim}in ${rest.duration}${colors.reset}`);
|
|
178
180
|
delete rest.duration;
|
|
179
181
|
}
|
|
180
182
|
console.log(parts.join(""), ...styles);
|
|
@@ -182,8 +184,9 @@ function prettyPrintWideEventBrowser(event) {
|
|
|
182
184
|
const lastIndex = entries.length - 1;
|
|
183
185
|
entries.forEach(([key, value], index) => {
|
|
184
186
|
const prefix = index === lastIndex ? "└─" : "├─";
|
|
185
|
-
const
|
|
186
|
-
console.log(` %c${prefix}%c %c${escapeFormatString(key)}:%c ${
|
|
187
|
+
const val = formatValue(value);
|
|
188
|
+
if (browser) console.log(` %c${prefix}%c %c${escapeFormatString(key)}:%c ${escapeFormatString(val)}`, cssColors.dim, cssColors.reset, cssColors.cyan, cssColors.reset);
|
|
189
|
+
else console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${val}`);
|
|
187
190
|
});
|
|
188
191
|
}
|
|
189
192
|
function createLogMethod(level) {
|
|
@@ -231,51 +234,51 @@ const noopLogger = {
|
|
|
231
234
|
* log.emit()
|
|
232
235
|
* ```
|
|
233
236
|
*/
|
|
234
|
-
function createLogger(initialContext = {}) {
|
|
237
|
+
function createLogger(initialContext = {}, internalOptions) {
|
|
235
238
|
if (!globalEnabled) return noopLogger;
|
|
239
|
+
const deferDrain = internalOptions?._deferDrain ?? false;
|
|
236
240
|
const startTime = Date.now();
|
|
237
|
-
|
|
241
|
+
const context = { ...initialContext };
|
|
238
242
|
let hasError = false;
|
|
239
243
|
let hasWarn = false;
|
|
240
244
|
function addLog(level, message) {
|
|
241
|
-
|
|
245
|
+
if (!Array.isArray(context.requestLogs)) context.requestLogs = [];
|
|
246
|
+
context.requestLogs.push({
|
|
242
247
|
level,
|
|
243
248
|
message,
|
|
244
|
-
timestamp: (
|
|
245
|
-
};
|
|
246
|
-
const requestLogs = Array.isArray(context.requestLogs) ? [...context.requestLogs, entry] : [entry];
|
|
247
|
-
context = {
|
|
248
|
-
...context,
|
|
249
|
-
requestLogs
|
|
250
|
-
};
|
|
249
|
+
timestamp: isoNow()
|
|
250
|
+
});
|
|
251
251
|
}
|
|
252
252
|
return {
|
|
253
253
|
set(data) {
|
|
254
|
-
context
|
|
254
|
+
mergeInto(context, data);
|
|
255
255
|
},
|
|
256
256
|
error(error, errorContext) {
|
|
257
257
|
hasError = true;
|
|
258
258
|
const err = typeof error === "string" ? new Error(error) : error;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
259
|
+
if (errorContext) mergeInto(context, errorContext);
|
|
260
|
+
const errorObj = {
|
|
261
|
+
name: err.name,
|
|
262
|
+
message: err.message,
|
|
263
|
+
stack: err.stack
|
|
264
|
+
};
|
|
265
|
+
const errRecord = err;
|
|
266
|
+
for (const k of [
|
|
267
|
+
"status",
|
|
268
|
+
"statusText",
|
|
269
|
+
"statusCode",
|
|
270
|
+
"statusMessage",
|
|
271
|
+
"data",
|
|
272
|
+
"cause"
|
|
273
|
+
]) if (k in err) errorObj[k] = errRecord[k];
|
|
274
|
+
if (isPlainObject(context.error)) mergeInto(context.error, errorObj);
|
|
275
|
+
else context.error = errorObj;
|
|
273
276
|
},
|
|
274
277
|
info(message, infoContext) {
|
|
275
278
|
addLog("info", message);
|
|
276
279
|
if (infoContext) {
|
|
277
280
|
const { requestLogs: _, ...rest } = infoContext;
|
|
278
|
-
context
|
|
281
|
+
mergeInto(context, rest);
|
|
279
282
|
}
|
|
280
283
|
},
|
|
281
284
|
warn(message, warnContext) {
|
|
@@ -283,30 +286,28 @@ function createLogger(initialContext = {}) {
|
|
|
283
286
|
addLog("warn", message);
|
|
284
287
|
if (warnContext) {
|
|
285
288
|
const { requestLogs: _, ...rest } = warnContext;
|
|
286
|
-
context
|
|
289
|
+
mergeInto(context, rest);
|
|
287
290
|
}
|
|
288
291
|
},
|
|
289
292
|
emit(overrides) {
|
|
290
293
|
const durationMs = Date.now() - startTime;
|
|
291
|
-
const duration = formatDuration(durationMs);
|
|
292
294
|
const level = hasError ? "error" : hasWarn ? "warn" : "info";
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
let forceKeep = false;
|
|
296
|
+
if (overrides?._forceKeep) forceKeep = true;
|
|
297
|
+
else if (globalSampling.keep?.length) forceKeep = shouldKeep({
|
|
298
|
+
status: overrides?.status ?? context.status,
|
|
296
299
|
duration: durationMs,
|
|
297
300
|
path: context.path,
|
|
298
301
|
method: context.method,
|
|
299
|
-
context
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
duration
|
|
309
|
-
}, true);
|
|
302
|
+
context
|
|
303
|
+
});
|
|
304
|
+
if (!forceKeep && !shouldSample(level)) return null;
|
|
305
|
+
if (overrides) {
|
|
306
|
+
const obj = overrides;
|
|
307
|
+
for (const key in obj) if (key !== "_forceKeep") context[key] = obj[key];
|
|
308
|
+
}
|
|
309
|
+
context.duration = formatDuration(durationMs);
|
|
310
|
+
return emitWideEvent(level, context, deferDrain, true);
|
|
310
311
|
},
|
|
311
312
|
getContext() {
|
|
312
313
|
return { ...context };
|
|
@@ -325,12 +326,12 @@ function createLogger(initialContext = {}) {
|
|
|
325
326
|
* log.emit()
|
|
326
327
|
* ```
|
|
327
328
|
*/
|
|
328
|
-
function createRequestLogger(options = {}) {
|
|
329
|
+
function createRequestLogger(options = {}, internalOptions) {
|
|
329
330
|
const initial = {};
|
|
330
331
|
if (options.method !== void 0) initial.method = options.method;
|
|
331
332
|
if (options.path !== void 0) initial.path = options.path;
|
|
332
333
|
if (options.requestId !== void 0) initial.requestId = options.requestId;
|
|
333
|
-
return createLogger(initial);
|
|
334
|
+
return createLogger(initial, internalOptions);
|
|
334
335
|
}
|
|
335
336
|
/**
|
|
336
337
|
* Get the current environment context.
|
|
@@ -338,7 +339,8 @@ function createRequestLogger(options = {}) {
|
|
|
338
339
|
function getEnvironment() {
|
|
339
340
|
return { ...globalEnv };
|
|
340
341
|
}
|
|
342
|
+
if (typeof __EVLOG_CONFIG__ !== "undefined") initLogger(__EVLOG_CONFIG__);
|
|
341
343
|
//#endregion
|
|
342
|
-
export { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
|
|
344
|
+
export { createLogger, createRequestLogger, getEnvironment, getGlobalDrain, initLogger, isEnabled, _log as log, shouldKeep };
|
|
343
345
|
|
|
344
346
|
//# sourceMappingURL=logger.mjs.map
|
package/dist/logger.mjs.map
CHANGED
|
@@ -1 +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, cssColors, detectEnvironment, escapeFormatString, formatDuration, getConsoleMethod, getCssLevelColor, getLevelColor, isClient, 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\n if (isClient()) {\n const levelColor = getCssLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(\n `%c${timestamp}%c %c[${escapeFormatString(tag)}]%c ${escapeFormatString(message)}`,\n cssColors.dim,\n cssColors.reset,\n levelColor,\n cssColors.reset,\n )\n return\n }\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 if (isClient()) {\n prettyPrintWideEventBrowser(event)\n return\n }\n\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 prettyPrintWideEventBrowser(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getCssLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n const parts: string[] = []\n const styles: string[] = []\n\n parts.push(`%c${ts}%c %c${(level as string).toUpperCase()}%c %c[${escapeFormatString(String(service))}]%c`)\n styles.push(cssColors.dim, cssColors.reset, levelColor, cssColors.reset, cssColors.cyan, cssColors.reset)\n\n if (rest.method && rest.path) {\n parts.push(` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}`)\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? cssColors.red : cssColors.green\n parts.push(` %c${rest.status}%c`)\n styles.push(statusColor, cssColors.reset)\n delete rest.status\n }\n\n if (rest.duration) {\n parts.push(` %c${escapeFormatString(`in ${rest.duration}`)}%c`)\n styles.push(cssColors.dim, cssColors.reset)\n delete rest.duration\n }\n\n console.log(parts.join(''), ...styles)\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 = escapeFormatString(formatValue(value))\n console.log(\n ` %c${prefix}%c %c${escapeFormatString(key)}:%c ${formatted}`,\n cssColors.dim,\n cssColors.reset,\n cssColors.cyan,\n cssColors.reset,\n )\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 scoped logger for building wide events.\n * Use this for any context: workflows, jobs, scripts, queues, etc.\n *\n * @example\n * ```ts\n * const log = createLogger({ jobId: job.id, queue: 'emails' })\n * log.set({ batch: { size: 50, processed: 12 } })\n * log.emit()\n * ```\n */\nexport function createLogger<T extends object = Record<string, unknown>>(initialContext: Record<string, unknown> = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = { ...initialContext }\n let hasError = false\n let hasWarn = false\n\n function addLog(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 addLog('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 addLog('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 * Create a request-scoped logger for building wide events.\n * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.\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 const initial: Record<string, unknown> = {}\n if (options.method !== undefined) initial.method = options.method\n if (options.path !== undefined) initial.path = options.path\n if (options.requestId !== undefined) initial.requestId = options.requestId\n return createLogger<T>(initial)\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
|
+
{"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, cssColors, detectEnvironment, escapeFormatString, formatDuration, getConsoleMethod, getCssLevelColor, getLevelColor, isClient, 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\nconst _tsDate = new Date()\nfunction isoNow(): string {\n _tsDate.setTime(Date.now())\n return _tsDate.toISOString()\n}\n\nfunction mergeInto(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const key in source) {\n const sourceVal = source[key]\n if (sourceVal === undefined || sourceVal === null) continue\n const targetVal = target[key]\n if (isPlainObject(sourceVal) && isPlainObject(targetVal)) {\n mergeInto(targetVal, sourceVal)\n } else {\n target[key] = sourceVal\n }\n }\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\nlet globalSilent = false\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 globalSilent = config.silent ?? false\n\n if (globalSilent && !globalDrain && !config._suppressDrainWarning) {\n console.warn('[evlog] silent mode is enabled but no drain is configured. Events will be built and sampled but not output anywhere. Set a drain via initLogger({ drain }) or a framework hook (evlog:drain).')\n }\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * @internal Get the globally configured drain callback.\n * Used by framework middleware to fall back to the global drain\n * when no middleware-level drain is provided.\n */\nexport function getGlobalDrain(): ((ctx: DrainContext) => void | Promise<void>) | undefined {\n return globalDrain\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>, deferDrain = false, ownsEvent = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!ownsEvent && !shouldSample(level)) {\n return null\n }\n\n let formatted: WideEvent\n if (ownsEvent) {\n event.timestamp = isoNow()\n event.level = level\n if (event.service === undefined) event.service = globalEnv.service\n if (event.environment === undefined) event.environment = globalEnv.environment\n if (globalEnv.version !== undefined && event.version === undefined) event.version = globalEnv.version\n if (globalEnv.commitHash !== undefined && event.commitHash === undefined) event.commitHash = globalEnv.commitHash\n if (globalEnv.region !== undefined && event.region === undefined) event.region = globalEnv.region\n formatted = event as WideEvent\n } else {\n formatted = {\n timestamp: isoNow(),\n level,\n ...globalEnv,\n ...event,\n }\n }\n\n if (!globalSilent) {\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\n if (globalDrain && !deferDrain) {\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 && !globalSilent) {\n if (!shouldSample(level)) {\n return\n }\n\n if (isClient()) {\n const levelColor = getCssLevelColor(level)\n const timestamp = isoNow().slice(11, 23)\n console.log(\n `%c${timestamp}%c %c[${escapeFormatString(tag)}]%c ${escapeFormatString(message)}`,\n cssColors.dim,\n cssColors.reset,\n levelColor,\n cssColors.reset,\n )\n } else {\n const color = getLevelColor(level)\n const timestamp = isoNow().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n }\n\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 ts = (timestamp as string).slice(11, 23)\n const browser = isClient()\n\n const parts: string[] = []\n const styles: string[] = []\n\n if (browser) {\n const lc = getCssLevelColor(level as string)\n parts.push(`%c${ts}%c %c${(level as string).toUpperCase()}%c %c[${escapeFormatString(String(service))}]%c`)\n styles.push(cssColors.dim, cssColors.reset, lc, cssColors.reset, cssColors.cyan, cssColors.reset)\n } else {\n const lc = getLevelColor(level as string)\n parts.push(`${colors.dim}${ts}${colors.reset} ${lc}${(level as string).toUpperCase()}${colors.reset} ${colors.cyan}[${service}]${colors.reset}`)\n }\n\n if (rest.method && rest.path) {\n parts.push(browser ? ` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}` : ` ${rest.method} ${rest.path}`)\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const sc = browser\n ? ((rest.status as number) >= 400 ? cssColors.red : cssColors.green)\n : ((rest.status as number) >= 400 ? colors.red : colors.green)\n if (browser) {\n parts.push(` %c${rest.status}%c`)\n styles.push(sc, cssColors.reset)\n } else {\n parts.push(` ${sc}${rest.status}${colors.reset}`)\n }\n delete rest.status\n }\n\n if (rest.duration) {\n if (browser) {\n parts.push(` %c${escapeFormatString(`in ${rest.duration}`)}%c`)\n styles.push(cssColors.dim, cssColors.reset)\n } else {\n parts.push(` ${colors.dim}in ${rest.duration}${colors.reset}`)\n }\n delete rest.duration\n }\n\n console.log(parts.join(''), ...styles)\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 prefix = index === lastIndex ? '└─' : '├─'\n const val = formatValue(value)\n if (browser) {\n console.log(` %c${prefix}%c %c${escapeFormatString(key)}:%c ${escapeFormatString(val)}`, cssColors.dim, cssColors.reset, cssColors.cyan, cssColors.reset)\n } else {\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${val}`)\n }\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 * @internal Options for createLogger that are not part of the public API.\n */\ninterface CreateLoggerInternalOptions {\n /**\n * When true, the global drain is skipped on emit.\n * Used by framework middleware that runs its own enrich+drain pipeline.\n */\n _deferDrain?: boolean\n}\n\n/**\n * Create a scoped logger for building wide events.\n * Use this for any context: workflows, jobs, scripts, queues, etc.\n *\n * @example\n * ```ts\n * const log = createLogger({ jobId: job.id, queue: 'emails' })\n * log.set({ batch: { size: 50, processed: 12 } })\n * log.emit()\n * ```\n */\nexport function createLogger<T extends object = Record<string, unknown>>(initialContext: Record<string, unknown> = {}, internalOptions?: CreateLoggerInternalOptions): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const deferDrain = internalOptions?._deferDrain ?? false\n const startTime = Date.now()\n const context: Record<string, unknown> = { ...initialContext }\n let hasError = false\n let hasWarn = false\n\n function addLog(level: 'info' | 'warn', message: string): void {\n if (!Array.isArray(context.requestLogs)) {\n context.requestLogs = []\n }\n (context.requestLogs as unknown[]).push({\n level,\n message,\n timestamp: isoNow(),\n })\n }\n\n return {\n set(data: FieldContext<T>): void {\n mergeInto(context, data 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 if (errorContext) {\n mergeInto(context, errorContext as Record<string, unknown>)\n }\n\n const errorObj: Record<string, unknown> = {\n name: err.name,\n message: err.message,\n stack: err.stack,\n }\n const errRecord = err as unknown as Record<string, unknown>\n for (const k of ['status', 'statusText', 'statusCode', 'statusMessage', 'data', 'cause'] as const) {\n if (k in err) errorObj[k] = errRecord[k]\n }\n\n if (isPlainObject(context.error)) {\n mergeInto(context.error as Record<string, unknown>, errorObj)\n } else {\n context.error = errorObj\n }\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n mergeInto(context, rest)\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n mergeInto(context, rest)\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n let forceKeep = false\n if (overrides?._forceKeep) {\n forceKeep = true\n } else if (globalSampling.keep?.length) {\n const status = (overrides as Record<string, unknown> | undefined)?.status ?? context.status\n forceKeep = shouldKeep({\n status: status as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context,\n })\n }\n\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n if (overrides) {\n const obj = overrides as Record<string, unknown>\n for (const key in obj) {\n if (key !== '_forceKeep') context[key] = obj[key]\n }\n }\n context.duration = formatDuration(durationMs)\n\n return emitWideEvent(level, context, deferDrain, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.\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 = {}, internalOptions?: CreateLoggerInternalOptions): RequestLogger<T> {\n const initial: Record<string, unknown> = {}\n if (options.method !== undefined) initial.method = options.method\n if (options.path !== undefined) initial.path = options.path\n if (options.requestId !== undefined) initial.requestId = options.requestId\n return createLogger<T>(initial, internalOptions)\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\ndeclare const __EVLOG_CONFIG__: import('./types').LoggerConfig | undefined\n\nif (typeof __EVLOG_CONFIG__ !== 'undefined') initLogger(__EVLOG_CONFIG__)\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as TailSamplingContext, T as WideEvent, g as RequestLogger, i as EnrichContext, r as DrainContext, v as RouteConfig } from "./types-
|
|
1
|
+
import { C as TailSamplingContext, T as WideEvent, g as RequestLogger, i as EnrichContext, r as DrainContext, v as RouteConfig } from "./types-CBpJBj_7.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/middleware.d.ts
|
|
4
4
|
/**
|
|
@@ -72,4 +72,4 @@ interface MiddlewareLoggerResult {
|
|
|
72
72
|
declare function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult;
|
|
73
73
|
//#endregion
|
|
74
74
|
export { createMiddlewareLogger as i, MiddlewareLoggerOptions as n, MiddlewareLoggerResult as r, BaseEvlogOptions as t };
|
|
75
|
-
//# sourceMappingURL=middleware-
|
|
75
|
+
//# sourceMappingURL=middleware-B-4hPOVG.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware-
|
|
1
|
+
{"version":3,"file":"middleware-B-4hPOVG.d.mts","names":[],"sources":["../src/shared/middleware.ts"],"mappings":";;;;;AAcA;;;;;;;UAAiB,gBAAA;EAgByB;EAdxC,OAAA;EAmB4C;EAjB5C,OAAA;EAiBmD;EAfnD,MAAA,GAAS,MAAA,SAAe,WAAA;EAFxB;;;;EAOA,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAAxB;;;;EAKd,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAA9B;;;;EAKV,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;AAAA;;;AAQ9C;;;UAAiB,uBAAA,SAAgC,gBAAA;EAC/C,MAAA;EACA,IAAA;EACA,SAAA;EAAA;EAEA,OAAA,GAAU,MAAA;AAAA;AAAA,UAGK,sBAAA;EACf,MAAA,EAAQ,aAAA;EACR,MAAA,GAAS,IAAA;IAAS,MAAA;IAAiB,KAAA,GAAQ,KAAA;EAAA,MAAY,OAAA,CAAQ,SAAA;EAC/D,OAAA;AAAA;;;;;;;;;;;;;;;;AAuEF;iBAAgB,sBAAA,CAAuB,OAAA,EAAS,uBAAA,GAA0B,sBAAA"}
|
package/dist/nestjs/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as RequestLogger } from "../types-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-CBpJBj_7.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-B-4hPOVG.mjs";
|
|
3
3
|
import { DynamicModule, MiddlewareConsumer, NestModule } from "@nestjs/common";
|
|
4
4
|
|
|
5
5
|
//#region src/nestjs/index.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/nestjs/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/nestjs/index.ts"],"mappings":";;;;;cAQiB,SAAA,sBAAS,MAAA,wBAAA,aAAA,CAAA,CAAA;AAAA,KAId,kBAAA,GAAqB,gBAAA;AAAA,UAIhB,uBAAA;EANhB;EAQC,OAAA;EAVwB;EAYxB,UAAA,MAAgB,IAAA,YAAgB,kBAAA,GAAqB,OAAA,CAAQ,kBAAA;EAZrC;EAcxB,MAAA;AAAA;AAAA;EAAA,UAIU,eAAA;IACR,GAAA,GAAM,aAAA;EAAA;AAAA;AAAA;EAAA,UAKE,OAAA;IACR,GAAA,GAAM,aAAA;EAAA;AAAA;AAjBV;;;;;;;;;;;;;;;;;AAOC;;;;;;;AAPD,cA0Ea,WAAA,YAAuB,UAAA;EAAA,eAEnB,OAAA;EAjEM;AAAA;;;;;;;;;;EAAA,OA8Ed,OAAA,CAAQ,OAAA,GAAS,kBAAA,GAA0B,aAAA;EAf3B;;;;;;;;;;;;;;EAAA,OAqChB,YAAA,CAAa,YAAA,EAAc,uBAAA,GAA0B,aAAA;EAkB5D,SAAA,CAAU,QAAA,EAAU,kBAAA;AAAA"}
|
package/dist/nestjs/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-
|
|
2
|
-
import { t as createLoggerStorage } from "../storage-
|
|
1
|
+
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-DJ_YZbxT.mjs";
|
|
2
|
+
import { t as createLoggerStorage } from "../storage-DsueXspk.mjs";
|
|
3
3
|
//#region src/nestjs/index.ts
|
|
4
4
|
const { storage, useLogger } = createLoggerStorage("middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.");
|
|
5
5
|
function createEvlogMiddleware(getOptions) {
|
|
6
6
|
return (req, res, next) => {
|
|
7
7
|
const options = getOptions();
|
|
8
8
|
const headers = extractSafeNodeHeaders(req.headers);
|
|
9
|
-
const url = new URL(req.url || "/", "http://localhost");
|
|
9
|
+
const url = new URL(req.originalUrl || req.url || "/", "http://localhost");
|
|
10
10
|
const { logger, finish, skipped } = createMiddlewareLogger({
|
|
11
11
|
method: req.method || "GET",
|
|
12
12
|
path: url.pathname,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import type { ServerResponse } from 'node:http'\nimport type { Request } from 'express'\nimport type { DynamicModule, MiddlewareConsumer, NestModule } from '@nestjs/common'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { extractSafeNodeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.',\n)\n\nexport type EvlogNestJSOptions = BaseEvlogOptions\n\nexport { useLogger }\n\nexport interface EvlogModuleAsyncOptions {\n /** Modules to import (for dependency injection into the factory) */\n imports?: any[]\n /** Factory function that returns evlog options. Can be async. */\n useFactory: (...args: any[]) => EvlogNestJSOptions | Promise<EvlogNestJSOptions>\n /** Injection tokens to resolve and pass to the factory */\n inject?: any[]\n}\n\ndeclare module 'http' {\n interface IncomingMessage {\n log?: RequestLogger\n }\n}\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log?: RequestLogger\n }\n}\n\nfunction createEvlogMiddleware(getOptions: () => EvlogNestJSOptions) {\n return (req: Request, res: ServerResponse, next: () => void) => {\n const options = getOptions()\n const headers = extractSafeNodeHeaders(req.headers)\n const url = new URL(req.originalUrl || req.url || '/', 'http://localhost')\n\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: req.method || 'GET',\n path: url.pathname,\n requestId: headers['x-request-id'] || crypto.randomUUID(),\n headers,\n ...options,\n })\n\n if (skipped) {\n next()\n return\n }\n\n req.log = logger\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n storage.run(logger, () => next())\n }\n}\n\n/**\n * NestJS module for evlog wide event logging.\n *\n * Registers a global middleware that creates a request-scoped logger\n * for every incoming request. Use `useLogger()` to access it anywhere\n * in the call stack, or `req.log` directly in controllers.\n *\n * @example\n * ```ts\n * import { Module } from '@nestjs/common'\n * import { EvlogModule } from 'evlog/nestjs'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * @Module({\n * imports: [\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * exclude: ['/health'],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class EvlogModule implements NestModule {\n\n private static options: EvlogNestJSOptions = {}\n\n /**\n * Register evlog with static configuration.\n *\n * @example\n * ```ts\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => { ctx.event.region = process.env.FLY_REGION },\n * })\n * ```\n */\n static forRoot(options: EvlogNestJSOptions = {}): DynamicModule {\n EvlogModule.options = options\n return {\n module: EvlogModule,\n global: true,\n }\n }\n\n /**\n * Register evlog with async configuration (e.g. from `ConfigService`).\n *\n * @example\n * ```ts\n * EvlogModule.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (config: ConfigService) => ({\n * drain: createAxiomDrain({ token: config.get('AXIOM_TOKEN') }),\n * }),\n * })\n * ```\n */\n static forRootAsync(asyncOptions: EvlogModuleAsyncOptions): DynamicModule {\n return {\n module: EvlogModule,\n imports: asyncOptions.imports || [],\n providers: [\n {\n provide: 'EVLOG_OPTIONS',\n useFactory: async (...args: any[]) => {\n EvlogModule.options = await asyncOptions.useFactory(...args)\n return EvlogModule.options\n },\n inject: asyncOptions.inject || [],\n },\n ],\n global: true,\n }\n }\n\n configure(consumer: MiddlewareConsumer): void {\n consumer\n .apply(createEvlogMiddleware(() => EvlogModule.options))\n .forRoutes('*')\n }\n\n}\n"],"mappings":";;;AAQA,MAAM,EAAE,SAAS,cAAc,oBAC7B,qFACD;AA2BD,SAAS,sBAAsB,YAAsC;AACnE,SAAQ,KAAc,KAAqB,SAAqB;EAC9D,MAAM,UAAU,YAAY;EAC5B,MAAM,UAAU,uBAAuB,IAAI,QAAQ;EACnD,MAAM,MAAM,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,KAAK,mBAAmB;EAE1E,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI;GACV,WAAW,QAAQ,mBAAmB,OAAO,YAAY;GACzD;GACA,GAAG;GACJ,CAAC;AAEF,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,MAAI,MAAM;AAEV,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEF,UAAQ,IAAI,cAAc,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BrC,IAAa,cAAb,MAAa,YAAkC;CAE7C,OAAe,UAA8B,EAAE;;;;;;;;;;;;CAa/C,OAAO,QAAQ,UAA8B,EAAE,EAAiB;AAC9D,cAAY,UAAU;AACtB,SAAO;GACL,QAAQ;GACR,QAAQ;GACT;;;;;;;;;;;;;;;;CAiBH,OAAO,aAAa,cAAsD;AACxE,SAAO;GACL,QAAQ;GACR,SAAS,aAAa,WAAW,EAAE;GACnC,WAAW,CACT;IACE,SAAS;IACT,YAAY,OAAO,GAAG,SAAgB;AACpC,iBAAY,UAAU,MAAM,aAAa,WAAW,GAAG,KAAK;AAC5D,YAAO,YAAY;;IAErB,QAAQ,aAAa,UAAU,EAAE;IAClC,CACF;GACD,QAAQ;GACT;;CAGH,UAAU,UAAoC;AAC5C,WACG,MAAM,4BAA4B,YAAY,QAAQ,CAAC,CACvD,UAAU,IAAI"}
|
package/dist/next/client.d.mts
CHANGED
package/dist/next/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as EnvironmentContext, d as Log, g as RequestLogger, y as SamplingConfig } from "../types-
|
|
2
|
-
import { n as createError } from "../error-
|
|
3
|
-
import { t as _log } from "../logger-
|
|
4
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { a as EnvironmentContext, d as Log, g as RequestLogger, y as SamplingConfig } from "../types-CBpJBj_7.mjs";
|
|
2
|
+
import { n as createError } from "../error-BheHTFFB.mjs";
|
|
3
|
+
import { t as _log } from "../logger-BkXYNnHP.mjs";
|
|
4
|
+
import { t as BaseEvlogOptions } from "../middleware-B-4hPOVG.mjs";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
|
|
7
7
|
//#region src/next/types.d.ts
|
|
@@ -34,6 +34,12 @@ interface NextEvlogOptions extends BaseEvlogOptions {
|
|
|
34
34
|
* @default true
|
|
35
35
|
*/
|
|
36
36
|
stringify?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Suppress built-in console output.
|
|
39
|
+
* Events are still built, sampled, and passed to drains.
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
silent?: boolean;
|
|
37
43
|
}
|
|
38
44
|
interface EvlogMiddlewareConfig {
|
|
39
45
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/next/types.ts","../../src/next/storage.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"mappings":";;;;;;;UAGiB,gBAAA,SAAyB,gBAAA;;;;;EAKxC,OAAA;;;AALF;EAUE,GAAA,GAAM,OAAA,CAAQ,kBAAA;;;;;EAMd,MAAA;EAhBwD;;;;EAsBxD,OAAA;EAZM;;;EAiBN,QAAA,GAAW,cAAA;EAAX;;;;EAMA,SAAA;AAAA;AAAA,UAGe,qBAAA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/next/types.ts","../../src/next/storage.ts","../../src/next/middleware.ts","../../src/next/index.ts"],"mappings":";;;;;;;UAGiB,gBAAA,SAAyB,gBAAA;;;;;EAKxC,OAAA;;;AALF;EAUE,GAAA,GAAM,OAAA,CAAQ,kBAAA;;;;;EAMd,MAAA;EAhBwD;;;;EAsBxD,OAAA;EAZM;;;EAiBN,QAAA,GAAW,cAAA;EAAX;;;;EAMA,SAAA;EAOM;AAGR;;;;EAHE,MAAA;AAAA;AAAA,UAGe,qBAAA;;AC1BjB;;;ED+BE,OAAA;EC/BqF;;;;EDqCrF,OAAA;AAAA;;;;;;;;;;AAtDF;;;;;;;;iBCiBgB,SAAA,oBAA6B,MAAA,kBAAA,CAAA,GAA4B,aAAA,CAAc,CAAA;;;KCjBlF,WAAA;EACH,OAAA;IAAW,QAAA;EAAA;EACX,OAAA;IAAW,GAAA,CAAI,IAAA;EAAA;AAAA;AAAA,KAGZ,YAAA;EACH,OAAA;IAAW,GAAA,CAAI,IAAA,UAAc,KAAA;EAAA;AAAA;;;;;;;;;;;;;;iBAoBf,eAAA,CAAgB,MAAA,GAAS,qBAAA,IACzB,OAAA,EAAS,WAAA,KAAW,OAAA,CAAA,YAAA;;;;;AF3BpC;;;;;;;;;;;;;;;;;;;;;;AA2CA;;;;;iBGJgB,WAAA,CAAY,OAAA,GAAS,gBAAA;6DAW8jE,IAAA,EAAA,KAAA,KAAA,OAAA,SAAkC,IAAA,EAAA,KAAA,KAAA,OAAA,CAAA,OAAA,CAAA,OAAA"}
|
package/dist/next/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { filterSafeHeaders } from "../utils.mjs";
|
|
2
2
|
import { EvlogError, createError } from "../error.mjs";
|
|
3
|
-
import { createRequestLogger, initLogger, isEnabled, log as _log } from "../logger.mjs";
|
|
4
|
-
import { n as shouldLog, t as getServiceForPath } from "../routes-
|
|
3
|
+
import { createRequestLogger, getGlobalDrain, initLogger, isEnabled, log as _log } from "../logger.mjs";
|
|
4
|
+
import { n as shouldLog, t as getServiceForPath } from "../routes-CGPmbzCZ.mjs";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
//#region src/next/storage.ts
|
|
7
7
|
const evlogStorage = new AsyncLocalStorage();
|
|
@@ -41,8 +41,10 @@ function configureHandler(options) {
|
|
|
41
41
|
...options.env
|
|
42
42
|
},
|
|
43
43
|
pretty: options.pretty,
|
|
44
|
+
silent: options.silent,
|
|
44
45
|
sampling: options.sampling,
|
|
45
|
-
stringify: options.stringify
|
|
46
|
+
stringify: options.stringify,
|
|
47
|
+
_suppressDrainWarning: true
|
|
46
48
|
});
|
|
47
49
|
}
|
|
48
50
|
function extractRequestInfo(request) {
|
|
@@ -60,7 +62,8 @@ function extractRequestInfo(request) {
|
|
|
60
62
|
}
|
|
61
63
|
async function callEnrichAndDrain(emittedEvent, requestInfo, headers, responseStatus) {
|
|
62
64
|
if (!emittedEvent) return;
|
|
63
|
-
const { enrich
|
|
65
|
+
const { enrich } = state.options;
|
|
66
|
+
const drain = state.options.drain ?? getGlobalDrain();
|
|
64
67
|
const run = async () => {
|
|
65
68
|
if (enrich) {
|
|
66
69
|
const enrichCtx = {
|
|
@@ -137,7 +140,7 @@ function createWithEvlog(options) {
|
|
|
137
140
|
method,
|
|
138
141
|
path,
|
|
139
142
|
requestId
|
|
140
|
-
});
|
|
143
|
+
}, { _deferDrain: true });
|
|
141
144
|
const routeService = getServiceForPath(path, state.options.routes);
|
|
142
145
|
if (routeService) logger.set({ service: routeService });
|
|
143
146
|
if (isRequest) {
|