@octaviaflow/logger 1.0.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 +306 -0
- package/dist/index.js +982 -0
- package/dist/index.js.map +18 -0
- package/dist/presets/index.js +1163 -0
- package/dist/presets/index.js.map +21 -0
- package/package.json +73 -0
- package/types/logger.d.ts +494 -0
|
@@ -0,0 +1,1163 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
19
|
+
var __toCommonJS = (from) => {
|
|
20
|
+
var entry = __moduleCache.get(from), desc;
|
|
21
|
+
if (entry)
|
|
22
|
+
return entry;
|
|
23
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
25
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
26
|
+
get: () => from[key],
|
|
27
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
+
}));
|
|
29
|
+
__moduleCache.set(from, entry);
|
|
30
|
+
return entry;
|
|
31
|
+
};
|
|
32
|
+
var __export = (target, all) => {
|
|
33
|
+
for (var name in all)
|
|
34
|
+
__defProp(target, name, {
|
|
35
|
+
get: all[name],
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
set: (newValue) => all[name] = () => newValue
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/presets/index.ts
|
|
43
|
+
var exports_presets = {};
|
|
44
|
+
__export(exports_presets, {
|
|
45
|
+
createUILogger: () => createUILogger,
|
|
46
|
+
createEngineLogger: () => createEngineLogger,
|
|
47
|
+
createBackendLogger: () => createBackendLogger
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(exports_presets);
|
|
50
|
+
|
|
51
|
+
// src/constants.ts
|
|
52
|
+
var LOG_LEVELS = {
|
|
53
|
+
fatal: 0,
|
|
54
|
+
error: 1,
|
|
55
|
+
warn: 2,
|
|
56
|
+
info: 3,
|
|
57
|
+
debug: 4,
|
|
58
|
+
trace: 5
|
|
59
|
+
};
|
|
60
|
+
var COLORS = {
|
|
61
|
+
fatal: "\x1B[35m",
|
|
62
|
+
error: "\x1B[31m",
|
|
63
|
+
warn: "\x1B[33m",
|
|
64
|
+
info: "\x1B[36m",
|
|
65
|
+
debug: "\x1B[32m",
|
|
66
|
+
trace: "\x1B[37m",
|
|
67
|
+
reset: "\x1B[0m",
|
|
68
|
+
bold: "\x1B[1m",
|
|
69
|
+
dim: "\x1B[2m"
|
|
70
|
+
};
|
|
71
|
+
var DEFAULT_MAX_FILE_SIZE = "10m";
|
|
72
|
+
var DEFAULT_MAX_FILES = 10;
|
|
73
|
+
var DEFAULT_DATE_PATTERN = "YYYY-MM-DD";
|
|
74
|
+
var SIZE_UNITS = {
|
|
75
|
+
b: 1,
|
|
76
|
+
k: 1024,
|
|
77
|
+
m: 1024 * 1024,
|
|
78
|
+
g: 1024 * 1024 * 1024
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/transports/base.ts
|
|
82
|
+
class BaseTransport {
|
|
83
|
+
config;
|
|
84
|
+
formatter;
|
|
85
|
+
constructor(config) {
|
|
86
|
+
this.config = config;
|
|
87
|
+
}
|
|
88
|
+
setFormatter(formatter) {
|
|
89
|
+
this.formatter = formatter;
|
|
90
|
+
}
|
|
91
|
+
shouldLog(level) {
|
|
92
|
+
if (!this.config.enabled)
|
|
93
|
+
return false;
|
|
94
|
+
const transportLevel = this.config.level || "trace";
|
|
95
|
+
return LOG_LEVELS[level] <= LOG_LEVELS[transportLevel];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// src/transports/console.ts
|
|
99
|
+
class ConsoleTransport extends BaseTransport {
|
|
100
|
+
log(message, meta) {
|
|
101
|
+
if (!this.shouldLog(meta.level))
|
|
102
|
+
return;
|
|
103
|
+
const formatted = this.formatter ? this.formatter.format(message, meta) : JSON.stringify({ message, ...meta });
|
|
104
|
+
switch (meta.level) {
|
|
105
|
+
case "fatal":
|
|
106
|
+
case "error":
|
|
107
|
+
console.error(formatted);
|
|
108
|
+
break;
|
|
109
|
+
case "warn":
|
|
110
|
+
console.warn(formatted);
|
|
111
|
+
break;
|
|
112
|
+
case "debug":
|
|
113
|
+
console.debug(formatted);
|
|
114
|
+
break;
|
|
115
|
+
case "trace":
|
|
116
|
+
console.trace(formatted);
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
console.log(formatted);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async flush() {}
|
|
123
|
+
async close() {}
|
|
124
|
+
}
|
|
125
|
+
// src/utils/helpers.ts
|
|
126
|
+
var import_node_os = __toESM(require("node:os"));
|
|
127
|
+
function parseSize(size) {
|
|
128
|
+
const match = size.toLowerCase().match(/^(\d+)([bkmg]?)$/);
|
|
129
|
+
if (!match) {
|
|
130
|
+
throw new Error(`Invalid size format: ${size}`);
|
|
131
|
+
}
|
|
132
|
+
const value = parseInt(match[1], 10);
|
|
133
|
+
const unit = match[2] || "b";
|
|
134
|
+
return value * (SIZE_UNITS[unit] ?? 1);
|
|
135
|
+
}
|
|
136
|
+
function formatDuration(ms) {
|
|
137
|
+
if (ms < 1)
|
|
138
|
+
return `${ms.toFixed(3)}ms`;
|
|
139
|
+
if (ms < 1000)
|
|
140
|
+
return `${ms.toFixed(0)}ms`;
|
|
141
|
+
if (ms < 60000)
|
|
142
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
143
|
+
if (ms < 3600000)
|
|
144
|
+
return `${(ms / 60000).toFixed(2)}m`;
|
|
145
|
+
return `${(ms / 3600000).toFixed(2)}h`;
|
|
146
|
+
}
|
|
147
|
+
function getHostname() {
|
|
148
|
+
return import_node_os.default.hostname();
|
|
149
|
+
}
|
|
150
|
+
function getPid() {
|
|
151
|
+
return process.pid;
|
|
152
|
+
}
|
|
153
|
+
function sanitize(obj, fields = ["password", "token", "apiKey", "secret", "authorization"], replacement = "[REDACTED]") {
|
|
154
|
+
if (obj === null || obj === undefined)
|
|
155
|
+
return obj;
|
|
156
|
+
if (typeof obj !== "object")
|
|
157
|
+
return obj;
|
|
158
|
+
if (Array.isArray(obj)) {
|
|
159
|
+
return obj.map((item) => sanitize(item, fields, replacement));
|
|
160
|
+
}
|
|
161
|
+
const sanitized = {};
|
|
162
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
163
|
+
const lowerKey = key.toLowerCase();
|
|
164
|
+
const shouldRedact = fields.some((field) => lowerKey.includes(field.toLowerCase()));
|
|
165
|
+
if (shouldRedact) {
|
|
166
|
+
sanitized[key] = replacement;
|
|
167
|
+
} else if (typeof value === "object" && value !== null) {
|
|
168
|
+
sanitized[key] = sanitize(value, fields, replacement);
|
|
169
|
+
} else {
|
|
170
|
+
sanitized[key] = value;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return sanitized;
|
|
174
|
+
}
|
|
175
|
+
function formatDateForFile(date, pattern) {
|
|
176
|
+
const year = date.getFullYear();
|
|
177
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
178
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
179
|
+
const hour = String(date.getHours()).padStart(2, "0");
|
|
180
|
+
const minute = String(date.getMinutes()).padStart(2, "0");
|
|
181
|
+
return pattern.replace("YYYY", String(year)).replace("MM", month).replace("DD", day).replace("HH", hour).replace("mm", minute);
|
|
182
|
+
}
|
|
183
|
+
function safeStringify(obj, space) {
|
|
184
|
+
const seen = new WeakSet;
|
|
185
|
+
return JSON.stringify(obj, (key, value) => {
|
|
186
|
+
if (typeof value === "object" && value !== null) {
|
|
187
|
+
if (seen.has(value)) {
|
|
188
|
+
return "[Circular]";
|
|
189
|
+
}
|
|
190
|
+
seen.add(value);
|
|
191
|
+
}
|
|
192
|
+
if (value instanceof Error) {
|
|
193
|
+
return {
|
|
194
|
+
name: value.name,
|
|
195
|
+
message: value.message,
|
|
196
|
+
stack: value.stack
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (typeof value === "bigint") {
|
|
200
|
+
return value.toString();
|
|
201
|
+
}
|
|
202
|
+
if (typeof value === "function") {
|
|
203
|
+
return "[Function]";
|
|
204
|
+
}
|
|
205
|
+
return value;
|
|
206
|
+
}, space);
|
|
207
|
+
}
|
|
208
|
+
async function ensureDir(dirPath) {
|
|
209
|
+
const fs = await import("node:fs/promises");
|
|
210
|
+
try {
|
|
211
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (error.code !== "EEXIST") {
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function isDevelopment() {
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/transports/file.ts
|
|
223
|
+
var import_node_path = __toESM(require("node:path"));
|
|
224
|
+
var import_promises = __toESM(require("node:fs/promises"));
|
|
225
|
+
var import_node_fs = require("node:fs");
|
|
226
|
+
var import_node_zlib = require("node:zlib");
|
|
227
|
+
var import_node_util = require("node:util");
|
|
228
|
+
var gzipAsync = import_node_util.promisify(import_node_zlib.gzip);
|
|
229
|
+
|
|
230
|
+
class FileTransport extends BaseTransport {
|
|
231
|
+
writeStream;
|
|
232
|
+
currentSize = 0;
|
|
233
|
+
currentDate = "";
|
|
234
|
+
writeQueue = [];
|
|
235
|
+
isWriting = false;
|
|
236
|
+
isClosed = false;
|
|
237
|
+
async log(message, meta) {
|
|
238
|
+
if (!this.shouldLog(meta.level) || this.isClosed)
|
|
239
|
+
return;
|
|
240
|
+
const formatted = this.formatter ? this.formatter.format(message, meta) : JSON.stringify({ message, ...meta });
|
|
241
|
+
this.writeQueue.push(formatted + `
|
|
242
|
+
`);
|
|
243
|
+
await this.processQueue();
|
|
244
|
+
}
|
|
245
|
+
async processQueue() {
|
|
246
|
+
if (this.isWriting || this.writeQueue.length === 0)
|
|
247
|
+
return;
|
|
248
|
+
this.isWriting = true;
|
|
249
|
+
try {
|
|
250
|
+
while (this.writeQueue.length > 0) {
|
|
251
|
+
const entry = this.writeQueue.shift();
|
|
252
|
+
if (!entry)
|
|
253
|
+
continue;
|
|
254
|
+
await this.ensureStream();
|
|
255
|
+
await this.writeToStream(entry);
|
|
256
|
+
}
|
|
257
|
+
} finally {
|
|
258
|
+
this.isWriting = false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async ensureStream() {
|
|
262
|
+
const fileConfig = this.config.file;
|
|
263
|
+
if (!fileConfig) {
|
|
264
|
+
throw new Error("File transport requires file configuration");
|
|
265
|
+
}
|
|
266
|
+
const maxSize = parseSize(fileConfig.maxSize || DEFAULT_MAX_FILE_SIZE);
|
|
267
|
+
const datePattern = fileConfig.datePattern || DEFAULT_DATE_PATTERN;
|
|
268
|
+
const currentDate = formatDateForFile(new Date, datePattern);
|
|
269
|
+
const needsRotation = this.currentSize >= maxSize || this.currentDate && this.currentDate !== currentDate;
|
|
270
|
+
if (needsRotation || !this.writeStream) {
|
|
271
|
+
await this.rotate();
|
|
272
|
+
}
|
|
273
|
+
this.currentDate = currentDate;
|
|
274
|
+
}
|
|
275
|
+
async writeToStream(data) {
|
|
276
|
+
return new Promise((resolve, reject) => {
|
|
277
|
+
if (!this.writeStream) {
|
|
278
|
+
reject(new Error("Write stream not initialized"));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const canWrite = this.writeStream.write(data);
|
|
282
|
+
this.currentSize += Buffer.byteLength(data);
|
|
283
|
+
if (canWrite) {
|
|
284
|
+
resolve();
|
|
285
|
+
} else {
|
|
286
|
+
this.writeStream.once("drain", () => resolve());
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
async rotate() {
|
|
291
|
+
if (this.writeStream) {
|
|
292
|
+
await this.closeStream();
|
|
293
|
+
}
|
|
294
|
+
const fileConfig = this.config.file;
|
|
295
|
+
const logDir = import_node_path.default.dirname(fileConfig.path);
|
|
296
|
+
const logName = import_node_path.default.basename(fileConfig.path, import_node_path.default.extname(fileConfig.path));
|
|
297
|
+
const logExt = import_node_path.default.extname(fileConfig.path);
|
|
298
|
+
await ensureDir(logDir);
|
|
299
|
+
const datePattern = fileConfig.datePattern || DEFAULT_DATE_PATTERN;
|
|
300
|
+
const dateStr = formatDateForFile(new Date, datePattern);
|
|
301
|
+
const currentLogPath = import_node_path.default.join(logDir, `${logName}-${dateStr}${logExt}`);
|
|
302
|
+
try {
|
|
303
|
+
const stats = await import_promises.default.stat(currentLogPath);
|
|
304
|
+
const maxSize = parseSize(fileConfig.maxSize || DEFAULT_MAX_FILE_SIZE);
|
|
305
|
+
if (stats.size >= maxSize) {
|
|
306
|
+
await this.rotateFiles(logDir, logName, logExt);
|
|
307
|
+
}
|
|
308
|
+
} catch {}
|
|
309
|
+
this.writeStream = import_node_fs.createWriteStream(currentLogPath, { flags: "a" });
|
|
310
|
+
this.currentSize = 0;
|
|
311
|
+
this.writeStream.on("error", (error) => {
|
|
312
|
+
console.error("File transport write error:", error);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async rotateFiles(logDir, logName, logExt) {
|
|
316
|
+
const fileConfig = this.config.file;
|
|
317
|
+
const maxFiles = fileConfig.maxFiles || DEFAULT_MAX_FILES;
|
|
318
|
+
try {
|
|
319
|
+
const files = await import_promises.default.readdir(logDir);
|
|
320
|
+
const logFiles = files.filter((f) => f.startsWith(logName) && f.endsWith(logExt)).sort().reverse();
|
|
321
|
+
if (logFiles.length >= maxFiles) {
|
|
322
|
+
const filesToDelete = logFiles.slice(maxFiles - 1);
|
|
323
|
+
await Promise.all(filesToDelete.map((f) => import_promises.default.unlink(import_node_path.default.join(logDir, f)).catch(() => {})));
|
|
324
|
+
}
|
|
325
|
+
if (fileConfig.compress) {
|
|
326
|
+
const filesToCompress = logFiles.slice(1, maxFiles - 1);
|
|
327
|
+
await Promise.all(filesToCompress.map((f) => this.compressFile(import_node_path.default.join(logDir, f))));
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error("Error rotating files:", error);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async compressFile(filePath) {
|
|
334
|
+
if (filePath.endsWith(".gz"))
|
|
335
|
+
return;
|
|
336
|
+
try {
|
|
337
|
+
const content = await import_promises.default.readFile(filePath);
|
|
338
|
+
const compressed = await gzipAsync(content);
|
|
339
|
+
await import_promises.default.writeFile(`${filePath}.gz`, compressed);
|
|
340
|
+
await import_promises.default.unlink(filePath);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error(`Error compressing file ${filePath}:`, error);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async closeStream() {
|
|
346
|
+
return new Promise((resolve) => {
|
|
347
|
+
if (!this.writeStream) {
|
|
348
|
+
resolve();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
this.writeStream.end(() => {
|
|
352
|
+
this.writeStream = undefined;
|
|
353
|
+
resolve();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
async flush() {
|
|
358
|
+
while (this.writeQueue.length > 0 || this.isWriting) {
|
|
359
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
360
|
+
}
|
|
361
|
+
if (this.writeStream) {
|
|
362
|
+
await new Promise((resolve) => {
|
|
363
|
+
this.writeStream.write("", () => resolve());
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async close() {
|
|
368
|
+
this.isClosed = true;
|
|
369
|
+
await this.flush();
|
|
370
|
+
await this.closeStream();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// src/transports/http.ts
|
|
374
|
+
class HTTPTransport extends BaseTransport {
|
|
375
|
+
batch = { logs: [], timestamp: Date.now() };
|
|
376
|
+
flushTimer;
|
|
377
|
+
isClosed = false;
|
|
378
|
+
constructor(config) {
|
|
379
|
+
super(config);
|
|
380
|
+
this.startFlushTimer();
|
|
381
|
+
}
|
|
382
|
+
async log(message, meta) {
|
|
383
|
+
if (!this.shouldLog(meta.level) || this.isClosed)
|
|
384
|
+
return;
|
|
385
|
+
const httpConfig = this.config.http;
|
|
386
|
+
if (!httpConfig) {
|
|
387
|
+
throw new Error("HTTP transport requires http configuration");
|
|
388
|
+
}
|
|
389
|
+
this.batch.logs.push({ message, meta });
|
|
390
|
+
const batchSize = httpConfig.batchSize || 10;
|
|
391
|
+
if (this.batch.logs.length >= batchSize) {
|
|
392
|
+
await this.flush();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
startFlushTimer() {
|
|
396
|
+
const httpConfig = this.config.http;
|
|
397
|
+
if (!httpConfig)
|
|
398
|
+
return;
|
|
399
|
+
const flushInterval = httpConfig.flushInterval || 5000;
|
|
400
|
+
this.flushTimer = setInterval(() => {
|
|
401
|
+
if (this.batch.logs.length > 0) {
|
|
402
|
+
this.flush().catch((error) => {
|
|
403
|
+
console.error("HTTP transport flush error:", error);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}, flushInterval);
|
|
407
|
+
}
|
|
408
|
+
async flush() {
|
|
409
|
+
if (this.batch.logs.length === 0)
|
|
410
|
+
return;
|
|
411
|
+
const httpConfig = this.config.http;
|
|
412
|
+
if (!httpConfig)
|
|
413
|
+
return;
|
|
414
|
+
const logsToSend = [...this.batch.logs];
|
|
415
|
+
this.batch = { logs: [], timestamp: Date.now() };
|
|
416
|
+
const payload = logsToSend.map((log) => ({
|
|
417
|
+
message: log.message,
|
|
418
|
+
...log.meta
|
|
419
|
+
}));
|
|
420
|
+
await this.sendWithRetry(httpConfig.url, payload, httpConfig.retry);
|
|
421
|
+
}
|
|
422
|
+
async sendWithRetry(url, payload, retryConfig) {
|
|
423
|
+
const httpConfig = this.config.http;
|
|
424
|
+
const maxAttempts = retryConfig?.attempts || 3;
|
|
425
|
+
const retryDelay = retryConfig?.delay || 1000;
|
|
426
|
+
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
427
|
+
try {
|
|
428
|
+
const response = await fetch(url, {
|
|
429
|
+
method: httpConfig.method || "POST",
|
|
430
|
+
headers: {
|
|
431
|
+
"Content-Type": "application/json",
|
|
432
|
+
...httpConfig.headers
|
|
433
|
+
},
|
|
434
|
+
body: JSON.stringify(payload)
|
|
435
|
+
});
|
|
436
|
+
if (!response.ok) {
|
|
437
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
440
|
+
} catch (error) {
|
|
441
|
+
if (attempt === maxAttempts) {
|
|
442
|
+
console.error(`HTTP transport failed after ${maxAttempts} attempts:`, error);
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay * attempt));
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
async close() {
|
|
450
|
+
this.isClosed = true;
|
|
451
|
+
if (this.flushTimer) {
|
|
452
|
+
clearInterval(this.flushTimer);
|
|
453
|
+
this.flushTimer = undefined;
|
|
454
|
+
}
|
|
455
|
+
await this.flush();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// src/formatters/index.ts
|
|
459
|
+
class JSONFormatter {
|
|
460
|
+
options;
|
|
461
|
+
constructor(options = {}) {
|
|
462
|
+
this.options = options;
|
|
463
|
+
}
|
|
464
|
+
format(message, meta) {
|
|
465
|
+
const logEntry = {
|
|
466
|
+
...meta,
|
|
467
|
+
message
|
|
468
|
+
};
|
|
469
|
+
return this.options.prettyPrint ? safeStringify(logEntry, 2) : safeStringify(logEntry);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
class PrettyFormatter {
|
|
474
|
+
options;
|
|
475
|
+
constructor(options = {}) {
|
|
476
|
+
this.options = options;
|
|
477
|
+
}
|
|
478
|
+
format(message, meta) {
|
|
479
|
+
const { colorize = true, includeTimestamp = true } = this.options;
|
|
480
|
+
const { level, service, timestamp } = meta;
|
|
481
|
+
const parts = [];
|
|
482
|
+
if (includeTimestamp) {
|
|
483
|
+
const time = new Date(timestamp).toISOString();
|
|
484
|
+
parts.push(colorize ? `${COLORS.dim}${time}${COLORS.reset}` : time);
|
|
485
|
+
}
|
|
486
|
+
const levelStr = level.toUpperCase().padEnd(5);
|
|
487
|
+
if (colorize) {
|
|
488
|
+
const color = COLORS[level] || COLORS.reset;
|
|
489
|
+
parts.push(`${color}${COLORS.bold}${levelStr}${COLORS.reset}`);
|
|
490
|
+
} else {
|
|
491
|
+
parts.push(levelStr);
|
|
492
|
+
}
|
|
493
|
+
parts.push(`[${service}]`);
|
|
494
|
+
parts.push(message);
|
|
495
|
+
const additionalMeta = this.extractAdditionalMeta(meta);
|
|
496
|
+
if (Object.keys(additionalMeta).length > 0) {
|
|
497
|
+
const metaStr = safeStringify(additionalMeta);
|
|
498
|
+
parts.push(colorize ? `${COLORS.dim}${metaStr}${COLORS.reset}` : metaStr);
|
|
499
|
+
}
|
|
500
|
+
return parts.join(" ");
|
|
501
|
+
}
|
|
502
|
+
extractAdditionalMeta(meta) {
|
|
503
|
+
const {
|
|
504
|
+
timestamp,
|
|
505
|
+
level,
|
|
506
|
+
service,
|
|
507
|
+
hostname,
|
|
508
|
+
pid,
|
|
509
|
+
version,
|
|
510
|
+
environment,
|
|
511
|
+
...additional
|
|
512
|
+
} = meta;
|
|
513
|
+
return additional;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
class CompactFormatter {
|
|
518
|
+
options;
|
|
519
|
+
constructor(options = {}) {
|
|
520
|
+
this.options = options;
|
|
521
|
+
}
|
|
522
|
+
format(message, meta) {
|
|
523
|
+
const { level, service, timestamp } = meta;
|
|
524
|
+
const time = new Date(timestamp).toISOString().split("T")[1]?.split(".")[0] || "";
|
|
525
|
+
return `${time} ${level.charAt(0).toUpperCase()} [${service}] ${message}`;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
class ECSFormatter {
|
|
530
|
+
options;
|
|
531
|
+
constructor(options = {}) {
|
|
532
|
+
this.options = options;
|
|
533
|
+
}
|
|
534
|
+
format(message, meta) {
|
|
535
|
+
const ecsLog = {
|
|
536
|
+
"@timestamp": meta.timestamp,
|
|
537
|
+
"log.level": meta.level,
|
|
538
|
+
message,
|
|
539
|
+
service: {
|
|
540
|
+
name: meta.service,
|
|
541
|
+
version: meta.version,
|
|
542
|
+
environment: meta.environment
|
|
543
|
+
},
|
|
544
|
+
host: {
|
|
545
|
+
hostname: meta.hostname
|
|
546
|
+
},
|
|
547
|
+
process: {
|
|
548
|
+
pid: meta.pid
|
|
549
|
+
},
|
|
550
|
+
labels: this.extractLabels(meta),
|
|
551
|
+
...this.extractECSFields(meta)
|
|
552
|
+
};
|
|
553
|
+
return safeStringify(ecsLog);
|
|
554
|
+
}
|
|
555
|
+
extractLabels(meta) {
|
|
556
|
+
const labels = {};
|
|
557
|
+
if (meta.correlation?.traceId) {
|
|
558
|
+
labels.trace_id = meta.correlation.traceId;
|
|
559
|
+
}
|
|
560
|
+
if (meta.correlation?.spanId) {
|
|
561
|
+
labels.span_id = meta.correlation.spanId;
|
|
562
|
+
}
|
|
563
|
+
if (meta.user?.userId) {
|
|
564
|
+
labels.user_id = meta.user.userId;
|
|
565
|
+
}
|
|
566
|
+
if (meta.workflow?.workflowId) {
|
|
567
|
+
labels.workflow_id = meta.workflow.workflowId;
|
|
568
|
+
}
|
|
569
|
+
return labels;
|
|
570
|
+
}
|
|
571
|
+
extractECSFields(meta) {
|
|
572
|
+
const fields = {};
|
|
573
|
+
if (meta.request) {
|
|
574
|
+
fields.http = {
|
|
575
|
+
request: {
|
|
576
|
+
method: meta.request.method,
|
|
577
|
+
id: meta.request.requestId
|
|
578
|
+
},
|
|
579
|
+
url: {
|
|
580
|
+
path: meta.request.path,
|
|
581
|
+
query: meta.request.query
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
fields.client = {
|
|
585
|
+
ip: meta.request.ip,
|
|
586
|
+
user_agent: meta.request.userAgent
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
if (meta.user) {
|
|
590
|
+
fields.user = {
|
|
591
|
+
id: meta.user.userId,
|
|
592
|
+
name: meta.user.username,
|
|
593
|
+
email: meta.user.email,
|
|
594
|
+
roles: meta.user.roles
|
|
595
|
+
};
|
|
596
|
+
fields.organization = {
|
|
597
|
+
id: meta.user.organizationId
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
return fields;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function createFormatter(format, options = {}) {
|
|
604
|
+
switch (format) {
|
|
605
|
+
case "json":
|
|
606
|
+
return new JSONFormatter(options);
|
|
607
|
+
case "pretty":
|
|
608
|
+
return new PrettyFormatter(options);
|
|
609
|
+
case "compact":
|
|
610
|
+
return new CompactFormatter(options);
|
|
611
|
+
case "ecs":
|
|
612
|
+
return new ECSFormatter(options);
|
|
613
|
+
default:
|
|
614
|
+
return new JSONFormatter(options);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// src/context/manager.ts
|
|
619
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
620
|
+
|
|
621
|
+
class ContextManager {
|
|
622
|
+
storage = new import_node_async_hooks.AsyncLocalStorage;
|
|
623
|
+
run(context, fn) {
|
|
624
|
+
return this.storage.run(context, fn);
|
|
625
|
+
}
|
|
626
|
+
getContext() {
|
|
627
|
+
return this.storage.getStore() || {};
|
|
628
|
+
}
|
|
629
|
+
setContext(context) {
|
|
630
|
+
const current = this.getContext();
|
|
631
|
+
const merged = { ...current, ...context };
|
|
632
|
+
this.storage.enterWith(merged);
|
|
633
|
+
}
|
|
634
|
+
clearContext() {
|
|
635
|
+
this.storage.enterWith({});
|
|
636
|
+
}
|
|
637
|
+
mergeContext(context) {
|
|
638
|
+
const current = this.getContext();
|
|
639
|
+
return { ...current, ...context };
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
var contextManager = new ContextManager;
|
|
643
|
+
|
|
644
|
+
// src/logger.ts
|
|
645
|
+
class Logger {
|
|
646
|
+
config;
|
|
647
|
+
transports = [];
|
|
648
|
+
timers = new Map;
|
|
649
|
+
childContext = {};
|
|
650
|
+
constructor(config) {
|
|
651
|
+
this.config = config;
|
|
652
|
+
this.initializeTransports();
|
|
653
|
+
this.setupErrorHandlers();
|
|
654
|
+
}
|
|
655
|
+
initializeTransports() {
|
|
656
|
+
for (const transportConfig of this.config.transports) {
|
|
657
|
+
let transport;
|
|
658
|
+
switch (transportConfig.type) {
|
|
659
|
+
case "console":
|
|
660
|
+
transport = new ConsoleTransport(transportConfig);
|
|
661
|
+
break;
|
|
662
|
+
case "file":
|
|
663
|
+
transport = new FileTransport(transportConfig);
|
|
664
|
+
break;
|
|
665
|
+
case "http":
|
|
666
|
+
transport = new HTTPTransport(transportConfig);
|
|
667
|
+
break;
|
|
668
|
+
default:
|
|
669
|
+
console.warn(`Unknown transport type: ${transportConfig.type}`);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
const format = transportConfig.format || this.config.format;
|
|
673
|
+
const formatter = createFormatter(format, {
|
|
674
|
+
colorize: this.config.colorize,
|
|
675
|
+
prettyPrint: this.config.prettyPrint,
|
|
676
|
+
includeTimestamp: this.config.timestamps
|
|
677
|
+
});
|
|
678
|
+
transport.setFormatter(formatter);
|
|
679
|
+
this.transports.push(transport);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
setupErrorHandlers() {
|
|
683
|
+
if (this.config.handleExceptions) {
|
|
684
|
+
process.on("uncaughtException", (error) => {
|
|
685
|
+
this.error("Uncaught exception", {
|
|
686
|
+
type: "error",
|
|
687
|
+
error: {
|
|
688
|
+
name: error.name,
|
|
689
|
+
message: error.message,
|
|
690
|
+
stack: error.stack
|
|
691
|
+
},
|
|
692
|
+
handled: false
|
|
693
|
+
});
|
|
694
|
+
if (this.config.exitOnError) {
|
|
695
|
+
this.close().then(() => process.exit(1));
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
if (this.config.handleRejections) {
|
|
700
|
+
process.on("unhandledRejection", (reason) => {
|
|
701
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
702
|
+
this.error("Unhandled rejection", {
|
|
703
|
+
type: "error",
|
|
704
|
+
error: {
|
|
705
|
+
name: error.name,
|
|
706
|
+
message: error.message,
|
|
707
|
+
stack: error.stack
|
|
708
|
+
},
|
|
709
|
+
handled: false
|
|
710
|
+
});
|
|
711
|
+
if (this.config.exitOnError) {
|
|
712
|
+
this.close().then(() => process.exit(1));
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
shouldLog(level) {
|
|
718
|
+
return LOG_LEVELS[level] <= LOG_LEVELS[this.config.level];
|
|
719
|
+
}
|
|
720
|
+
buildMeta(level, meta = {}) {
|
|
721
|
+
const asyncContext = contextManager.getContext();
|
|
722
|
+
const mergedMeta = {
|
|
723
|
+
timestamp: new Date().toISOString(),
|
|
724
|
+
level,
|
|
725
|
+
service: this.config.service,
|
|
726
|
+
hostname: this.config.hostname || getHostname(),
|
|
727
|
+
pid: getPid(),
|
|
728
|
+
version: this.config.version,
|
|
729
|
+
environment: this.config.environment,
|
|
730
|
+
...this.config.defaultMeta,
|
|
731
|
+
...asyncContext,
|
|
732
|
+
...this.childContext,
|
|
733
|
+
...meta
|
|
734
|
+
};
|
|
735
|
+
if (this.config.sanitize?.enabled) {
|
|
736
|
+
return sanitize(mergedMeta, this.config.sanitize.fields, this.config.sanitize.replacement);
|
|
737
|
+
}
|
|
738
|
+
return mergedMeta;
|
|
739
|
+
}
|
|
740
|
+
log(level, message, meta = {}) {
|
|
741
|
+
if (!this.shouldLog(level))
|
|
742
|
+
return;
|
|
743
|
+
const fullMeta = this.buildMeta(level, meta);
|
|
744
|
+
if (this.config.sampling?.enabled && !this.shouldSample(fullMeta)) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
if (this.config.filters?.enabled && this.shouldFilter(fullMeta)) {
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
for (const transport of this.transports) {
|
|
751
|
+
try {
|
|
752
|
+
transport.log(message, fullMeta);
|
|
753
|
+
} catch (error) {
|
|
754
|
+
console.error("Transport error:", error);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
shouldSample(meta) {
|
|
759
|
+
if (!this.config.sampling?.enabled)
|
|
760
|
+
return true;
|
|
761
|
+
for (const rule of this.config.sampling.rules) {
|
|
762
|
+
if (rule.level && meta.level !== rule.level)
|
|
763
|
+
continue;
|
|
764
|
+
if (rule.service && meta.service !== rule.service)
|
|
765
|
+
continue;
|
|
766
|
+
if (rule.condition && !rule.condition(meta))
|
|
767
|
+
continue;
|
|
768
|
+
return Math.random() < rule.rate;
|
|
769
|
+
}
|
|
770
|
+
return true;
|
|
771
|
+
}
|
|
772
|
+
shouldFilter(meta) {
|
|
773
|
+
if (!this.config.filters?.enabled)
|
|
774
|
+
return false;
|
|
775
|
+
for (const rule of this.config.filters.rules) {
|
|
776
|
+
const value = this.getNestedValue(meta, rule.field);
|
|
777
|
+
if (value === undefined)
|
|
778
|
+
continue;
|
|
779
|
+
const matches = typeof rule.pattern === "string" ? String(value).includes(rule.pattern) : rule.pattern.test(String(value));
|
|
780
|
+
if (rule.type === "exclude" && matches) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
if (rule.type === "include" && !matches) {
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
getNestedValue(obj, path2) {
|
|
790
|
+
return path2.split(".").reduce((current, key) => {
|
|
791
|
+
return current && typeof current === "object" ? current[key] : undefined;
|
|
792
|
+
}, obj);
|
|
793
|
+
}
|
|
794
|
+
fatal(message, meta) {
|
|
795
|
+
this.log("fatal", message, meta);
|
|
796
|
+
}
|
|
797
|
+
error(message, meta) {
|
|
798
|
+
this.log("error", message, meta);
|
|
799
|
+
}
|
|
800
|
+
warn(message, meta) {
|
|
801
|
+
this.log("warn", message, meta);
|
|
802
|
+
}
|
|
803
|
+
info(message, meta) {
|
|
804
|
+
this.log("info", message, meta);
|
|
805
|
+
}
|
|
806
|
+
debug(message, meta) {
|
|
807
|
+
this.log("debug", message, meta);
|
|
808
|
+
}
|
|
809
|
+
trace(message, meta) {
|
|
810
|
+
this.log("trace", message, meta);
|
|
811
|
+
}
|
|
812
|
+
audit(action, meta) {
|
|
813
|
+
this.info(`Audit: ${action}`, {
|
|
814
|
+
...meta,
|
|
815
|
+
type: "audit"
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
security(event, meta) {
|
|
819
|
+
const level = meta.severity === "critical" || meta.severity === "high" ? "error" : "warn";
|
|
820
|
+
this.log(level, `Security: ${event}`, {
|
|
821
|
+
...meta,
|
|
822
|
+
type: "security",
|
|
823
|
+
event
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
performance(operation, duration, meta) {
|
|
827
|
+
this.info(`Performance: ${operation}`, {
|
|
828
|
+
...meta,
|
|
829
|
+
type: "performance",
|
|
830
|
+
operation,
|
|
831
|
+
duration: {
|
|
832
|
+
ms: duration,
|
|
833
|
+
human: formatDuration(duration)
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
metric(name, value, meta) {
|
|
838
|
+
this.info(`Metric: ${name}`, {
|
|
839
|
+
...meta,
|
|
840
|
+
type: "metrics",
|
|
841
|
+
metrics: {
|
|
842
|
+
counters: { [name]: value }
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
child(context) {
|
|
847
|
+
const childLogger = new Logger(this.config);
|
|
848
|
+
childLogger.childContext = { ...this.childContext, ...context };
|
|
849
|
+
childLogger.transports = this.transports;
|
|
850
|
+
return childLogger;
|
|
851
|
+
}
|
|
852
|
+
setContext(context) {
|
|
853
|
+
contextManager.setContext(context);
|
|
854
|
+
}
|
|
855
|
+
clearContext() {
|
|
856
|
+
contextManager.clearContext();
|
|
857
|
+
}
|
|
858
|
+
startWorkflow(workflow) {
|
|
859
|
+
this.setContext({ workflow });
|
|
860
|
+
this.info("Workflow started", {
|
|
861
|
+
type: "workflow",
|
|
862
|
+
event: "started"
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
endWorkflow(success, meta) {
|
|
866
|
+
const event = success ? "completed" : "failed";
|
|
867
|
+
const logMeta = {
|
|
868
|
+
type: "workflow",
|
|
869
|
+
event,
|
|
870
|
+
...meta
|
|
871
|
+
};
|
|
872
|
+
this.info(`Workflow ${event}`, logMeta);
|
|
873
|
+
this.clearContext();
|
|
874
|
+
}
|
|
875
|
+
startRequest(request) {
|
|
876
|
+
this.setContext({ request });
|
|
877
|
+
this.info("Request started", {
|
|
878
|
+
type: "api",
|
|
879
|
+
direction: "inbound"
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
endRequest(statusCode, duration) {
|
|
883
|
+
this.info("Request completed", {
|
|
884
|
+
type: "api",
|
|
885
|
+
direction: "inbound",
|
|
886
|
+
statusCode,
|
|
887
|
+
duration
|
|
888
|
+
});
|
|
889
|
+
this.clearContext();
|
|
890
|
+
}
|
|
891
|
+
profile(id) {
|
|
892
|
+
if (this.timers.has(id)) {
|
|
893
|
+
const start = this.timers.get(id);
|
|
894
|
+
const duration = Date.now() - start;
|
|
895
|
+
this.timers.delete(id);
|
|
896
|
+
this.performance(id, duration);
|
|
897
|
+
} else {
|
|
898
|
+
this.timers.set(id, Date.now());
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
startTimer() {
|
|
902
|
+
const start = Date.now();
|
|
903
|
+
return () => Date.now() - start;
|
|
904
|
+
}
|
|
905
|
+
async flush() {
|
|
906
|
+
await Promise.all(this.transports.map((t) => t.flush()));
|
|
907
|
+
}
|
|
908
|
+
async close() {
|
|
909
|
+
await Promise.all(this.transports.map((t) => t.close()));
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// src/presets/backend.ts
|
|
914
|
+
var import_node_path2 = __toESM(require("node:path"));
|
|
915
|
+
function createBackendLogger(options = {}) {
|
|
916
|
+
const {
|
|
917
|
+
level = isDevelopment() ? "debug" : "info",
|
|
918
|
+
logDir = "./logs",
|
|
919
|
+
enableConsole = true,
|
|
920
|
+
enableFile = true,
|
|
921
|
+
version = "1.0.0",
|
|
922
|
+
defaultMeta = {}
|
|
923
|
+
} = options;
|
|
924
|
+
const config = {
|
|
925
|
+
service: "backend",
|
|
926
|
+
environment: "development",
|
|
927
|
+
version,
|
|
928
|
+
level,
|
|
929
|
+
format: isDevelopment() ? "pretty" : "json",
|
|
930
|
+
prettyPrint: isDevelopment(),
|
|
931
|
+
colorize: isDevelopment(),
|
|
932
|
+
timestamps: true,
|
|
933
|
+
transports: [],
|
|
934
|
+
handleExceptions: true,
|
|
935
|
+
handleRejections: true,
|
|
936
|
+
exitOnError: false,
|
|
937
|
+
defaultMeta,
|
|
938
|
+
contextStorage: "asynclocal",
|
|
939
|
+
sanitize: {
|
|
940
|
+
enabled: true,
|
|
941
|
+
fields: ["password", "token", "apiKey", "secret", "authorization", "cookie"]
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
if (enableConsole) {
|
|
945
|
+
config.transports.push({
|
|
946
|
+
type: "console",
|
|
947
|
+
enabled: true,
|
|
948
|
+
level,
|
|
949
|
+
format: isDevelopment() ? "pretty" : "json"
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
if (enableFile) {
|
|
953
|
+
config.transports.push({
|
|
954
|
+
type: "file",
|
|
955
|
+
enabled: true,
|
|
956
|
+
level,
|
|
957
|
+
format: "json",
|
|
958
|
+
file: {
|
|
959
|
+
path: import_node_path2.default.join(logDir, "backend.log"),
|
|
960
|
+
maxSize: "10m",
|
|
961
|
+
maxFiles: 10,
|
|
962
|
+
compress: true,
|
|
963
|
+
datePattern: "YYYY-MM-DD"
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
config.transports.push({
|
|
967
|
+
type: "file",
|
|
968
|
+
enabled: true,
|
|
969
|
+
level: "error",
|
|
970
|
+
format: "json",
|
|
971
|
+
file: {
|
|
972
|
+
path: import_node_path2.default.join(logDir, "backend-error.log"),
|
|
973
|
+
maxSize: "10m",
|
|
974
|
+
maxFiles: 10,
|
|
975
|
+
compress: true,
|
|
976
|
+
datePattern: "YYYY-MM-DD"
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
config.transports.push({
|
|
980
|
+
type: "file",
|
|
981
|
+
enabled: true,
|
|
982
|
+
level: "info",
|
|
983
|
+
format: "json",
|
|
984
|
+
file: {
|
|
985
|
+
path: import_node_path2.default.join(logDir, "backend-audit.log"),
|
|
986
|
+
maxSize: "10m",
|
|
987
|
+
maxFiles: 30,
|
|
988
|
+
compress: true,
|
|
989
|
+
datePattern: "YYYY-MM-DD"
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
return new Logger(config);
|
|
994
|
+
}
|
|
995
|
+
// src/presets/engine.ts
|
|
996
|
+
var import_node_path3 = __toESM(require("node:path"));
|
|
997
|
+
function createEngineLogger(options = {}) {
|
|
998
|
+
const {
|
|
999
|
+
level = isDevelopment() ? "debug" : "info",
|
|
1000
|
+
logDir = "./logs",
|
|
1001
|
+
enableConsole = true,
|
|
1002
|
+
enableFile = true,
|
|
1003
|
+
version = "1.0.0",
|
|
1004
|
+
workerId,
|
|
1005
|
+
defaultMeta = {}
|
|
1006
|
+
} = options;
|
|
1007
|
+
const config = {
|
|
1008
|
+
service: "engine",
|
|
1009
|
+
environment: "development",
|
|
1010
|
+
version,
|
|
1011
|
+
level,
|
|
1012
|
+
format: isDevelopment() ? "pretty" : "json",
|
|
1013
|
+
prettyPrint: isDevelopment(),
|
|
1014
|
+
colorize: isDevelopment(),
|
|
1015
|
+
timestamps: true,
|
|
1016
|
+
transports: [],
|
|
1017
|
+
handleExceptions: true,
|
|
1018
|
+
handleRejections: true,
|
|
1019
|
+
exitOnError: false,
|
|
1020
|
+
defaultMeta: {
|
|
1021
|
+
...defaultMeta,
|
|
1022
|
+
...workerId && { workerId }
|
|
1023
|
+
},
|
|
1024
|
+
contextStorage: "asynclocal"
|
|
1025
|
+
};
|
|
1026
|
+
if (enableConsole) {
|
|
1027
|
+
config.transports.push({
|
|
1028
|
+
type: "console",
|
|
1029
|
+
enabled: true,
|
|
1030
|
+
level,
|
|
1031
|
+
format: isDevelopment() ? "pretty" : "json"
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
if (enableFile) {
|
|
1035
|
+
const workerSuffix = workerId ? `-${workerId}` : "";
|
|
1036
|
+
config.transports.push({
|
|
1037
|
+
type: "file",
|
|
1038
|
+
enabled: true,
|
|
1039
|
+
level,
|
|
1040
|
+
format: "json",
|
|
1041
|
+
file: {
|
|
1042
|
+
path: import_node_path3.default.join(logDir, `engine${workerSuffix}.log`),
|
|
1043
|
+
maxSize: "10m",
|
|
1044
|
+
maxFiles: 10,
|
|
1045
|
+
compress: true,
|
|
1046
|
+
datePattern: "YYYY-MM-DD"
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
config.transports.push({
|
|
1050
|
+
type: "file",
|
|
1051
|
+
enabled: true,
|
|
1052
|
+
level: "error",
|
|
1053
|
+
format: "json",
|
|
1054
|
+
file: {
|
|
1055
|
+
path: import_node_path3.default.join(logDir, `engine${workerSuffix}-error.log`),
|
|
1056
|
+
maxSize: "10m",
|
|
1057
|
+
maxFiles: 10,
|
|
1058
|
+
compress: true,
|
|
1059
|
+
datePattern: "YYYY-MM-DD"
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
config.transports.push({
|
|
1063
|
+
type: "file",
|
|
1064
|
+
enabled: true,
|
|
1065
|
+
level: "info",
|
|
1066
|
+
format: "json",
|
|
1067
|
+
file: {
|
|
1068
|
+
path: import_node_path3.default.join(logDir, `engine${workerSuffix}-workflows.log`),
|
|
1069
|
+
maxSize: "20m",
|
|
1070
|
+
maxFiles: 20,
|
|
1071
|
+
compress: true,
|
|
1072
|
+
datePattern: "YYYY-MM-DD"
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
config.transports.push({
|
|
1076
|
+
type: "file",
|
|
1077
|
+
enabled: true,
|
|
1078
|
+
level: "info",
|
|
1079
|
+
format: "json",
|
|
1080
|
+
file: {
|
|
1081
|
+
path: import_node_path3.default.join(logDir, `engine${workerSuffix}-performance.log`),
|
|
1082
|
+
maxSize: "10m",
|
|
1083
|
+
maxFiles: 10,
|
|
1084
|
+
compress: true,
|
|
1085
|
+
datePattern: "YYYY-MM-DD"
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
return new Logger(config);
|
|
1090
|
+
}
|
|
1091
|
+
// src/presets/ui.ts
|
|
1092
|
+
function createUILogger(options = {}) {
|
|
1093
|
+
const {
|
|
1094
|
+
level = isDevelopment() ? "debug" : "warn",
|
|
1095
|
+
enableConsole = true,
|
|
1096
|
+
enableRemote = false,
|
|
1097
|
+
remoteUrl,
|
|
1098
|
+
version = "1.0.0",
|
|
1099
|
+
defaultMeta = {}
|
|
1100
|
+
} = options;
|
|
1101
|
+
const config = {
|
|
1102
|
+
service: "ui",
|
|
1103
|
+
environment: "development",
|
|
1104
|
+
version,
|
|
1105
|
+
level,
|
|
1106
|
+
format: isDevelopment() ? "pretty" : "compact",
|
|
1107
|
+
prettyPrint: isDevelopment(),
|
|
1108
|
+
colorize: isDevelopment(),
|
|
1109
|
+
timestamps: true,
|
|
1110
|
+
transports: [],
|
|
1111
|
+
handleExceptions: true,
|
|
1112
|
+
handleRejections: true,
|
|
1113
|
+
exitOnError: false,
|
|
1114
|
+
defaultMeta,
|
|
1115
|
+
contextStorage: "asynclocal",
|
|
1116
|
+
sanitize: {
|
|
1117
|
+
enabled: true,
|
|
1118
|
+
fields: ["password", "token", "apiKey", "secret", "authorization", "cookie", "creditCard"]
|
|
1119
|
+
},
|
|
1120
|
+
sampling: isDevelopment() ? undefined : {
|
|
1121
|
+
enabled: true,
|
|
1122
|
+
rules: [
|
|
1123
|
+
{
|
|
1124
|
+
level: "debug",
|
|
1125
|
+
rate: 0.1
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
level: "trace",
|
|
1129
|
+
rate: 0.05
|
|
1130
|
+
}
|
|
1131
|
+
]
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
if (enableConsole) {
|
|
1135
|
+
config.transports.push({
|
|
1136
|
+
type: "console",
|
|
1137
|
+
enabled: true,
|
|
1138
|
+
level,
|
|
1139
|
+
format: isDevelopment() ? "pretty" : "compact"
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
if (enableRemote && remoteUrl) {
|
|
1143
|
+
config.transports.push({
|
|
1144
|
+
type: "http",
|
|
1145
|
+
enabled: true,
|
|
1146
|
+
level: "warn",
|
|
1147
|
+
format: "json",
|
|
1148
|
+
http: {
|
|
1149
|
+
url: remoteUrl,
|
|
1150
|
+
method: "POST",
|
|
1151
|
+
batchSize: 20,
|
|
1152
|
+
flushInterval: 1e4,
|
|
1153
|
+
retry: {
|
|
1154
|
+
attempts: 3,
|
|
1155
|
+
delay: 1000
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
return new Logger(config);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
//# debugId=F1B76F8586B4D6C964756E2164756E21
|