voltlog-io 1.0.1
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/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/index.d.mts +1142 -0
- package/dist/index.d.ts +1142 -0
- package/dist/index.js +1493 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1423 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +78 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1493 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
LogLevel: () => LogLevel,
|
|
34
|
+
LogLevelNameMap: () => LogLevelNameMap,
|
|
35
|
+
LogLevelValueMap: () => LogLevelValueMap,
|
|
36
|
+
aiEnrichmentMiddleware: () => aiEnrichmentMiddleware,
|
|
37
|
+
alertMiddleware: () => alertMiddleware,
|
|
38
|
+
batchTransport: () => batchTransport,
|
|
39
|
+
browserJsonStreamTransport: () => browserJsonStreamTransport,
|
|
40
|
+
consoleTransport: () => consoleTransport,
|
|
41
|
+
correlationIdMiddleware: () => correlationIdMiddleware,
|
|
42
|
+
createLogger: () => createLogger,
|
|
43
|
+
createMiddleware: () => createMiddleware,
|
|
44
|
+
createOpenAiErrorAnalyzer: () => createOpenAiErrorAnalyzer,
|
|
45
|
+
createTransport: () => createTransport,
|
|
46
|
+
datadogTransport: () => datadogTransport,
|
|
47
|
+
deduplicationMiddleware: () => deduplicationMiddleware,
|
|
48
|
+
discordTransport: () => discordTransport,
|
|
49
|
+
fileTransport: () => fileTransport,
|
|
50
|
+
heapUsageMiddleware: () => heapUsageMiddleware,
|
|
51
|
+
ipMiddleware: () => ipMiddleware,
|
|
52
|
+
jsonStreamTransport: () => jsonStreamTransport,
|
|
53
|
+
levelOverrideMiddleware: () => levelOverrideMiddleware,
|
|
54
|
+
lokiTransport: () => lokiTransport,
|
|
55
|
+
ocppMiddleware: () => ocppMiddleware,
|
|
56
|
+
prettyTransport: () => prettyTransport,
|
|
57
|
+
redactionMiddleware: () => redactionMiddleware,
|
|
58
|
+
redisTransport: () => redisTransport,
|
|
59
|
+
resolveLevel: () => resolveLevel,
|
|
60
|
+
samplingMiddleware: () => samplingMiddleware,
|
|
61
|
+
sentryTransport: () => sentryTransport,
|
|
62
|
+
shouldIncludeStack: () => shouldIncludeStack,
|
|
63
|
+
shouldLog: () => shouldLog,
|
|
64
|
+
slackTransport: () => slackTransport,
|
|
65
|
+
userAgentMiddleware: () => userAgentMiddleware,
|
|
66
|
+
webhookTransport: () => webhookTransport
|
|
67
|
+
});
|
|
68
|
+
module.exports = __toCommonJS(src_exports);
|
|
69
|
+
|
|
70
|
+
// src/core/types.ts
|
|
71
|
+
var LogLevel = {
|
|
72
|
+
TRACE: 10,
|
|
73
|
+
DEBUG: 20,
|
|
74
|
+
INFO: 30,
|
|
75
|
+
WARN: 40,
|
|
76
|
+
ERROR: 50,
|
|
77
|
+
FATAL: 60,
|
|
78
|
+
SILENT: Infinity
|
|
79
|
+
};
|
|
80
|
+
var LogLevelNameMap = Object.fromEntries(
|
|
81
|
+
Object.entries(LogLevel).map(([k, v]) => [k.toLowerCase(), v])
|
|
82
|
+
);
|
|
83
|
+
var LogLevelValueMap = Object.fromEntries(
|
|
84
|
+
Object.entries(LogLevel).filter(([, v]) => Number.isFinite(v)).map(([k, v]) => [v, k])
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// src/core/levels.ts
|
|
88
|
+
function resolveLevel(level) {
|
|
89
|
+
const n = LogLevelNameMap[level.toLowerCase()];
|
|
90
|
+
return n !== void 0 ? n : LogLevel.INFO;
|
|
91
|
+
}
|
|
92
|
+
function shouldLog(entryLevel, filterLevel) {
|
|
93
|
+
return entryLevel >= filterLevel;
|
|
94
|
+
}
|
|
95
|
+
function shouldIncludeStack(entryLevel, includeStack) {
|
|
96
|
+
if (typeof includeStack === "boolean") return includeStack;
|
|
97
|
+
return entryLevel >= resolveLevel(includeStack);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/core/logger.ts
|
|
101
|
+
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
102
|
+
|
|
103
|
+
// src/core/pipeline.ts
|
|
104
|
+
function composeMiddleware(middleware, final) {
|
|
105
|
+
if (middleware.length === 0) return final;
|
|
106
|
+
return (entry) => {
|
|
107
|
+
let index = 0;
|
|
108
|
+
const next = (e) => {
|
|
109
|
+
if (index < middleware.length) {
|
|
110
|
+
const mw = middleware[index++];
|
|
111
|
+
mw(e, next);
|
|
112
|
+
} else {
|
|
113
|
+
final(e);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
next(entry);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function fanOutToTransports(entry, transports, loggerLevel) {
|
|
120
|
+
for (const t of transports) {
|
|
121
|
+
const tLevel = t.level ? resolveLevel(t.level) : loggerLevel;
|
|
122
|
+
if (!shouldLog(entry.level, tLevel)) continue;
|
|
123
|
+
try {
|
|
124
|
+
const result = t.write(entry);
|
|
125
|
+
if (result && typeof result.catch === "function") {
|
|
126
|
+
result.catch(() => {
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/core/logger.ts
|
|
135
|
+
var LoggerImpl = class {
|
|
136
|
+
_level;
|
|
137
|
+
_transports;
|
|
138
|
+
_middlewareList;
|
|
139
|
+
_pipeline;
|
|
140
|
+
_context;
|
|
141
|
+
_includeStack;
|
|
142
|
+
_timestampFn;
|
|
143
|
+
constructor(options = {}) {
|
|
144
|
+
this._level = resolveLevel(options.level ?? "INFO");
|
|
145
|
+
this._transports = [...options.transports ?? []];
|
|
146
|
+
this._middlewareList = [...options.middleware ?? []];
|
|
147
|
+
this._context = options.context ? { ...options.context } : {};
|
|
148
|
+
this._includeStack = options.includeStack ?? "ERROR";
|
|
149
|
+
this._timestampFn = options.timestamp ?? Date.now;
|
|
150
|
+
this._pipeline = this._buildPipeline();
|
|
151
|
+
}
|
|
152
|
+
// ─── Log Methods ────────────────────────────────────────────
|
|
153
|
+
trace(message, meta) {
|
|
154
|
+
this._log(10, "TRACE", message, meta);
|
|
155
|
+
}
|
|
156
|
+
debug(message, meta) {
|
|
157
|
+
this._log(20, "DEBUG", message, meta);
|
|
158
|
+
}
|
|
159
|
+
info(message, meta) {
|
|
160
|
+
this._log(30, "INFO", message, meta);
|
|
161
|
+
}
|
|
162
|
+
warn(message, meta) {
|
|
163
|
+
this._log(40, "WARN", message, meta);
|
|
164
|
+
}
|
|
165
|
+
error(message, metaOrError, error) {
|
|
166
|
+
if (metaOrError instanceof Error) {
|
|
167
|
+
this._log(50, "ERROR", message, void 0, metaOrError);
|
|
168
|
+
} else {
|
|
169
|
+
this._log(50, "ERROR", message, metaOrError, error);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
fatal(message, metaOrError, error) {
|
|
173
|
+
if (metaOrError instanceof Error) {
|
|
174
|
+
this._log(60, "FATAL", message, void 0, metaOrError);
|
|
175
|
+
} else {
|
|
176
|
+
this._log(60, "FATAL", message, metaOrError, error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// ─── Child Logger ───────────────────────────────────────────
|
|
180
|
+
child(context) {
|
|
181
|
+
return new ChildLoggerImpl(this, { ...this._context, ...context });
|
|
182
|
+
}
|
|
183
|
+
// ─── Dynamic Configuration ─────────────────────────────────
|
|
184
|
+
addTransport(transport) {
|
|
185
|
+
this._transports.push(transport);
|
|
186
|
+
}
|
|
187
|
+
removeTransport(name) {
|
|
188
|
+
this._transports = this._transports.filter((t) => t.name !== name);
|
|
189
|
+
}
|
|
190
|
+
addMiddleware(middleware) {
|
|
191
|
+
this._middlewareList.push(middleware);
|
|
192
|
+
this._pipeline = this._buildPipeline();
|
|
193
|
+
}
|
|
194
|
+
// ─── Lifecycle ──────────────────────────────────────────────
|
|
195
|
+
async flush() {
|
|
196
|
+
await Promise.all(this._transports.map((t) => t.flush?.()).filter(Boolean));
|
|
197
|
+
}
|
|
198
|
+
async close() {
|
|
199
|
+
await this.flush();
|
|
200
|
+
await Promise.all(this._transports.map((t) => t.close?.()).filter(Boolean));
|
|
201
|
+
}
|
|
202
|
+
// ─── Internal ───────────────────────────────────────────────
|
|
203
|
+
/** @internal */
|
|
204
|
+
_log(level, levelName, message, meta, error) {
|
|
205
|
+
this._logWithContext(level, levelName, message, this._context, meta, error);
|
|
206
|
+
}
|
|
207
|
+
/** @internal — used by child loggers to inject bound context */
|
|
208
|
+
_logWithContext(level, levelName, message, context, meta, error) {
|
|
209
|
+
if (!shouldLog(level, this._level)) return;
|
|
210
|
+
const entry = {
|
|
211
|
+
id: (0, import_cuid2.createId)(),
|
|
212
|
+
level,
|
|
213
|
+
levelName,
|
|
214
|
+
message,
|
|
215
|
+
timestamp: this._timestampFn(),
|
|
216
|
+
meta: meta ?? {},
|
|
217
|
+
context: Object.keys(context).length > 0 ? context : void 0
|
|
218
|
+
};
|
|
219
|
+
if (error) {
|
|
220
|
+
const logError = {
|
|
221
|
+
message: error.message,
|
|
222
|
+
name: error.name,
|
|
223
|
+
code: error.code
|
|
224
|
+
};
|
|
225
|
+
if (shouldIncludeStack(level, this._includeStack)) {
|
|
226
|
+
logError.stack = error.stack;
|
|
227
|
+
}
|
|
228
|
+
entry.error = logError;
|
|
229
|
+
}
|
|
230
|
+
this._pipeline(entry);
|
|
231
|
+
}
|
|
232
|
+
_buildPipeline() {
|
|
233
|
+
return composeMiddleware(this._middlewareList, (entry) => {
|
|
234
|
+
fanOutToTransports(entry, this._transports, this._level);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
var ChildLoggerImpl = class _ChildLoggerImpl {
|
|
239
|
+
constructor(_parent, _context) {
|
|
240
|
+
this._parent = _parent;
|
|
241
|
+
this._context = _context;
|
|
242
|
+
}
|
|
243
|
+
trace(message, meta) {
|
|
244
|
+
this._parent._logWithContext(10, "TRACE", message, this._context, meta);
|
|
245
|
+
}
|
|
246
|
+
debug(message, meta) {
|
|
247
|
+
this._parent._logWithContext(20, "DEBUG", message, this._context, meta);
|
|
248
|
+
}
|
|
249
|
+
info(message, meta) {
|
|
250
|
+
this._parent._logWithContext(30, "INFO", message, this._context, meta);
|
|
251
|
+
}
|
|
252
|
+
warn(message, meta) {
|
|
253
|
+
this._parent._logWithContext(40, "WARN", message, this._context, meta);
|
|
254
|
+
}
|
|
255
|
+
error(message, metaOrError, error) {
|
|
256
|
+
if (metaOrError instanceof Error) {
|
|
257
|
+
this._parent._logWithContext(
|
|
258
|
+
50,
|
|
259
|
+
"ERROR",
|
|
260
|
+
message,
|
|
261
|
+
this._context,
|
|
262
|
+
void 0,
|
|
263
|
+
metaOrError
|
|
264
|
+
);
|
|
265
|
+
} else {
|
|
266
|
+
this._parent._logWithContext(
|
|
267
|
+
50,
|
|
268
|
+
"ERROR",
|
|
269
|
+
message,
|
|
270
|
+
this._context,
|
|
271
|
+
metaOrError,
|
|
272
|
+
error
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
fatal(message, metaOrError, error) {
|
|
277
|
+
if (metaOrError instanceof Error) {
|
|
278
|
+
this._parent._logWithContext(
|
|
279
|
+
60,
|
|
280
|
+
"FATAL",
|
|
281
|
+
message,
|
|
282
|
+
this._context,
|
|
283
|
+
void 0,
|
|
284
|
+
metaOrError
|
|
285
|
+
);
|
|
286
|
+
} else {
|
|
287
|
+
this._parent._logWithContext(
|
|
288
|
+
60,
|
|
289
|
+
"FATAL",
|
|
290
|
+
message,
|
|
291
|
+
this._context,
|
|
292
|
+
metaOrError,
|
|
293
|
+
error
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
child(context) {
|
|
298
|
+
return new _ChildLoggerImpl(this._parent, {
|
|
299
|
+
...this._context,
|
|
300
|
+
...context
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
addTransport(transport) {
|
|
304
|
+
this._parent.addTransport(transport);
|
|
305
|
+
}
|
|
306
|
+
removeTransport(name) {
|
|
307
|
+
this._parent.removeTransport(name);
|
|
308
|
+
}
|
|
309
|
+
addMiddleware(middleware) {
|
|
310
|
+
this._parent.addMiddleware(middleware);
|
|
311
|
+
}
|
|
312
|
+
flush() {
|
|
313
|
+
return this._parent.flush();
|
|
314
|
+
}
|
|
315
|
+
close() {
|
|
316
|
+
return this._parent.close();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function createLogger(options) {
|
|
320
|
+
return new LoggerImpl(options);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/middleware/ai-enrichment.ts
|
|
324
|
+
function aiEnrichmentMiddleware(options) {
|
|
325
|
+
const minLevel = resolveLevel(options.level ?? "ERROR");
|
|
326
|
+
const timeoutMs = options.timeout ?? 2e3;
|
|
327
|
+
const swallow = options.swallowErrors ?? true;
|
|
328
|
+
const fieldName = options.targetField ?? "ai_analysis";
|
|
329
|
+
return async (entry, next) => {
|
|
330
|
+
if (entry.level < minLevel) {
|
|
331
|
+
next(entry);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
const analysisPromise = options.analyzer(entry);
|
|
336
|
+
const timeoutPromise = new Promise(
|
|
337
|
+
(_, reject) => setTimeout(() => reject(new Error("AI Analysis Timeout")), timeoutMs)
|
|
338
|
+
);
|
|
339
|
+
const result = await Promise.race([analysisPromise, timeoutPromise]);
|
|
340
|
+
if (result) {
|
|
341
|
+
entry.meta = {
|
|
342
|
+
...entry.meta,
|
|
343
|
+
[fieldName]: result
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
} catch (err) {
|
|
347
|
+
if (!swallow) {
|
|
348
|
+
throw err;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
next(entry);
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function createOpenAiErrorAnalyzer(apiKey, model = "gpt-3.5-turbo", systemPrompt = "You are a log analyzer. Explain this error briefly and suggest a fix in 1 sentence.") {
|
|
355
|
+
return async (entry) => {
|
|
356
|
+
try {
|
|
357
|
+
const response = await fetch(
|
|
358
|
+
"https://api.openai.com/v1/chat/completions",
|
|
359
|
+
{
|
|
360
|
+
method: "POST",
|
|
361
|
+
headers: {
|
|
362
|
+
"Content-Type": "application/json",
|
|
363
|
+
Authorization: `Bearer ${apiKey}`
|
|
364
|
+
},
|
|
365
|
+
body: JSON.stringify({
|
|
366
|
+
model,
|
|
367
|
+
messages: [
|
|
368
|
+
{ role: "system", content: systemPrompt },
|
|
369
|
+
{
|
|
370
|
+
role: "user",
|
|
371
|
+
content: `Error Message: ${entry.message}
|
|
372
|
+
Context: ${JSON.stringify(entry.meta)}`
|
|
373
|
+
}
|
|
374
|
+
],
|
|
375
|
+
max_tokens: 150
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
if (!response.ok) return null;
|
|
380
|
+
const data = await response.json();
|
|
381
|
+
return data.choices?.[0]?.message?.content ?? null;
|
|
382
|
+
} catch {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// src/middleware/alert.ts
|
|
389
|
+
function alertMiddleware(rules) {
|
|
390
|
+
const states = /* @__PURE__ */ new Map();
|
|
391
|
+
for (const rule of rules) {
|
|
392
|
+
states.set(rule.name, { entries: [], lastFired: -Infinity });
|
|
393
|
+
}
|
|
394
|
+
return (entry, next) => {
|
|
395
|
+
const now = entry.timestamp;
|
|
396
|
+
for (const rule of rules) {
|
|
397
|
+
if (!rule.when(entry)) continue;
|
|
398
|
+
const state = states.get(rule.name);
|
|
399
|
+
const windowMs = rule.windowMs ?? Infinity;
|
|
400
|
+
const threshold = rule.threshold ?? 1;
|
|
401
|
+
const cooldownMs = rule.cooldownMs ?? 0;
|
|
402
|
+
if (Number.isFinite(windowMs)) {
|
|
403
|
+
state.entries = state.entries.filter(
|
|
404
|
+
(e) => now - e.timestamp < windowMs
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
state.entries.push(entry);
|
|
408
|
+
if (state.entries.length >= threshold && now - state.lastFired >= cooldownMs) {
|
|
409
|
+
const alertEntries = [...state.entries];
|
|
410
|
+
state.entries = [];
|
|
411
|
+
state.lastFired = now;
|
|
412
|
+
try {
|
|
413
|
+
const result = rule.onAlert(alertEntries);
|
|
414
|
+
if (result && typeof result.catch === "function") {
|
|
415
|
+
result.catch(() => {
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
} catch {
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
next(entry);
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/middleware/correlation-id.ts
|
|
427
|
+
var import_cuid22 = require("@paralleldrive/cuid2");
|
|
428
|
+
function correlationIdMiddleware(options = {}) {
|
|
429
|
+
const header = options.header ?? "x-correlation-id";
|
|
430
|
+
const generate = options.generator ?? import_cuid22.createId;
|
|
431
|
+
return (entry, next) => {
|
|
432
|
+
if (entry.correlationId) {
|
|
433
|
+
return next(entry);
|
|
434
|
+
}
|
|
435
|
+
const meta = entry.meta;
|
|
436
|
+
let id = meta.correlationId || meta.traceId || meta[header];
|
|
437
|
+
if (!id) {
|
|
438
|
+
id = generate();
|
|
439
|
+
}
|
|
440
|
+
entry.correlationId = id;
|
|
441
|
+
if (!meta.correlationId) {
|
|
442
|
+
entry.meta.correlationId = id;
|
|
443
|
+
}
|
|
444
|
+
next(entry);
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/middleware/create-middleware.ts
|
|
449
|
+
function createMiddleware(fn) {
|
|
450
|
+
return fn;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/middleware/deduplication.ts
|
|
454
|
+
function deduplicationMiddleware(options = {}) {
|
|
455
|
+
const windowMs = options.windowMs ?? 1e3;
|
|
456
|
+
const keyFn = options.keyFn ?? ((e) => `${e.level}:${e.message}:${e.error?.message ?? ""}`);
|
|
457
|
+
const buffer = /* @__PURE__ */ new Map();
|
|
458
|
+
return (entry, next) => {
|
|
459
|
+
const key = keyFn(entry);
|
|
460
|
+
if (buffer.has(key)) {
|
|
461
|
+
const state = buffer.get(key);
|
|
462
|
+
state.count++;
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const timer = setTimeout(() => {
|
|
466
|
+
const state = buffer.get(key);
|
|
467
|
+
if (state) {
|
|
468
|
+
buffer.delete(key);
|
|
469
|
+
if (state.count > 1) {
|
|
470
|
+
state.entry.meta = {
|
|
471
|
+
...state.entry.meta,
|
|
472
|
+
duplicateCount: state.count
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
next(state.entry);
|
|
476
|
+
}
|
|
477
|
+
}, windowMs);
|
|
478
|
+
buffer.set(key, {
|
|
479
|
+
entry,
|
|
480
|
+
count: 1,
|
|
481
|
+
timer
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/middleware/heap-usage.ts
|
|
487
|
+
function heapUsageMiddleware(options = {}) {
|
|
488
|
+
const fieldName = options.fieldName ?? "memory";
|
|
489
|
+
return (entry, next) => {
|
|
490
|
+
if (typeof process !== "undefined" && process.memoryUsage) {
|
|
491
|
+
const memory = process.memoryUsage();
|
|
492
|
+
entry.meta = {
|
|
493
|
+
...entry.meta,
|
|
494
|
+
[fieldName]: {
|
|
495
|
+
rss: memory.rss,
|
|
496
|
+
heapTotal: memory.heapTotal,
|
|
497
|
+
heapUsed: memory.heapUsed
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
next(entry);
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/middleware/ip.ts
|
|
506
|
+
function ipMiddleware(options = {}) {
|
|
507
|
+
const targetField = options.fieldName ?? "ip";
|
|
508
|
+
const keysToCheck = options.headerKeys ?? [
|
|
509
|
+
"x-forwarded-for",
|
|
510
|
+
"x-real-ip",
|
|
511
|
+
"req.ip",
|
|
512
|
+
"ip",
|
|
513
|
+
"x-client-ip"
|
|
514
|
+
];
|
|
515
|
+
return (entry, next) => {
|
|
516
|
+
const meta = entry.meta;
|
|
517
|
+
const headers = meta.headers || {};
|
|
518
|
+
const req = meta.req || {};
|
|
519
|
+
let foundIp;
|
|
520
|
+
for (const key of keysToCheck) {
|
|
521
|
+
if (typeof meta[key] === "string") {
|
|
522
|
+
foundIp = meta[key];
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
if (typeof headers[key] === "string") {
|
|
526
|
+
foundIp = headers[key];
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
if (typeof req[key] === "string") {
|
|
530
|
+
foundIp = req[key];
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
if (key === "req.ip" && typeof req.ip === "string") {
|
|
534
|
+
foundIp = req.ip;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (foundIp) {
|
|
539
|
+
const firstIp = typeof foundIp === "string" ? foundIp.split(",")[0].trim() : String(foundIp);
|
|
540
|
+
entry.meta = {
|
|
541
|
+
...entry.meta,
|
|
542
|
+
[targetField]: firstIp
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
next(entry);
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// src/middleware/level-override.ts
|
|
550
|
+
function levelOverrideMiddleware(options = {}) {
|
|
551
|
+
const key = options.key ?? "x-log-level";
|
|
552
|
+
const cleanup = options.cleanup ?? true;
|
|
553
|
+
return (entry, next) => {
|
|
554
|
+
const meta = entry.meta;
|
|
555
|
+
const context = entry.context;
|
|
556
|
+
const levelName = meta[key] || context?.[key] || meta.headers?.[key];
|
|
557
|
+
if (levelName && typeof levelName === "string") {
|
|
558
|
+
const upperName = levelName.toUpperCase();
|
|
559
|
+
if (LogLevel[upperName]) {
|
|
560
|
+
entry.level = LogLevel[upperName];
|
|
561
|
+
entry.levelName = upperName;
|
|
562
|
+
if (cleanup) {
|
|
563
|
+
delete meta[key];
|
|
564
|
+
if (meta.headers) {
|
|
565
|
+
delete meta.headers[key];
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
next(entry);
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// src/middleware/ocpp.ts
|
|
575
|
+
function ocppMiddleware(options = {}) {
|
|
576
|
+
const autoPayloadSize = options.autoPayloadSize ?? true;
|
|
577
|
+
const propagateCorrelationId = options.propagateCorrelationId ?? true;
|
|
578
|
+
return (entry, next) => {
|
|
579
|
+
const enriched = { ...entry, meta: { ...entry.meta } };
|
|
580
|
+
if (autoPayloadSize && enriched.meta.payloadSize === void 0 && enriched.meta.action) {
|
|
581
|
+
try {
|
|
582
|
+
enriched.meta.payloadSize = JSON.stringify(enriched.meta).length;
|
|
583
|
+
} catch {
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (propagateCorrelationId && enriched.meta.correlationId && !enriched.correlationId) {
|
|
587
|
+
enriched.correlationId = enriched.meta.correlationId;
|
|
588
|
+
}
|
|
589
|
+
next(enriched);
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// src/middleware/redaction.ts
|
|
594
|
+
var DEFAULT_REDACT_VALUE = "[REDACTED]";
|
|
595
|
+
function redactionMiddleware(options) {
|
|
596
|
+
const paths = new Set(options.paths.map((p) => p.toLowerCase()));
|
|
597
|
+
const replacement = options.replacement ?? DEFAULT_REDACT_VALUE;
|
|
598
|
+
const deep = options.deep ?? true;
|
|
599
|
+
function redactObject(obj) {
|
|
600
|
+
const result = {};
|
|
601
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
602
|
+
if (paths.has(key.toLowerCase())) {
|
|
603
|
+
result[key] = replacement;
|
|
604
|
+
} else if (deep && value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
605
|
+
result[key] = redactObject(value);
|
|
606
|
+
} else {
|
|
607
|
+
result[key] = value;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return result;
|
|
611
|
+
}
|
|
612
|
+
return (entry, next) => {
|
|
613
|
+
const redacted = { ...entry };
|
|
614
|
+
if (entry.meta && typeof entry.meta === "object") {
|
|
615
|
+
redacted.meta = redactObject(
|
|
616
|
+
entry.meta
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
if (entry.context && typeof entry.context === "object") {
|
|
620
|
+
redacted.context = redactObject(entry.context);
|
|
621
|
+
}
|
|
622
|
+
next(redacted);
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/middleware/sampling.ts
|
|
627
|
+
function samplingMiddleware(options = {}) {
|
|
628
|
+
const keyFn = options.keyFn ?? ((entry) => entry.message);
|
|
629
|
+
const maxPerWindow = options.maxPerWindow ?? 100;
|
|
630
|
+
const windowMs = options.windowMs ?? 6e4;
|
|
631
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
632
|
+
const priorityLevel = options.priorityLevel ?? 40;
|
|
633
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
634
|
+
return (entry, next) => {
|
|
635
|
+
if (entry.level >= priorityLevel) {
|
|
636
|
+
return next(entry);
|
|
637
|
+
}
|
|
638
|
+
if (sampleRate < 1 && Math.random() > sampleRate) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
const key = keyFn(entry);
|
|
642
|
+
const now = entry.timestamp;
|
|
643
|
+
let bucket = buckets.get(key);
|
|
644
|
+
if (!bucket || now - bucket.windowStart >= windowMs) {
|
|
645
|
+
bucket = { count: 0, windowStart: now };
|
|
646
|
+
buckets.set(key, bucket);
|
|
647
|
+
}
|
|
648
|
+
if (bucket.count < maxPerWindow) {
|
|
649
|
+
bucket.count++;
|
|
650
|
+
next(entry);
|
|
651
|
+
}
|
|
652
|
+
if (buckets.size > 2e3) {
|
|
653
|
+
const expireBefore = now - windowMs * 2;
|
|
654
|
+
for (const [k, b] of buckets) {
|
|
655
|
+
if (b.windowStart < expireBefore) {
|
|
656
|
+
buckets.delete(k);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/middleware/user-agent.ts
|
|
664
|
+
function userAgentMiddleware(options = {}) {
|
|
665
|
+
const sourceField = options.sourceField;
|
|
666
|
+
const targetField = options.targetField ?? "client";
|
|
667
|
+
return (entry, next) => {
|
|
668
|
+
const meta = entry.meta;
|
|
669
|
+
const context = entry.context;
|
|
670
|
+
const ua = (sourceField ? meta[sourceField] : void 0) || meta.userAgent || meta["user-agent"] || context?.userAgent || context?.["user-agent"];
|
|
671
|
+
if (ua) {
|
|
672
|
+
const info = parseUserAgent(ua);
|
|
673
|
+
entry.meta = {
|
|
674
|
+
...entry.meta,
|
|
675
|
+
[targetField]: info
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
next(entry);
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function parseUserAgent(ua) {
|
|
682
|
+
const browser = /(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i.exec(ua) || [];
|
|
683
|
+
let name = browser[1] ? browser[1].toLowerCase() : "unknown";
|
|
684
|
+
let version = browser[2] || "unknown";
|
|
685
|
+
if (/trident/i.test(name)) {
|
|
686
|
+
name = "ie";
|
|
687
|
+
} else if (name === "chrome") {
|
|
688
|
+
const edge = /edg(e)?\/(\d+)/i.exec(ua);
|
|
689
|
+
if (edge) {
|
|
690
|
+
name = "edge";
|
|
691
|
+
version = edge[2];
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
const osResult = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.exec(
|
|
695
|
+
ua
|
|
696
|
+
);
|
|
697
|
+
const os = osResult ? osResult[0].toLowerCase() : "desktop";
|
|
698
|
+
return { browser: name, version, os };
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// src/transports/batch.ts
|
|
702
|
+
function batchTransport(inner, options = {}) {
|
|
703
|
+
const batchSize = options.batchSize ?? 100;
|
|
704
|
+
const flushIntervalMs = options.flushIntervalMs ?? 5e3;
|
|
705
|
+
let buffer = [];
|
|
706
|
+
let flushTimer = null;
|
|
707
|
+
function scheduleFlush() {
|
|
708
|
+
if (flushTimer) return;
|
|
709
|
+
flushTimer = setTimeout(() => {
|
|
710
|
+
flushTimer = null;
|
|
711
|
+
doFlush();
|
|
712
|
+
}, flushIntervalMs);
|
|
713
|
+
}
|
|
714
|
+
function doFlush() {
|
|
715
|
+
if (buffer.length === 0) return;
|
|
716
|
+
const batch = buffer;
|
|
717
|
+
buffer = [];
|
|
718
|
+
for (const entry of batch) {
|
|
719
|
+
try {
|
|
720
|
+
const result = inner.write(entry);
|
|
721
|
+
if (result && typeof result.catch === "function") {
|
|
722
|
+
result.catch(() => {
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
} catch {
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
name: `batch(${inner.name})`,
|
|
731
|
+
level: inner.level,
|
|
732
|
+
write(entry) {
|
|
733
|
+
buffer.push(entry);
|
|
734
|
+
if (buffer.length >= batchSize) {
|
|
735
|
+
doFlush();
|
|
736
|
+
} else {
|
|
737
|
+
scheduleFlush();
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
async flush() {
|
|
741
|
+
if (flushTimer) {
|
|
742
|
+
clearTimeout(flushTimer);
|
|
743
|
+
flushTimer = null;
|
|
744
|
+
}
|
|
745
|
+
doFlush();
|
|
746
|
+
await inner.flush?.();
|
|
747
|
+
},
|
|
748
|
+
async close() {
|
|
749
|
+
await this.flush?.();
|
|
750
|
+
await inner.close?.();
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// src/transports/browser-json-stream.ts
|
|
756
|
+
function browserJsonStreamTransport(options) {
|
|
757
|
+
const stream = options.stream;
|
|
758
|
+
const writer = stream.getWriter();
|
|
759
|
+
const serialize = options.serializer ?? ((entry) => `${JSON.stringify(entry)}
|
|
760
|
+
`);
|
|
761
|
+
return {
|
|
762
|
+
name: "browser-stream",
|
|
763
|
+
level: options.level,
|
|
764
|
+
async write(entry) {
|
|
765
|
+
try {
|
|
766
|
+
const data = serialize(entry);
|
|
767
|
+
await writer.ready;
|
|
768
|
+
await writer.write(data);
|
|
769
|
+
} catch (err) {
|
|
770
|
+
console.error("[voltlog] Failed to write to browser stream", err);
|
|
771
|
+
}
|
|
772
|
+
},
|
|
773
|
+
async close() {
|
|
774
|
+
try {
|
|
775
|
+
await writer.close();
|
|
776
|
+
} catch (_err) {
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// src/transports/console.ts
|
|
783
|
+
function consoleTransport(options = {}) {
|
|
784
|
+
const useConsoleLevels = options.useConsoleLevels ?? true;
|
|
785
|
+
const formatter = options.formatter ?? ((entry) => JSON.stringify(entry));
|
|
786
|
+
return {
|
|
787
|
+
name: "console",
|
|
788
|
+
level: options.level,
|
|
789
|
+
write(entry) {
|
|
790
|
+
const output = formatter(entry);
|
|
791
|
+
if (!useConsoleLevels) {
|
|
792
|
+
console.log(output);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (entry.level >= LogLevel.FATAL) {
|
|
796
|
+
console.error(output);
|
|
797
|
+
} else if (entry.level >= LogLevel.ERROR) {
|
|
798
|
+
console.error(output);
|
|
799
|
+
} else if (entry.level >= LogLevel.WARN) {
|
|
800
|
+
console.warn(output);
|
|
801
|
+
} else if (entry.level >= LogLevel.INFO) {
|
|
802
|
+
console.info(output);
|
|
803
|
+
} else if (entry.level >= LogLevel.DEBUG) {
|
|
804
|
+
console.debug(output);
|
|
805
|
+
} else {
|
|
806
|
+
console.log(output);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// src/transports/create-transport.ts
|
|
813
|
+
function createTransport(name, write, options = {}) {
|
|
814
|
+
return {
|
|
815
|
+
name,
|
|
816
|
+
write,
|
|
817
|
+
...options
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// src/transports/datadog.ts
|
|
822
|
+
function datadogTransport(options) {
|
|
823
|
+
const {
|
|
824
|
+
apiKey,
|
|
825
|
+
site = "datadoghq.com",
|
|
826
|
+
service,
|
|
827
|
+
ddSource = "nodejs",
|
|
828
|
+
hostname,
|
|
829
|
+
tags,
|
|
830
|
+
level
|
|
831
|
+
} = options;
|
|
832
|
+
const url = `https://http-intake.logs.${site}/api/v2/logs`;
|
|
833
|
+
return {
|
|
834
|
+
name: "datadog",
|
|
835
|
+
level,
|
|
836
|
+
async write(entry) {
|
|
837
|
+
const payload = {
|
|
838
|
+
ddsource: ddSource,
|
|
839
|
+
ddtags: tags,
|
|
840
|
+
hostname,
|
|
841
|
+
service,
|
|
842
|
+
message: entry.message,
|
|
843
|
+
status: entry.levelName.toLowerCase(),
|
|
844
|
+
// Datadog uses lowercase status
|
|
845
|
+
...entry.meta,
|
|
846
|
+
timestamp: entry.timestamp
|
|
847
|
+
// Datadog auto-parses this
|
|
848
|
+
};
|
|
849
|
+
try {
|
|
850
|
+
await fetch(url, {
|
|
851
|
+
method: "POST",
|
|
852
|
+
headers: {
|
|
853
|
+
"Content-Type": "application/json",
|
|
854
|
+
"DD-API-KEY": apiKey
|
|
855
|
+
},
|
|
856
|
+
body: JSON.stringify(payload)
|
|
857
|
+
});
|
|
858
|
+
} catch (err) {
|
|
859
|
+
console.error("[voltlog] Datadog push failed", err);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// src/transports/discord.ts
|
|
866
|
+
function discordTransport(options) {
|
|
867
|
+
const { webhookUrl, username, avatarUrl, level = "ERROR" } = options;
|
|
868
|
+
return {
|
|
869
|
+
name: "discord",
|
|
870
|
+
level,
|
|
871
|
+
async write(entry) {
|
|
872
|
+
try {
|
|
873
|
+
await fetch(webhookUrl, {
|
|
874
|
+
method: "POST",
|
|
875
|
+
headers: { "Content-Type": "application/json" },
|
|
876
|
+
body: JSON.stringify(
|
|
877
|
+
formatDiscordPayload(entry, username, avatarUrl)
|
|
878
|
+
)
|
|
879
|
+
});
|
|
880
|
+
} catch (_err) {
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function formatDiscordPayload(entry, username, avatar_url) {
|
|
886
|
+
const color = getLevelColor(entry.level);
|
|
887
|
+
return {
|
|
888
|
+
username: username || "VoltLog",
|
|
889
|
+
avatar_url,
|
|
890
|
+
embeds: [
|
|
891
|
+
{
|
|
892
|
+
title: `${entry.levelName} - ${entry.message}`,
|
|
893
|
+
color,
|
|
894
|
+
timestamp: new Date(entry.timestamp).toISOString(),
|
|
895
|
+
fields: [
|
|
896
|
+
{
|
|
897
|
+
name: "Meta",
|
|
898
|
+
value: `\`\`\`json
|
|
899
|
+
${JSON.stringify(entry.meta, null, 2).slice(
|
|
900
|
+
0,
|
|
901
|
+
1e3
|
|
902
|
+
)}
|
|
903
|
+
\`\`\``
|
|
904
|
+
},
|
|
905
|
+
entry.error?.stack ? {
|
|
906
|
+
name: "Stack",
|
|
907
|
+
value: `\`\`\`js
|
|
908
|
+
${entry.error.stack.slice(0, 1e3)}
|
|
909
|
+
\`\`\``
|
|
910
|
+
} : null
|
|
911
|
+
].filter(Boolean)
|
|
912
|
+
}
|
|
913
|
+
]
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
function getLevelColor(level) {
|
|
917
|
+
if (level >= 50) return 15158332;
|
|
918
|
+
if (level >= 40) return 16776960;
|
|
919
|
+
if (level >= 30) return 3447003;
|
|
920
|
+
return 9807270;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/transports/file.ts
|
|
924
|
+
var import_node_fs = __toESM(require("fs"));
|
|
925
|
+
var import_node_path = __toESM(require("path"));
|
|
926
|
+
function fileTransport(options) {
|
|
927
|
+
const { dir, level } = options;
|
|
928
|
+
const filenamePattern = options.filename ?? "app-%DATE%.log";
|
|
929
|
+
let currentStream = null;
|
|
930
|
+
let currentPath = "";
|
|
931
|
+
try {
|
|
932
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
933
|
+
} catch (err) {
|
|
934
|
+
console.error(`[voltlog] Failed to create log directory: ${dir}`, err);
|
|
935
|
+
}
|
|
936
|
+
function getPath() {
|
|
937
|
+
const now = /* @__PURE__ */ new Date();
|
|
938
|
+
const dateStr = now.toISOString().split("T")[0];
|
|
939
|
+
const filename = filenamePattern.replace("%DATE%", dateStr);
|
|
940
|
+
return import_node_path.default.join(dir, filename);
|
|
941
|
+
}
|
|
942
|
+
function rotate() {
|
|
943
|
+
const newPath = getPath();
|
|
944
|
+
if (newPath !== currentPath) {
|
|
945
|
+
if (currentStream) {
|
|
946
|
+
currentStream.end();
|
|
947
|
+
}
|
|
948
|
+
currentPath = newPath;
|
|
949
|
+
currentStream = import_node_fs.default.createWriteStream(newPath, { flags: "a" });
|
|
950
|
+
currentStream.on("error", (err) => {
|
|
951
|
+
console.error(`[voltlog] File write error to ${newPath}:`, err);
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
rotate();
|
|
956
|
+
return {
|
|
957
|
+
name: "file",
|
|
958
|
+
level,
|
|
959
|
+
write(entry) {
|
|
960
|
+
rotate();
|
|
961
|
+
if (currentStream && !currentStream.writableEnded) {
|
|
962
|
+
const line = `${JSON.stringify(entry)}
|
|
963
|
+
`;
|
|
964
|
+
currentStream.write(line);
|
|
965
|
+
}
|
|
966
|
+
},
|
|
967
|
+
async flush() {
|
|
968
|
+
},
|
|
969
|
+
async close() {
|
|
970
|
+
if (currentStream) {
|
|
971
|
+
return new Promise((resolve) => {
|
|
972
|
+
currentStream?.end(() => resolve());
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// src/transports/json-stream.ts
|
|
980
|
+
function jsonStreamTransport(options) {
|
|
981
|
+
const stream = options.stream;
|
|
982
|
+
const serialize = options.serializer ?? ((entry) => `${JSON.stringify(entry)}
|
|
983
|
+
`);
|
|
984
|
+
return {
|
|
985
|
+
name: "json-stream",
|
|
986
|
+
level: options.level,
|
|
987
|
+
write(entry) {
|
|
988
|
+
const data = serialize(entry);
|
|
989
|
+
stream.write(data);
|
|
990
|
+
},
|
|
991
|
+
close() {
|
|
992
|
+
return new Promise((resolve) => {
|
|
993
|
+
if ("end" in stream && typeof stream.end === "function") {
|
|
994
|
+
stream.end(() => resolve());
|
|
995
|
+
} else {
|
|
996
|
+
resolve();
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// src/transports/loki.ts
|
|
1004
|
+
function lokiTransport(options) {
|
|
1005
|
+
const { host, labels = { app: "voltlog" }, level } = options;
|
|
1006
|
+
const batchSize = options.batchSize ?? 10;
|
|
1007
|
+
const interval = options.interval ?? 5e3;
|
|
1008
|
+
const url = `${host.replace(/\/$/, "")}/loki/api/v1/push`;
|
|
1009
|
+
const headers = {
|
|
1010
|
+
"Content-Type": "application/json"
|
|
1011
|
+
};
|
|
1012
|
+
if (options.basicAuthUser && options.basicAuthPassword) {
|
|
1013
|
+
const creds = btoa(`${options.basicAuthUser}:${options.basicAuthPassword}`);
|
|
1014
|
+
headers.Authorization = `Basic ${creds}`;
|
|
1015
|
+
}
|
|
1016
|
+
if (options.tenantId) {
|
|
1017
|
+
headers["X-Scope-OrgID"] = options.tenantId;
|
|
1018
|
+
}
|
|
1019
|
+
let buffer = [];
|
|
1020
|
+
let timer = null;
|
|
1021
|
+
const flush = async () => {
|
|
1022
|
+
if (buffer.length === 0) return;
|
|
1023
|
+
const batch = buffer;
|
|
1024
|
+
buffer = [];
|
|
1025
|
+
const streams = [
|
|
1026
|
+
{
|
|
1027
|
+
stream: labels,
|
|
1028
|
+
values: batch.map((e) => [
|
|
1029
|
+
String(e.timestamp * 1e6),
|
|
1030
|
+
// Loki wants nanoseconds
|
|
1031
|
+
JSON.stringify({
|
|
1032
|
+
level: e.levelName,
|
|
1033
|
+
message: e.message,
|
|
1034
|
+
...e.meta
|
|
1035
|
+
})
|
|
1036
|
+
])
|
|
1037
|
+
}
|
|
1038
|
+
];
|
|
1039
|
+
try {
|
|
1040
|
+
await fetch(url, {
|
|
1041
|
+
method: "POST",
|
|
1042
|
+
headers,
|
|
1043
|
+
body: JSON.stringify({ streams })
|
|
1044
|
+
});
|
|
1045
|
+
} catch (err) {
|
|
1046
|
+
console.error("[voltlog] Loki push failed", err);
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
const schedule = () => {
|
|
1050
|
+
if (!timer) {
|
|
1051
|
+
timer = setTimeout(() => {
|
|
1052
|
+
timer = null;
|
|
1053
|
+
flush();
|
|
1054
|
+
}, interval);
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
return {
|
|
1058
|
+
name: "loki",
|
|
1059
|
+
level,
|
|
1060
|
+
write(entry) {
|
|
1061
|
+
buffer.push(entry);
|
|
1062
|
+
if (buffer.length >= batchSize) {
|
|
1063
|
+
if (timer) clearTimeout(timer);
|
|
1064
|
+
timer = null;
|
|
1065
|
+
flush();
|
|
1066
|
+
} else {
|
|
1067
|
+
schedule();
|
|
1068
|
+
}
|
|
1069
|
+
},
|
|
1070
|
+
async flush() {
|
|
1071
|
+
if (timer) clearTimeout(timer);
|
|
1072
|
+
await flush();
|
|
1073
|
+
},
|
|
1074
|
+
async close() {
|
|
1075
|
+
await this.flush?.();
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// src/transports/pretty.ts
|
|
1081
|
+
var RESET = "\x1B[0m";
|
|
1082
|
+
var DIM = "\x1B[2m";
|
|
1083
|
+
var BOLD = "\x1B[1m";
|
|
1084
|
+
var COLORS = {
|
|
1085
|
+
TRACE: "\x1B[90m",
|
|
1086
|
+
// gray
|
|
1087
|
+
DEBUG: "\x1B[36m",
|
|
1088
|
+
// cyan
|
|
1089
|
+
INFO: "\x1B[32m",
|
|
1090
|
+
// green
|
|
1091
|
+
WARN: "\x1B[33m",
|
|
1092
|
+
// yellow
|
|
1093
|
+
ERROR: "\x1B[31m",
|
|
1094
|
+
// red
|
|
1095
|
+
FATAL: "\x1B[35;1m"
|
|
1096
|
+
// bold magenta
|
|
1097
|
+
};
|
|
1098
|
+
var ICONS = {
|
|
1099
|
+
TRACE: "\u{1F50D}",
|
|
1100
|
+
DEBUG: "\u{1F41B}",
|
|
1101
|
+
INFO: "\u2139",
|
|
1102
|
+
WARN: "\u26A0",
|
|
1103
|
+
ERROR: "\u2716",
|
|
1104
|
+
FATAL: "\u{1F480}"
|
|
1105
|
+
};
|
|
1106
|
+
var EXCHANGE_ICONS = {
|
|
1107
|
+
CALL: "\u26A1",
|
|
1108
|
+
CALLRESULT: "\u2714",
|
|
1109
|
+
CALLERROR: "\u{1F6A8}"
|
|
1110
|
+
};
|
|
1111
|
+
var DIRECTION_ARROWS = {
|
|
1112
|
+
IN: "\u2192",
|
|
1113
|
+
OUT: "\u2190"
|
|
1114
|
+
};
|
|
1115
|
+
function prettyTransport(options = {}) {
|
|
1116
|
+
const showTimestamps = options.timestamps ?? true;
|
|
1117
|
+
const useColors = options.colors ?? true;
|
|
1118
|
+
function colorize(text, color) {
|
|
1119
|
+
return useColors ? `${color}${text}${RESET}` : text;
|
|
1120
|
+
}
|
|
1121
|
+
function formatExchange(entry) {
|
|
1122
|
+
const meta = entry.meta;
|
|
1123
|
+
if (!meta || !meta.action || !meta.messageType) return null;
|
|
1124
|
+
const icon = EXCHANGE_ICONS[meta.messageType] ?? "\u2022";
|
|
1125
|
+
const arrow = DIRECTION_ARROWS[meta.direction ?? "IN"] ?? "\u2192";
|
|
1126
|
+
const cpId = meta.chargePointId ?? "unknown";
|
|
1127
|
+
const action = meta.action;
|
|
1128
|
+
const msgType = meta.messageType;
|
|
1129
|
+
const dir = meta.direction ?? "";
|
|
1130
|
+
let line = `${icon} ${colorize(cpId, BOLD)} ${arrow} ${colorize(
|
|
1131
|
+
action,
|
|
1132
|
+
BOLD
|
|
1133
|
+
)} [${dir}] ${colorize(msgType, DIM)}`;
|
|
1134
|
+
if (meta.status || meta.latencyMs !== void 0) {
|
|
1135
|
+
const statusIcon = meta.messageType === "CALLERROR" ? "\u274C" : "\u2714";
|
|
1136
|
+
const status = meta.status ?? "";
|
|
1137
|
+
const latency = meta.latencyMs !== void 0 ? `(${meta.latencyMs}ms)` : "";
|
|
1138
|
+
line += `
|
|
1139
|
+
${statusIcon} ${status} ${colorize(latency, DIM)}`;
|
|
1140
|
+
}
|
|
1141
|
+
return line;
|
|
1142
|
+
}
|
|
1143
|
+
function formatStandard(entry) {
|
|
1144
|
+
const icon = ICONS[entry.levelName] ?? "\u2022";
|
|
1145
|
+
const levelColor = COLORS[entry.levelName] ?? "";
|
|
1146
|
+
const level = colorize(entry.levelName.padEnd(5), levelColor);
|
|
1147
|
+
const ts = showTimestamps ? `${colorize(new Date(entry.timestamp).toISOString(), DIM)} ` : "";
|
|
1148
|
+
let line = `${icon} ${ts}${level} ${entry.message}`;
|
|
1149
|
+
if (entry.context && Object.keys(entry.context).length > 0) {
|
|
1150
|
+
line += ` ${colorize(JSON.stringify(entry.context), DIM)}`;
|
|
1151
|
+
}
|
|
1152
|
+
if (entry.meta && Object.keys(entry.meta).length > 0) {
|
|
1153
|
+
line += ` ${colorize(JSON.stringify(entry.meta), DIM)}`;
|
|
1154
|
+
}
|
|
1155
|
+
if (entry.error) {
|
|
1156
|
+
line += `
|
|
1157
|
+
${colorize(
|
|
1158
|
+
`${entry.error.name ?? "Error"}: ${entry.error.message}`,
|
|
1159
|
+
COLORS.ERROR ?? ""
|
|
1160
|
+
)}`;
|
|
1161
|
+
if (entry.error.stack) {
|
|
1162
|
+
line += `
|
|
1163
|
+
${colorize(entry.error.stack, DIM)}`;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
return line;
|
|
1167
|
+
}
|
|
1168
|
+
return {
|
|
1169
|
+
name: "pretty",
|
|
1170
|
+
level: options.level,
|
|
1171
|
+
write(entry) {
|
|
1172
|
+
const exchangeOutput = formatExchange(entry);
|
|
1173
|
+
if (exchangeOutput) {
|
|
1174
|
+
console.log(exchangeOutput);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
const output = formatStandard(entry);
|
|
1178
|
+
if (entry.level >= LogLevel.ERROR) {
|
|
1179
|
+
console.error(output);
|
|
1180
|
+
} else if (entry.level >= LogLevel.WARN) {
|
|
1181
|
+
console.warn(output);
|
|
1182
|
+
} else {
|
|
1183
|
+
console.log(output);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// src/transports/redis.ts
|
|
1190
|
+
function redisTransport(options) {
|
|
1191
|
+
const { client, streamKey = "logs", maxLen, level } = options;
|
|
1192
|
+
const fieldMapper = options.fieldMapper ?? defaultFieldMapper;
|
|
1193
|
+
function defaultFieldMapper(entry) {
|
|
1194
|
+
return {
|
|
1195
|
+
id: entry.id,
|
|
1196
|
+
level: String(entry.level),
|
|
1197
|
+
levelName: entry.levelName,
|
|
1198
|
+
message: entry.message,
|
|
1199
|
+
timestamp: String(entry.timestamp),
|
|
1200
|
+
data: JSON.stringify({
|
|
1201
|
+
meta: entry.meta,
|
|
1202
|
+
context: entry.context,
|
|
1203
|
+
correlationId: entry.correlationId,
|
|
1204
|
+
error: entry.error
|
|
1205
|
+
})
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
return {
|
|
1209
|
+
name: "redis",
|
|
1210
|
+
level,
|
|
1211
|
+
write(entry) {
|
|
1212
|
+
const fields = fieldMapper(entry);
|
|
1213
|
+
const args = [streamKey];
|
|
1214
|
+
if (maxLen) {
|
|
1215
|
+
args.push("MAXLEN", "~", maxLen);
|
|
1216
|
+
}
|
|
1217
|
+
args.push("*");
|
|
1218
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
1219
|
+
args.push(key, value);
|
|
1220
|
+
}
|
|
1221
|
+
client.xadd(...args).catch(() => {
|
|
1222
|
+
});
|
|
1223
|
+
},
|
|
1224
|
+
async close() {
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
// src/transports/sentry.ts
|
|
1230
|
+
function sentryTransport(options) {
|
|
1231
|
+
const { sentry } = options;
|
|
1232
|
+
const errorLevelValue = resolveLevel(options.errorLevel ?? "ERROR");
|
|
1233
|
+
const breadcrumbLevelValue = resolveLevel(options.breadcrumbLevel ?? "INFO");
|
|
1234
|
+
return {
|
|
1235
|
+
name: "sentry",
|
|
1236
|
+
write(entry) {
|
|
1237
|
+
if (entry.level >= errorLevelValue) {
|
|
1238
|
+
if (entry.error) {
|
|
1239
|
+
sentry.captureException(entry.error, {
|
|
1240
|
+
extra: {
|
|
1241
|
+
...entry.meta,
|
|
1242
|
+
context: entry.context
|
|
1243
|
+
},
|
|
1244
|
+
level: "error"
|
|
1245
|
+
});
|
|
1246
|
+
} else {
|
|
1247
|
+
sentry.captureMessage(entry.message, "error");
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
if (entry.level >= breadcrumbLevelValue) {
|
|
1251
|
+
sentry.addBreadcrumb({
|
|
1252
|
+
category: "log",
|
|
1253
|
+
message: entry.message,
|
|
1254
|
+
level: mapLevelToSentry(entry.level),
|
|
1255
|
+
data: { ...entry.meta, ...entry.context },
|
|
1256
|
+
timestamp: entry.timestamp / 1e3
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
function mapLevelToSentry(level) {
|
|
1263
|
+
if (level >= 60) return "fatal";
|
|
1264
|
+
if (level >= 50) return "error";
|
|
1265
|
+
if (level >= 40) return "warning";
|
|
1266
|
+
if (level >= 30) return "info";
|
|
1267
|
+
return "debug";
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// src/transports/slack.ts
|
|
1271
|
+
function slackTransport(options) {
|
|
1272
|
+
const { webhookUrl, username, iconEmoji, level } = options;
|
|
1273
|
+
return {
|
|
1274
|
+
name: "slack",
|
|
1275
|
+
level: level ?? "ERROR",
|
|
1276
|
+
// Default to ERROR to prevent spamming
|
|
1277
|
+
async write(entry) {
|
|
1278
|
+
try {
|
|
1279
|
+
const payload = formatSlackMessage(entry, username, iconEmoji);
|
|
1280
|
+
const response = await fetch(webhookUrl, {
|
|
1281
|
+
method: "POST",
|
|
1282
|
+
headers: { "Content-Type": "application/json" },
|
|
1283
|
+
body: JSON.stringify(payload)
|
|
1284
|
+
});
|
|
1285
|
+
if (!response.ok) {
|
|
1286
|
+
}
|
|
1287
|
+
} catch (_err) {
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
function formatSlackMessage(entry, username, icon_emoji) {
|
|
1293
|
+
const levelEmoji = getLevelEmoji(entry.level);
|
|
1294
|
+
const color = getLevelColor2(entry.level);
|
|
1295
|
+
const blocks = [
|
|
1296
|
+
{
|
|
1297
|
+
type: "header",
|
|
1298
|
+
text: {
|
|
1299
|
+
type: "plain_text",
|
|
1300
|
+
text: `${levelEmoji} ${entry.levelName}: ${entry.message}`,
|
|
1301
|
+
emoji: true
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
type: "context",
|
|
1306
|
+
elements: [
|
|
1307
|
+
{
|
|
1308
|
+
type: "mrkdwn",
|
|
1309
|
+
text: `*Time:* ${new Date(entry.timestamp).toISOString()}`
|
|
1310
|
+
},
|
|
1311
|
+
{
|
|
1312
|
+
type: "mrkdwn",
|
|
1313
|
+
text: `*ID:* \`${entry.id}\``
|
|
1314
|
+
}
|
|
1315
|
+
]
|
|
1316
|
+
}
|
|
1317
|
+
];
|
|
1318
|
+
if (entry.correlationId) {
|
|
1319
|
+
blocks[1].elements.push({
|
|
1320
|
+
type: "mrkdwn",
|
|
1321
|
+
text: `*Trace:* \`${entry.correlationId}\``
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
if (Object.keys(entry.meta).length > 0) {
|
|
1325
|
+
blocks.push({
|
|
1326
|
+
type: "section",
|
|
1327
|
+
text: {
|
|
1328
|
+
type: "mrkdwn",
|
|
1329
|
+
text: `*Metadata:*
|
|
1330
|
+
\`\`\`${JSON.stringify(entry.meta, null, 2)}\`\`\``,
|
|
1331
|
+
emoji: true
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
if (entry.error?.stack) {
|
|
1336
|
+
blocks.push({
|
|
1337
|
+
type: "section",
|
|
1338
|
+
text: {
|
|
1339
|
+
type: "mrkdwn",
|
|
1340
|
+
text: `*Error Stack:*
|
|
1341
|
+
\`\`\`${entry.error.stack}\`\`\``,
|
|
1342
|
+
emoji: true
|
|
1343
|
+
}
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
return {
|
|
1347
|
+
username,
|
|
1348
|
+
icon_emoji,
|
|
1349
|
+
attachments: [
|
|
1350
|
+
{
|
|
1351
|
+
color,
|
|
1352
|
+
blocks
|
|
1353
|
+
}
|
|
1354
|
+
]
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
function getLevelEmoji(level) {
|
|
1358
|
+
if (level >= 60) return "\u{1F525}";
|
|
1359
|
+
if (level >= 50) return "\u{1F6A8}";
|
|
1360
|
+
if (level >= 40) return "\u26A0\uFE0F";
|
|
1361
|
+
if (level >= 30) return "\u2139\uFE0F";
|
|
1362
|
+
if (level >= 20) return "\u{1F41B}";
|
|
1363
|
+
return "\u{1F50D}";
|
|
1364
|
+
}
|
|
1365
|
+
function getLevelColor2(level) {
|
|
1366
|
+
if (level >= 60) return "#ff0000";
|
|
1367
|
+
if (level >= 50) return "#ff4444";
|
|
1368
|
+
if (level >= 40) return "#ffbb33";
|
|
1369
|
+
if (level >= 30) return "#33b5e5";
|
|
1370
|
+
if (level >= 20) return "#99cc00";
|
|
1371
|
+
return "#aa66cc";
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// src/transports/webhook.ts
|
|
1375
|
+
function webhookTransport(options) {
|
|
1376
|
+
const {
|
|
1377
|
+
url,
|
|
1378
|
+
method = "POST",
|
|
1379
|
+
headers = {},
|
|
1380
|
+
batchSize = 1,
|
|
1381
|
+
flushIntervalMs = 5e3,
|
|
1382
|
+
retry = false,
|
|
1383
|
+
maxRetries = 3
|
|
1384
|
+
} = options;
|
|
1385
|
+
const serialize = options.serializer ?? ((entries) => JSON.stringify({
|
|
1386
|
+
entries,
|
|
1387
|
+
count: entries.length,
|
|
1388
|
+
timestamp: Date.now()
|
|
1389
|
+
}));
|
|
1390
|
+
let buffer = [];
|
|
1391
|
+
let flushTimer = null;
|
|
1392
|
+
async function sendBatch(entries, attempt = 0) {
|
|
1393
|
+
try {
|
|
1394
|
+
const response = await fetch(url, {
|
|
1395
|
+
method,
|
|
1396
|
+
headers: {
|
|
1397
|
+
"Content-Type": "application/json",
|
|
1398
|
+
...headers
|
|
1399
|
+
},
|
|
1400
|
+
body: serialize(entries)
|
|
1401
|
+
});
|
|
1402
|
+
if (!response.ok && retry && attempt < maxRetries) {
|
|
1403
|
+
const delay = Math.min(1e3 * 2 ** attempt, 3e4);
|
|
1404
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
1405
|
+
return sendBatch(entries, attempt + 1);
|
|
1406
|
+
}
|
|
1407
|
+
} catch {
|
|
1408
|
+
if (retry && attempt < maxRetries) {
|
|
1409
|
+
const delay = Math.min(1e3 * 2 ** attempt, 3e4);
|
|
1410
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
1411
|
+
return sendBatch(entries, attempt + 1);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
function scheduleFlush() {
|
|
1416
|
+
if (flushTimer) return;
|
|
1417
|
+
flushTimer = setTimeout(() => {
|
|
1418
|
+
flushTimer = null;
|
|
1419
|
+
doFlush();
|
|
1420
|
+
}, flushIntervalMs);
|
|
1421
|
+
}
|
|
1422
|
+
function doFlush() {
|
|
1423
|
+
if (buffer.length === 0) return;
|
|
1424
|
+
const batch = buffer;
|
|
1425
|
+
buffer = [];
|
|
1426
|
+
sendBatch(batch).catch(() => {
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
return {
|
|
1430
|
+
name: "webhook",
|
|
1431
|
+
level: options.level,
|
|
1432
|
+
write(entry) {
|
|
1433
|
+
buffer.push(entry);
|
|
1434
|
+
if (buffer.length >= batchSize) {
|
|
1435
|
+
doFlush();
|
|
1436
|
+
} else {
|
|
1437
|
+
scheduleFlush();
|
|
1438
|
+
}
|
|
1439
|
+
},
|
|
1440
|
+
async flush() {
|
|
1441
|
+
if (flushTimer) {
|
|
1442
|
+
clearTimeout(flushTimer);
|
|
1443
|
+
flushTimer = null;
|
|
1444
|
+
}
|
|
1445
|
+
if (buffer.length > 0) {
|
|
1446
|
+
const batch = buffer;
|
|
1447
|
+
buffer = [];
|
|
1448
|
+
await sendBatch(batch);
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
async close() {
|
|
1452
|
+
await this.flush?.();
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1457
|
+
0 && (module.exports = {
|
|
1458
|
+
LogLevel,
|
|
1459
|
+
LogLevelNameMap,
|
|
1460
|
+
LogLevelValueMap,
|
|
1461
|
+
aiEnrichmentMiddleware,
|
|
1462
|
+
alertMiddleware,
|
|
1463
|
+
batchTransport,
|
|
1464
|
+
browserJsonStreamTransport,
|
|
1465
|
+
consoleTransport,
|
|
1466
|
+
correlationIdMiddleware,
|
|
1467
|
+
createLogger,
|
|
1468
|
+
createMiddleware,
|
|
1469
|
+
createOpenAiErrorAnalyzer,
|
|
1470
|
+
createTransport,
|
|
1471
|
+
datadogTransport,
|
|
1472
|
+
deduplicationMiddleware,
|
|
1473
|
+
discordTransport,
|
|
1474
|
+
fileTransport,
|
|
1475
|
+
heapUsageMiddleware,
|
|
1476
|
+
ipMiddleware,
|
|
1477
|
+
jsonStreamTransport,
|
|
1478
|
+
levelOverrideMiddleware,
|
|
1479
|
+
lokiTransport,
|
|
1480
|
+
ocppMiddleware,
|
|
1481
|
+
prettyTransport,
|
|
1482
|
+
redactionMiddleware,
|
|
1483
|
+
redisTransport,
|
|
1484
|
+
resolveLevel,
|
|
1485
|
+
samplingMiddleware,
|
|
1486
|
+
sentryTransport,
|
|
1487
|
+
shouldIncludeStack,
|
|
1488
|
+
shouldLog,
|
|
1489
|
+
slackTransport,
|
|
1490
|
+
userAgentMiddleware,
|
|
1491
|
+
webhookTransport
|
|
1492
|
+
});
|
|
1493
|
+
//# sourceMappingURL=index.js.map
|