@rawnodes/logger 1.9.1 → 2.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/dist/index.d.mts +26 -5
- package/dist/index.d.ts +26 -5
- package/dist/index.js +488 -328
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +487 -326
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -7
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pino from 'pino';
|
|
2
2
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
3
|
+
import { Transform, Writable } from 'stream';
|
|
4
|
+
import { mkdir } from 'fs/promises';
|
|
5
|
+
import { createStream } from 'rotating-file-stream';
|
|
6
|
+
import { EventEmitter } from 'events';
|
|
6
7
|
import { CloudWatchLogsClient, PutLogEventsCommand, CreateLogGroupCommand, CreateLogStreamCommand, DescribeLogStreamsCommand } from '@aws-sdk/client-cloudwatch-logs';
|
|
7
8
|
import { z } from 'zod';
|
|
8
9
|
import { randomUUID } from 'crypto';
|
|
@@ -38,238 +39,6 @@ function assertLogLevel(level) {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
// src/utils/mask-secrets.ts
|
|
42
|
-
var DEFAULT_SECRET_PATTERNS = [
|
|
43
|
-
"password",
|
|
44
|
-
"secret",
|
|
45
|
-
"token",
|
|
46
|
-
"apikey",
|
|
47
|
-
"api_key",
|
|
48
|
-
"api-key",
|
|
49
|
-
"auth",
|
|
50
|
-
"credential",
|
|
51
|
-
"private"
|
|
52
|
-
];
|
|
53
|
-
var DEFAULT_MASK = "***";
|
|
54
|
-
function isSecretKey(key, patterns) {
|
|
55
|
-
const lowerKey = key.toLowerCase();
|
|
56
|
-
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
57
|
-
}
|
|
58
|
-
function maskUrlCredentials(url, mask) {
|
|
59
|
-
try {
|
|
60
|
-
const parsed = new URL(url);
|
|
61
|
-
if (parsed.password) {
|
|
62
|
-
parsed.password = mask;
|
|
63
|
-
}
|
|
64
|
-
if (parsed.username && parsed.password) {
|
|
65
|
-
parsed.username = mask;
|
|
66
|
-
}
|
|
67
|
-
return parsed.toString();
|
|
68
|
-
} catch {
|
|
69
|
-
return url;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function maskSecrets(obj, options = {}) {
|
|
73
|
-
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
74
|
-
if (obj === null || obj === void 0) {
|
|
75
|
-
return obj;
|
|
76
|
-
}
|
|
77
|
-
if (typeof obj === "string") {
|
|
78
|
-
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
79
|
-
return maskUrlCredentials(obj, mask);
|
|
80
|
-
}
|
|
81
|
-
return obj;
|
|
82
|
-
}
|
|
83
|
-
if (Array.isArray(obj)) {
|
|
84
|
-
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
85
|
-
}
|
|
86
|
-
if (typeof obj === "object") {
|
|
87
|
-
const result = {};
|
|
88
|
-
for (const sym of Object.getOwnPropertySymbols(obj)) {
|
|
89
|
-
result[sym] = obj[sym];
|
|
90
|
-
}
|
|
91
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
92
|
-
if (isSecretKey(key, patterns)) {
|
|
93
|
-
result[key] = mask;
|
|
94
|
-
} else if (deep && typeof value === "object" && value !== null) {
|
|
95
|
-
result[key] = maskSecrets(value, options);
|
|
96
|
-
} else if (typeof value === "string") {
|
|
97
|
-
result[key] = maskSecrets(value, options);
|
|
98
|
-
} else {
|
|
99
|
-
result[key] = value;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return result;
|
|
103
|
-
}
|
|
104
|
-
return obj;
|
|
105
|
-
}
|
|
106
|
-
function createMasker(options = {}) {
|
|
107
|
-
return (obj) => maskSecrets(obj, options);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// src/formatters.ts
|
|
111
|
-
var DEFAULT_CONTEXT = "APP";
|
|
112
|
-
var LEVEL_COLORS = {
|
|
113
|
-
error: "\x1B[31m",
|
|
114
|
-
// red
|
|
115
|
-
warn: "\x1B[33m",
|
|
116
|
-
// yellow
|
|
117
|
-
info: "\x1B[32m",
|
|
118
|
-
// green
|
|
119
|
-
http: "\x1B[35m",
|
|
120
|
-
// magenta
|
|
121
|
-
verbose: "\x1B[36m",
|
|
122
|
-
// cyan
|
|
123
|
-
debug: "\x1B[34m",
|
|
124
|
-
// blue
|
|
125
|
-
silly: "\x1B[90m"
|
|
126
|
-
// grey
|
|
127
|
-
};
|
|
128
|
-
var RESET = "\x1B[0m";
|
|
129
|
-
function colorizeLevel(level) {
|
|
130
|
-
const color = LEVEL_COLORS[level] || "";
|
|
131
|
-
return color ? `${color}${level}${RESET}` : level;
|
|
132
|
-
}
|
|
133
|
-
function formatMeta(meta, colors) {
|
|
134
|
-
return Object.entries(meta).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => {
|
|
135
|
-
if (typeof value === "object") {
|
|
136
|
-
const inspected = inspect(value, { depth: 4, colors, compact: false });
|
|
137
|
-
return `
|
|
138
|
-
${key}: ${inspected.split("\n").join("\n ")}`;
|
|
139
|
-
}
|
|
140
|
-
return `
|
|
141
|
-
${key}: ${value}`;
|
|
142
|
-
}).join("");
|
|
143
|
-
}
|
|
144
|
-
function flattenObject(obj, prefix = "") {
|
|
145
|
-
const result = {};
|
|
146
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
147
|
-
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
148
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Error)) {
|
|
149
|
-
Object.assign(result, flattenObject(value, newKey));
|
|
150
|
-
} else {
|
|
151
|
-
result[newKey] = value;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
function formatLogfmtValue(value) {
|
|
157
|
-
if (value === null || value === void 0) {
|
|
158
|
-
return "";
|
|
159
|
-
}
|
|
160
|
-
if (typeof value === "string") {
|
|
161
|
-
if (value.includes(" ") || value.includes('"') || value.includes("=")) {
|
|
162
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
163
|
-
}
|
|
164
|
-
return value;
|
|
165
|
-
}
|
|
166
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
167
|
-
return String(value);
|
|
168
|
-
}
|
|
169
|
-
if (value instanceof Error) {
|
|
170
|
-
return `"${value.message.replace(/"/g, '\\"')}"`;
|
|
171
|
-
}
|
|
172
|
-
if (Array.isArray(value)) {
|
|
173
|
-
return `"${JSON.stringify(value).replace(/"/g, '\\"')}"`;
|
|
174
|
-
}
|
|
175
|
-
return `"${JSON.stringify(value).replace(/"/g, '\\"')}"`;
|
|
176
|
-
}
|
|
177
|
-
function formatLogfmt(data) {
|
|
178
|
-
const flattened = flattenObject(data);
|
|
179
|
-
return Object.entries(flattened).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${formatLogfmtValue(value)}`).join(" ");
|
|
180
|
-
}
|
|
181
|
-
function addStoreContext(store) {
|
|
182
|
-
return format((info) => {
|
|
183
|
-
const storeContext = store.getStore();
|
|
184
|
-
if (storeContext) {
|
|
185
|
-
return { ...info, ...storeContext };
|
|
186
|
-
}
|
|
187
|
-
return info;
|
|
188
|
-
})();
|
|
189
|
-
}
|
|
190
|
-
function maskSecretsFormat(options) {
|
|
191
|
-
return format((info) => {
|
|
192
|
-
return maskSecrets(info, options);
|
|
193
|
-
})();
|
|
194
|
-
}
|
|
195
|
-
function createFilterFormat(defaultLevel, rules, store) {
|
|
196
|
-
if (!rules?.length && defaultLevel === void 0) {
|
|
197
|
-
return format((info) => info)();
|
|
198
|
-
}
|
|
199
|
-
return format((info) => {
|
|
200
|
-
const logLevel = info.level;
|
|
201
|
-
const context = info.context;
|
|
202
|
-
const storeContext = store.getStore();
|
|
203
|
-
const matchingRule = rules?.find((rule) => matchesContext(storeContext, context, rule.match));
|
|
204
|
-
const effectiveLevel = matchingRule?.level ?? defaultLevel ?? "silly";
|
|
205
|
-
if (effectiveLevel === "off") return false;
|
|
206
|
-
return LOG_LEVELS[logLevel] <= LOG_LEVELS[effectiveLevel] ? info : false;
|
|
207
|
-
})();
|
|
208
|
-
}
|
|
209
|
-
function createPlainFormat(store) {
|
|
210
|
-
return format.combine(
|
|
211
|
-
format.errors({ stack: true }),
|
|
212
|
-
format.timestamp(),
|
|
213
|
-
addStoreContext(store),
|
|
214
|
-
maskSecretsFormat(),
|
|
215
|
-
format.printf(({ timestamp, level, context, message, ...meta }) => {
|
|
216
|
-
const formattedMeta = formatMeta(meta, true);
|
|
217
|
-
const coloredLevel = colorizeLevel(level);
|
|
218
|
-
return `[${timestamp}] ${coloredLevel} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;
|
|
219
|
-
})
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
function createJsonFormat(store) {
|
|
223
|
-
return format.combine(
|
|
224
|
-
format.errors({ stack: true }),
|
|
225
|
-
format.timestamp(),
|
|
226
|
-
addStoreContext(store),
|
|
227
|
-
maskSecretsFormat(),
|
|
228
|
-
format.json()
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
function createLogfmtFormat(store) {
|
|
232
|
-
return format.combine(
|
|
233
|
-
format.errors({ stack: true }),
|
|
234
|
-
format.timestamp(),
|
|
235
|
-
addStoreContext(store),
|
|
236
|
-
maskSecretsFormat(),
|
|
237
|
-
format.printf(({ timestamp, level, context, message, ...meta }) => {
|
|
238
|
-
const data = {
|
|
239
|
-
level,
|
|
240
|
-
msg: message,
|
|
241
|
-
context: context || DEFAULT_CONTEXT,
|
|
242
|
-
ts: timestamp,
|
|
243
|
-
...meta
|
|
244
|
-
};
|
|
245
|
-
return formatLogfmt(data);
|
|
246
|
-
})
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
function createSimpleFormat(store) {
|
|
250
|
-
return format.combine(
|
|
251
|
-
format.errors({ stack: true }),
|
|
252
|
-
format.timestamp(),
|
|
253
|
-
addStoreContext(store),
|
|
254
|
-
maskSecretsFormat(),
|
|
255
|
-
format.printf(({ timestamp, level, message }) => {
|
|
256
|
-
return `[${timestamp}] ${level}: ${message}`;
|
|
257
|
-
})
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
function createFormat(logFormat, store) {
|
|
261
|
-
switch (logFormat) {
|
|
262
|
-
case "plain":
|
|
263
|
-
return createPlainFormat(store);
|
|
264
|
-
case "json":
|
|
265
|
-
return createJsonFormat(store);
|
|
266
|
-
case "logfmt":
|
|
267
|
-
return createLogfmtFormat(store);
|
|
268
|
-
case "simple":
|
|
269
|
-
return createSimpleFormat(store);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
42
|
// src/transports/buffer.ts
|
|
274
43
|
var MessageBuffer = class {
|
|
275
44
|
constructor(options) {
|
|
@@ -351,7 +120,7 @@ var DEFAULT_OPTIONS = {
|
|
|
351
120
|
maxRetries: 3,
|
|
352
121
|
retryDelay: 1e3
|
|
353
122
|
};
|
|
354
|
-
var BaseHttpTransport = class extends
|
|
123
|
+
var BaseHttpTransport = class extends EventEmitter {
|
|
355
124
|
buffer;
|
|
356
125
|
constructor(opts = {}) {
|
|
357
126
|
super();
|
|
@@ -377,7 +146,7 @@ var BaseHttpTransport = class extends TransportStream {
|
|
|
377
146
|
return {
|
|
378
147
|
level,
|
|
379
148
|
message: String(message),
|
|
380
|
-
timestamp: timestamp ? new Date(String(timestamp)) : /* @__PURE__ */ new Date(),
|
|
149
|
+
timestamp: timestamp instanceof Date ? timestamp : timestamp ? new Date(String(timestamp)) : /* @__PURE__ */ new Date(),
|
|
381
150
|
context,
|
|
382
151
|
meta: Object.keys(meta).length > 0 ? meta : void 0
|
|
383
152
|
};
|
|
@@ -402,6 +171,16 @@ var DEFAULT_EMBED_COLORS = {
|
|
|
402
171
|
debug: 3447003,
|
|
403
172
|
silly: 9807270
|
|
404
173
|
};
|
|
174
|
+
var LEVEL_EMOJI = {
|
|
175
|
+
off: "\u26AB",
|
|
176
|
+
error: "\u{1F534}",
|
|
177
|
+
warn: "\u{1F7E1}",
|
|
178
|
+
info: "\u{1F7E2}",
|
|
179
|
+
http: "\u{1F535}",
|
|
180
|
+
verbose: "\u{1F7E3}",
|
|
181
|
+
debug: "\u26AA",
|
|
182
|
+
silly: "\u26AB"
|
|
183
|
+
};
|
|
405
184
|
var DiscordTransport = class extends BaseHttpTransport {
|
|
406
185
|
config;
|
|
407
186
|
constructor(config) {
|
|
@@ -414,6 +193,13 @@ var DiscordTransport = class extends BaseHttpTransport {
|
|
|
414
193
|
this.config = config;
|
|
415
194
|
}
|
|
416
195
|
async sendBatch(messages) {
|
|
196
|
+
if (this.config.format === "markdown") {
|
|
197
|
+
await this.sendMarkdownBatch(messages);
|
|
198
|
+
} else {
|
|
199
|
+
await this.sendEmbedBatch(messages);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async sendEmbedBatch(messages) {
|
|
417
203
|
const chunks = this.chunkArray(messages, 10);
|
|
418
204
|
for (const chunk of chunks) {
|
|
419
205
|
const payload = {
|
|
@@ -424,6 +210,51 @@ var DiscordTransport = class extends BaseHttpTransport {
|
|
|
424
210
|
await this.sendWebhook(payload);
|
|
425
211
|
}
|
|
426
212
|
}
|
|
213
|
+
async sendMarkdownBatch(messages) {
|
|
214
|
+
const content = messages.map((msg) => this.formatMarkdown(msg)).join("\n\n---\n\n");
|
|
215
|
+
const chunks = this.splitContent(content, 1900);
|
|
216
|
+
for (const chunk of chunks) {
|
|
217
|
+
const payload = {
|
|
218
|
+
username: this.config.username,
|
|
219
|
+
avatar_url: this.config.avatarUrl,
|
|
220
|
+
content: chunk
|
|
221
|
+
};
|
|
222
|
+
await this.sendWebhook(payload);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
formatMarkdown(msg) {
|
|
226
|
+
const emoji = LEVEL_EMOJI[msg.level];
|
|
227
|
+
const level = msg.level.toUpperCase();
|
|
228
|
+
const context = msg.context || "APP";
|
|
229
|
+
const timestamp = this.config.includeTimestamp !== false ? `\`${msg.timestamp.toISOString()}\`` : "";
|
|
230
|
+
let text = `${emoji} **${level}** [${context}] ${timestamp}
|
|
231
|
+
${msg.message}`;
|
|
232
|
+
if (this.config.includeMeta !== false && msg.meta && Object.keys(msg.meta).length > 0) {
|
|
233
|
+
text += "\n```json\n" + JSON.stringify(msg.meta, null, 2) + "\n```";
|
|
234
|
+
}
|
|
235
|
+
return text;
|
|
236
|
+
}
|
|
237
|
+
splitContent(content, maxLength) {
|
|
238
|
+
if (content.length <= maxLength) return [content];
|
|
239
|
+
const chunks = [];
|
|
240
|
+
let current = content;
|
|
241
|
+
while (current.length > 0) {
|
|
242
|
+
if (current.length <= maxLength) {
|
|
243
|
+
chunks.push(current);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
let splitAt = current.lastIndexOf("\n", maxLength);
|
|
247
|
+
if (splitAt === -1 || splitAt < maxLength / 2) {
|
|
248
|
+
splitAt = current.lastIndexOf(" ", maxLength);
|
|
249
|
+
}
|
|
250
|
+
if (splitAt === -1 || splitAt < maxLength / 2) {
|
|
251
|
+
splitAt = maxLength;
|
|
252
|
+
}
|
|
253
|
+
chunks.push(current.slice(0, splitAt));
|
|
254
|
+
current = current.slice(splitAt).trimStart();
|
|
255
|
+
}
|
|
256
|
+
return chunks;
|
|
257
|
+
}
|
|
427
258
|
createEmbed(msg) {
|
|
428
259
|
const color = this.config.embedColors?.[msg.level] ?? DEFAULT_EMBED_COLORS[msg.level];
|
|
429
260
|
const embed = {
|
|
@@ -480,7 +311,7 @@ var DiscordTransport = class extends BaseHttpTransport {
|
|
|
480
311
|
};
|
|
481
312
|
|
|
482
313
|
// src/transports/telegram.ts
|
|
483
|
-
var
|
|
314
|
+
var LEVEL_EMOJI2 = {
|
|
484
315
|
off: "",
|
|
485
316
|
error: "\u{1F534}",
|
|
486
317
|
warn: "\u{1F7E1}",
|
|
@@ -508,7 +339,7 @@ var TelegramTransport = class extends BaseHttpTransport {
|
|
|
508
339
|
await this.sendMessage(text, messages);
|
|
509
340
|
}
|
|
510
341
|
formatBatchMessage(messages) {
|
|
511
|
-
const parseMode = this.config.parseMode ?? "
|
|
342
|
+
const parseMode = this.config.parseMode ?? "HTML";
|
|
512
343
|
return messages.map((msg) => {
|
|
513
344
|
if (parseMode === "HTML") {
|
|
514
345
|
return this.formatHtml(msg);
|
|
@@ -517,9 +348,10 @@ var TelegramTransport = class extends BaseHttpTransport {
|
|
|
517
348
|
}).join("\n\n---\n\n");
|
|
518
349
|
}
|
|
519
350
|
formatMarkdown(msg, v2) {
|
|
520
|
-
const emoji =
|
|
351
|
+
const emoji = LEVEL_EMOJI2[msg.level];
|
|
521
352
|
const escape = v2 ? this.escapeMarkdownV2.bind(this) : (s) => s;
|
|
522
|
-
|
|
353
|
+
const bracket = v2 ? ["\\[", "\\]"] : ["[", "]"];
|
|
354
|
+
let text = `${emoji} *${msg.level.toUpperCase()}* ${bracket[0]}${escape(msg.context || "APP")}${bracket[1]}
|
|
523
355
|
`;
|
|
524
356
|
text += escape(msg.message);
|
|
525
357
|
if (msg.meta && Object.keys(msg.meta).length > 0) {
|
|
@@ -529,7 +361,7 @@ var TelegramTransport = class extends BaseHttpTransport {
|
|
|
529
361
|
return text;
|
|
530
362
|
}
|
|
531
363
|
formatHtml(msg) {
|
|
532
|
-
const emoji =
|
|
364
|
+
const emoji = LEVEL_EMOJI2[msg.level];
|
|
533
365
|
let text = `${emoji} <b>${msg.level.toUpperCase()}</b> [${this.escapeHtml(msg.context || "APP")}]
|
|
534
366
|
`;
|
|
535
367
|
text += this.escapeHtml(msg.message);
|
|
@@ -549,7 +381,7 @@ var TelegramTransport = class extends BaseHttpTransport {
|
|
|
549
381
|
const body = {
|
|
550
382
|
chat_id: this.config.chatId,
|
|
551
383
|
text,
|
|
552
|
-
parse_mode: this.config.parseMode ?? "
|
|
384
|
+
parse_mode: this.config.parseMode ?? "HTML",
|
|
553
385
|
disable_notification: this.shouldMute(messages)
|
|
554
386
|
};
|
|
555
387
|
if (this.config.threadId) {
|
|
@@ -704,85 +536,224 @@ var CloudWatchTransport = class extends BaseHttpTransport {
|
|
|
704
536
|
}
|
|
705
537
|
};
|
|
706
538
|
|
|
707
|
-
// src/
|
|
708
|
-
function
|
|
709
|
-
|
|
710
|
-
|
|
539
|
+
// src/streams.ts
|
|
540
|
+
function parseLogLine(line) {
|
|
541
|
+
try {
|
|
542
|
+
return JSON.parse(line);
|
|
543
|
+
} catch {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
function getLevelName(levelNum) {
|
|
548
|
+
if (levelNum >= 50) return "error";
|
|
549
|
+
if (levelNum >= 40) return "warn";
|
|
550
|
+
if (levelNum >= 30) return "info";
|
|
551
|
+
if (levelNum >= 25) return "http";
|
|
552
|
+
if (levelNum >= 20) return "debug";
|
|
553
|
+
return "silly";
|
|
554
|
+
}
|
|
555
|
+
function shouldPassTransport(log, level, rules, store) {
|
|
556
|
+
const logLevel = getLevelName(log.level);
|
|
557
|
+
const context = log.context;
|
|
558
|
+
const storeContext = store.getStore();
|
|
559
|
+
const matchingRule = rules?.find((rule) => matchesContext(storeContext, context, rule.match));
|
|
560
|
+
const effectiveLevel = matchingRule?.level ?? level ?? "silly";
|
|
561
|
+
if (effectiveLevel === "off") return false;
|
|
562
|
+
return LOG_LEVELS[logLevel] <= LOG_LEVELS[effectiveLevel];
|
|
563
|
+
}
|
|
564
|
+
function formatLog(log, format, store) {
|
|
565
|
+
const levelName = getLevelName(log.level);
|
|
566
|
+
const timestamp = new Date(log.time).toISOString();
|
|
567
|
+
const context = log.context || "APP";
|
|
568
|
+
const message = log.msg || "";
|
|
569
|
+
const storeContext = store.getStore();
|
|
570
|
+
const meta = {};
|
|
571
|
+
for (const [key, value] of Object.entries(log)) {
|
|
572
|
+
if (!["level", "time", "msg", "context"].includes(key)) {
|
|
573
|
+
meta[key] = value;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (storeContext) {
|
|
577
|
+
Object.assign(meta, storeContext);
|
|
578
|
+
}
|
|
579
|
+
if (format === "json") {
|
|
580
|
+
return JSON.stringify({
|
|
581
|
+
level: levelName,
|
|
582
|
+
timestamp,
|
|
583
|
+
context,
|
|
584
|
+
message,
|
|
585
|
+
...meta
|
|
586
|
+
}) + "\n";
|
|
587
|
+
}
|
|
588
|
+
if (format === "plain") {
|
|
589
|
+
const LEVEL_COLORS = {
|
|
590
|
+
error: "\x1B[31m",
|
|
591
|
+
warn: "\x1B[33m",
|
|
592
|
+
info: "\x1B[32m",
|
|
593
|
+
http: "\x1B[35m",
|
|
594
|
+
verbose: "\x1B[36m",
|
|
595
|
+
debug: "\x1B[34m",
|
|
596
|
+
silly: "\x1B[90m"
|
|
597
|
+
};
|
|
598
|
+
const RESET = "\x1B[0m";
|
|
599
|
+
const color = LEVEL_COLORS[levelName] || "";
|
|
600
|
+
const coloredLevel = color ? `${color}${levelName}${RESET}` : levelName;
|
|
601
|
+
const metaStr = Object.keys(meta).length > 0 ? "\n " + Object.entries(meta).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join("\n ") : "";
|
|
602
|
+
return `[${timestamp}] ${coloredLevel} [${context}] ${message}${metaStr}
|
|
603
|
+
`;
|
|
604
|
+
}
|
|
605
|
+
if (format === "logfmt") {
|
|
606
|
+
const parts = [`level=${levelName}`, `msg="${message}"`, `context=${context}`, `ts=${timestamp}`];
|
|
607
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
608
|
+
parts.push(`${k}=${JSON.stringify(v)}`);
|
|
609
|
+
}
|
|
610
|
+
return parts.join(" ") + "\n";
|
|
611
|
+
}
|
|
612
|
+
return `[${timestamp}] ${levelName}: ${message}
|
|
613
|
+
`;
|
|
711
614
|
}
|
|
712
|
-
function
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
615
|
+
function createFormattedFilterStream(format, level, rules, store, destination) {
|
|
616
|
+
return new Transform({
|
|
617
|
+
transform(chunk, _encoding, callback) {
|
|
618
|
+
const line = chunk.toString().trim();
|
|
619
|
+
if (!line) {
|
|
620
|
+
callback();
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const log = parseLogLine(line);
|
|
624
|
+
if (!log) {
|
|
625
|
+
callback();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
if (!shouldPassTransport(log, level, rules, store)) {
|
|
629
|
+
callback();
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
const formatted = formatLog(log, format, store);
|
|
633
|
+
destination.write(formatted);
|
|
634
|
+
callback();
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
function createStreams(config, store) {
|
|
639
|
+
const streams = [];
|
|
640
|
+
const consoleStream = createFormattedFilterStream(
|
|
641
|
+
config.console.format,
|
|
642
|
+
config.console.level,
|
|
643
|
+
config.console.rules,
|
|
644
|
+
store,
|
|
645
|
+
process.stdout
|
|
646
|
+
);
|
|
647
|
+
streams.push({
|
|
648
|
+
level: "trace",
|
|
649
|
+
stream: consoleStream
|
|
650
|
+
});
|
|
721
651
|
if (config.file) {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
)
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
652
|
+
const fileConfig = config.file;
|
|
653
|
+
mkdir(fileConfig.dirname, { recursive: true }).catch(() => {
|
|
654
|
+
});
|
|
655
|
+
const rotatingStream = createStream(
|
|
656
|
+
(time, index) => {
|
|
657
|
+
const date = time instanceof Date ? time : /* @__PURE__ */ new Date();
|
|
658
|
+
const dateStr = date.toISOString().split("T")[0];
|
|
659
|
+
const base = fileConfig.filename.replace(".log", "");
|
|
660
|
+
return `${base}-${dateStr}${index ? `.${index}` : ""}.log`;
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
path: fileConfig.dirname,
|
|
664
|
+
size: fileConfig.maxSize || "20M",
|
|
665
|
+
interval: fileConfig.datePattern === "YYYY-MM-DD-HH" ? "1h" : "1d",
|
|
666
|
+
compress: fileConfig.zippedArchive ? "gzip" : false,
|
|
667
|
+
maxFiles: parseInt(fileConfig.maxFiles?.replace("d", "") || "14")
|
|
668
|
+
}
|
|
735
669
|
);
|
|
670
|
+
const fileStream = createFormattedFilterStream(
|
|
671
|
+
fileConfig.format,
|
|
672
|
+
fileConfig.level,
|
|
673
|
+
fileConfig.rules,
|
|
674
|
+
store,
|
|
675
|
+
rotatingStream
|
|
676
|
+
);
|
|
677
|
+
streams.push({
|
|
678
|
+
level: "trace",
|
|
679
|
+
stream: fileStream
|
|
680
|
+
});
|
|
736
681
|
}
|
|
737
682
|
for (const discordConfig of toArray(config.discord)) {
|
|
738
|
-
const
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
683
|
+
const transport = new DiscordTransport(discordConfig);
|
|
684
|
+
const discordStream = createHttpTransportStream(transport, discordConfig.level, discordConfig.rules, store);
|
|
685
|
+
streams.push({
|
|
686
|
+
level: "trace",
|
|
687
|
+
stream: discordStream
|
|
688
|
+
});
|
|
744
689
|
}
|
|
745
690
|
for (const telegramConfig of toArray(config.telegram)) {
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
691
|
+
const transport = new TelegramTransport(telegramConfig);
|
|
692
|
+
const telegramStream = createHttpTransportStream(transport, telegramConfig.level, telegramConfig.rules, store);
|
|
693
|
+
streams.push({
|
|
694
|
+
level: "trace",
|
|
695
|
+
stream: telegramStream
|
|
696
|
+
});
|
|
752
697
|
}
|
|
753
698
|
for (const cloudwatchConfig of toArray(config.cloudwatch)) {
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
699
|
+
const transport = new CloudWatchTransport(cloudwatchConfig);
|
|
700
|
+
const cwStream = createHttpTransportStream(transport, cloudwatchConfig.level, cloudwatchConfig.rules, store);
|
|
701
|
+
streams.push({
|
|
702
|
+
level: "trace",
|
|
703
|
+
stream: cwStream
|
|
704
|
+
});
|
|
760
705
|
}
|
|
761
|
-
return
|
|
706
|
+
return pino.multistream(streams);
|
|
762
707
|
}
|
|
763
|
-
function
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
708
|
+
function toArray(value) {
|
|
709
|
+
if (!value) return [];
|
|
710
|
+
return Array.isArray(value) ? value : [value];
|
|
711
|
+
}
|
|
712
|
+
function createHttpTransportStream(transport, level, rules, store) {
|
|
713
|
+
return new Writable({
|
|
714
|
+
write(chunk, _encoding, callback) {
|
|
715
|
+
const line = chunk.toString().trim();
|
|
716
|
+
if (!line) {
|
|
717
|
+
callback();
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const log = parseLogLine(line);
|
|
721
|
+
if (!log) {
|
|
722
|
+
callback();
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (!shouldPassTransport(log, level, rules, store)) {
|
|
726
|
+
callback();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
const levelName = getLevelName(log.level);
|
|
730
|
+
const storeContext = store.getStore();
|
|
731
|
+
const meta = {};
|
|
732
|
+
for (const [key, value] of Object.entries(log)) {
|
|
733
|
+
if (!["level", "time", "msg", "context"].includes(key)) {
|
|
734
|
+
meta[key] = value;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (storeContext) {
|
|
738
|
+
Object.assign(meta, storeContext);
|
|
739
|
+
}
|
|
740
|
+
transport.log({
|
|
741
|
+
level: levelName,
|
|
742
|
+
message: log.msg || "",
|
|
743
|
+
context: log.context,
|
|
744
|
+
timestamp: new Date(log.time),
|
|
745
|
+
...meta
|
|
746
|
+
}, callback);
|
|
747
|
+
}
|
|
748
|
+
});
|
|
783
749
|
}
|
|
784
750
|
|
|
785
751
|
// src/state.ts
|
|
752
|
+
var CUSTOM_LEVELS = {
|
|
753
|
+
http: 25,
|
|
754
|
+
verbose: 25,
|
|
755
|
+
silly: 10
|
|
756
|
+
};
|
|
786
757
|
function parseLevelConfig(level) {
|
|
787
758
|
if (typeof level === "string") {
|
|
788
759
|
assertLogLevel(level);
|
|
@@ -795,37 +766,64 @@ function parseLevelConfig(level) {
|
|
|
795
766
|
});
|
|
796
767
|
return { defaultLevel: level.default, rules };
|
|
797
768
|
}
|
|
769
|
+
function buildIndexes(overrides) {
|
|
770
|
+
const contextIndex = /* @__PURE__ */ new Map();
|
|
771
|
+
const complexRules = [];
|
|
772
|
+
for (const override of overrides.values()) {
|
|
773
|
+
const keys = Object.keys(override.match);
|
|
774
|
+
if (keys.length === 1 && keys[0] === "context" && typeof override.match.context === "string") {
|
|
775
|
+
contextIndex.set(override.match.context, override);
|
|
776
|
+
} else {
|
|
777
|
+
complexRules.push(override);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return { contextIndex, complexRules };
|
|
781
|
+
}
|
|
798
782
|
function createState(config, store) {
|
|
799
783
|
const { defaultLevel, rules } = parseLevelConfig(config.level);
|
|
800
784
|
const loggerStore = store ?? new LoggerStore();
|
|
801
|
-
const exceptionHandlers = createExceptionHandlers(config, loggerStore);
|
|
802
|
-
const winston = createLogger({
|
|
803
|
-
level: "silly",
|
|
804
|
-
// Accept all, we filter in shouldLog()
|
|
805
|
-
transports: createTransports(config, loggerStore),
|
|
806
|
-
exceptionHandlers,
|
|
807
|
-
rejectionHandlers: exceptionHandlers,
|
|
808
|
-
exitOnError: false
|
|
809
|
-
});
|
|
810
785
|
const levelOverrides = /* @__PURE__ */ new Map();
|
|
811
786
|
for (const rule of rules) {
|
|
812
787
|
const key = JSON.stringify(rule.match);
|
|
813
788
|
levelOverrides.set(key, rule);
|
|
814
789
|
}
|
|
790
|
+
const { contextIndex, complexRules } = buildIndexes(levelOverrides);
|
|
791
|
+
const streams = createStreams(config, loggerStore);
|
|
792
|
+
const options = {
|
|
793
|
+
level: "trace",
|
|
794
|
+
// Accept all, we filter in shouldLog()
|
|
795
|
+
customLevels: CUSTOM_LEVELS,
|
|
796
|
+
base: void 0
|
|
797
|
+
// Disable pid and hostname
|
|
798
|
+
};
|
|
799
|
+
const pinoLogger = pino(options, streams);
|
|
815
800
|
return {
|
|
816
|
-
|
|
801
|
+
pino: pinoLogger,
|
|
817
802
|
store: loggerStore,
|
|
818
803
|
defaultLevel,
|
|
819
|
-
levelOverrides
|
|
804
|
+
levelOverrides,
|
|
805
|
+
contextIndex,
|
|
806
|
+
complexRules
|
|
820
807
|
};
|
|
821
808
|
}
|
|
809
|
+
function rebuildIndexes(state) {
|
|
810
|
+
const { contextIndex, complexRules } = buildIndexes(state.levelOverrides);
|
|
811
|
+
state.contextIndex = contextIndex;
|
|
812
|
+
state.complexRules.length = 0;
|
|
813
|
+
state.complexRules.push(...complexRules);
|
|
814
|
+
}
|
|
822
815
|
function shouldLog(state, level, context) {
|
|
823
816
|
const effectiveLevel = getEffectiveLevel(state, context);
|
|
817
|
+
if (effectiveLevel === "off") return false;
|
|
824
818
|
return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];
|
|
825
819
|
}
|
|
826
820
|
function getEffectiveLevel(state, loggerContext) {
|
|
821
|
+
if (loggerContext) {
|
|
822
|
+
const indexed = state.contextIndex.get(loggerContext);
|
|
823
|
+
if (indexed) return indexed.level;
|
|
824
|
+
}
|
|
827
825
|
const storeContext = state.store.getStore();
|
|
828
|
-
for (const { match, level } of state.
|
|
826
|
+
for (const { match, level } of state.complexRules) {
|
|
829
827
|
if (matchesContext(storeContext, loggerContext, match)) {
|
|
830
828
|
return level;
|
|
831
829
|
}
|
|
@@ -883,6 +881,7 @@ var DiscordConfigSchema = z.object({
|
|
|
883
881
|
maxRetries: z.number().int().nonnegative().optional(),
|
|
884
882
|
retryDelay: z.number().int().positive().optional(),
|
|
885
883
|
webhookUrl: z.string().url("webhookUrl must be a valid URL"),
|
|
884
|
+
format: z.enum(["embed", "markdown"]).optional(),
|
|
886
885
|
username: z.string().optional(),
|
|
887
886
|
avatarUrl: z.string().url().optional(),
|
|
888
887
|
embedColors: z.record(z.string(), z.number().int()).optional(),
|
|
@@ -948,6 +947,7 @@ var Logger = class _Logger {
|
|
|
948
947
|
this.state = state;
|
|
949
948
|
this.context = context;
|
|
950
949
|
}
|
|
950
|
+
profileTimers = /* @__PURE__ */ new Map();
|
|
951
951
|
static create(config, store) {
|
|
952
952
|
const validatedConfig = validateConfig(config);
|
|
953
953
|
const state = createState(validatedConfig, store);
|
|
@@ -964,6 +964,7 @@ var Logger = class _Logger {
|
|
|
964
964
|
assertLogLevel(level);
|
|
965
965
|
const key = JSON.stringify(match);
|
|
966
966
|
this.state.levelOverrides.set(key, { match, level });
|
|
967
|
+
rebuildIndexes(this.state);
|
|
967
968
|
}
|
|
968
969
|
removeLevelOverride(match) {
|
|
969
970
|
const key = JSON.stringify(match);
|
|
@@ -971,26 +972,50 @@ var Logger = class _Logger {
|
|
|
971
972
|
if (override?.readonly) {
|
|
972
973
|
return false;
|
|
973
974
|
}
|
|
974
|
-
|
|
975
|
+
const deleted = this.state.levelOverrides.delete(key);
|
|
976
|
+
if (deleted) {
|
|
977
|
+
rebuildIndexes(this.state);
|
|
978
|
+
}
|
|
979
|
+
return deleted;
|
|
975
980
|
}
|
|
976
981
|
clearLevelOverrides() {
|
|
982
|
+
let changed = false;
|
|
977
983
|
for (const [key, override] of this.state.levelOverrides) {
|
|
978
984
|
if (!override.readonly) {
|
|
979
985
|
this.state.levelOverrides.delete(key);
|
|
986
|
+
changed = true;
|
|
980
987
|
}
|
|
981
988
|
}
|
|
989
|
+
if (changed) {
|
|
990
|
+
rebuildIndexes(this.state);
|
|
991
|
+
}
|
|
982
992
|
}
|
|
983
993
|
getLevelOverrides() {
|
|
984
994
|
return Array.from(this.state.levelOverrides.values());
|
|
985
995
|
}
|
|
986
996
|
// Profiling
|
|
987
997
|
profile(id, meta) {
|
|
988
|
-
this.
|
|
998
|
+
const existing = this.profileTimers.get(id);
|
|
999
|
+
if (existing) {
|
|
1000
|
+
const duration = Date.now() - existing;
|
|
1001
|
+
this.profileTimers.delete(id);
|
|
1002
|
+
this.info(`${id} completed`, { ...meta, durationMs: duration });
|
|
1003
|
+
} else {
|
|
1004
|
+
this.profileTimers.set(id, Date.now());
|
|
1005
|
+
}
|
|
989
1006
|
}
|
|
990
1007
|
// Logging methods
|
|
991
|
-
error(
|
|
1008
|
+
error(errorOrMessage, messageOrMeta, meta) {
|
|
992
1009
|
if (!shouldLog(this.state, "error", this.context)) return;
|
|
993
|
-
|
|
1010
|
+
if (errorOrMessage instanceof Error) {
|
|
1011
|
+
if (typeof messageOrMeta === "string") {
|
|
1012
|
+
this.log("error", messageOrMeta, meta, errorOrMessage);
|
|
1013
|
+
} else {
|
|
1014
|
+
this.log("error", errorOrMessage.message, messageOrMeta, errorOrMessage);
|
|
1015
|
+
}
|
|
1016
|
+
} else {
|
|
1017
|
+
this.log("error", errorOrMessage, messageOrMeta);
|
|
1018
|
+
}
|
|
994
1019
|
}
|
|
995
1020
|
warn(message, meta) {
|
|
996
1021
|
if (!shouldLog(this.state, "warn", this.context)) return;
|
|
@@ -1020,13 +1045,41 @@ var Logger = class _Logger {
|
|
|
1020
1045
|
log(level, message, meta, error) {
|
|
1021
1046
|
const resolved = typeof meta === "function" ? meta() : meta;
|
|
1022
1047
|
const logMeta = { context: this.context, ...resolved };
|
|
1048
|
+
const storeContext = this.state.store.getStore();
|
|
1049
|
+
if (storeContext) {
|
|
1050
|
+
Object.assign(logMeta, storeContext);
|
|
1051
|
+
}
|
|
1023
1052
|
if (error instanceof Error) {
|
|
1024
1053
|
logMeta.errorMessage = error.message;
|
|
1025
1054
|
logMeta.stack = error.stack;
|
|
1026
1055
|
} else if (error !== void 0) {
|
|
1027
1056
|
logMeta.error = error;
|
|
1028
1057
|
}
|
|
1029
|
-
this.
|
|
1058
|
+
const pinoMethod = this.getPinoMethod(level);
|
|
1059
|
+
pinoMethod.call(this.state.pino, logMeta, message);
|
|
1060
|
+
}
|
|
1061
|
+
getPinoMethod(level) {
|
|
1062
|
+
switch (level) {
|
|
1063
|
+
case "error":
|
|
1064
|
+
return this.state.pino.error.bind(this.state.pino);
|
|
1065
|
+
case "warn":
|
|
1066
|
+
return this.state.pino.warn.bind(this.state.pino);
|
|
1067
|
+
case "info":
|
|
1068
|
+
return this.state.pino.info.bind(this.state.pino);
|
|
1069
|
+
case "http":
|
|
1070
|
+
case "verbose":
|
|
1071
|
+
return (obj, msg) => {
|
|
1072
|
+
this.state.pino[level](obj, msg);
|
|
1073
|
+
};
|
|
1074
|
+
case "debug":
|
|
1075
|
+
return this.state.pino.debug.bind(this.state.pino);
|
|
1076
|
+
case "silly":
|
|
1077
|
+
return (obj, msg) => {
|
|
1078
|
+
this.state.pino.silly(obj, msg);
|
|
1079
|
+
};
|
|
1080
|
+
default:
|
|
1081
|
+
return this.state.pino.info.bind(this.state.pino);
|
|
1082
|
+
}
|
|
1030
1083
|
}
|
|
1031
1084
|
};
|
|
1032
1085
|
|
|
@@ -1130,6 +1183,114 @@ function getOrGenerateRequestId(headers, options = {}) {
|
|
|
1130
1183
|
return extractRequestId(headers) ?? generateRequestId(options);
|
|
1131
1184
|
}
|
|
1132
1185
|
|
|
1186
|
+
// src/utils/mask-secrets.ts
|
|
1187
|
+
var DEFAULT_SECRET_PATTERNS = [
|
|
1188
|
+
"password",
|
|
1189
|
+
"secret",
|
|
1190
|
+
"token",
|
|
1191
|
+
"apikey",
|
|
1192
|
+
"api_key",
|
|
1193
|
+
"api-key",
|
|
1194
|
+
"auth",
|
|
1195
|
+
"credential",
|
|
1196
|
+
"private"
|
|
1197
|
+
];
|
|
1198
|
+
var DEFAULT_MASK = "***";
|
|
1199
|
+
function isSecretKey(key, patterns) {
|
|
1200
|
+
const lowerKey = key.toLowerCase();
|
|
1201
|
+
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
1202
|
+
}
|
|
1203
|
+
function maskUrlCredentials(url, mask) {
|
|
1204
|
+
try {
|
|
1205
|
+
const parsed = new URL(url);
|
|
1206
|
+
if (parsed.password) {
|
|
1207
|
+
parsed.password = mask;
|
|
1208
|
+
}
|
|
1209
|
+
if (parsed.username && parsed.password) {
|
|
1210
|
+
parsed.username = mask;
|
|
1211
|
+
}
|
|
1212
|
+
return parsed.toString();
|
|
1213
|
+
} catch {
|
|
1214
|
+
return url;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
function maskSecrets(obj, options = {}) {
|
|
1218
|
+
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
1219
|
+
if (obj === null || obj === void 0) {
|
|
1220
|
+
return obj;
|
|
1221
|
+
}
|
|
1222
|
+
if (typeof obj === "string") {
|
|
1223
|
+
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
1224
|
+
return maskUrlCredentials(obj, mask);
|
|
1225
|
+
}
|
|
1226
|
+
return obj;
|
|
1227
|
+
}
|
|
1228
|
+
if (Array.isArray(obj)) {
|
|
1229
|
+
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
1230
|
+
}
|
|
1231
|
+
if (typeof obj === "object") {
|
|
1232
|
+
const result = {};
|
|
1233
|
+
for (const sym of Object.getOwnPropertySymbols(obj)) {
|
|
1234
|
+
result[sym] = obj[sym];
|
|
1235
|
+
}
|
|
1236
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1237
|
+
if (isSecretKey(key, patterns)) {
|
|
1238
|
+
result[key] = mask;
|
|
1239
|
+
} else if (deep && typeof value === "object" && value !== null) {
|
|
1240
|
+
result[key] = maskSecrets(value, options);
|
|
1241
|
+
} else if (typeof value === "string") {
|
|
1242
|
+
result[key] = maskSecrets(value, options);
|
|
1243
|
+
} else {
|
|
1244
|
+
result[key] = value;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return result;
|
|
1248
|
+
}
|
|
1249
|
+
return obj;
|
|
1250
|
+
}
|
|
1251
|
+
function createMasker(options = {}) {
|
|
1252
|
+
return (obj) => maskSecrets(obj, options);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// src/formatters.ts
|
|
1256
|
+
function flattenObject(obj, prefix = "") {
|
|
1257
|
+
const result = {};
|
|
1258
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1259
|
+
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
1260
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Error)) {
|
|
1261
|
+
Object.assign(result, flattenObject(value, newKey));
|
|
1262
|
+
} else {
|
|
1263
|
+
result[newKey] = value;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return result;
|
|
1267
|
+
}
|
|
1268
|
+
function formatLogfmtValue(value) {
|
|
1269
|
+
if (value === null || value === void 0) {
|
|
1270
|
+
return "";
|
|
1271
|
+
}
|
|
1272
|
+
if (typeof value === "string") {
|
|
1273
|
+
if (value.includes(" ") || value.includes('"') || value.includes("=")) {
|
|
1274
|
+
return `"${value.replace(/"/g, '\\"')}"`;
|
|
1275
|
+
}
|
|
1276
|
+
return value;
|
|
1277
|
+
}
|
|
1278
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1279
|
+
return String(value);
|
|
1280
|
+
}
|
|
1281
|
+
if (value instanceof Error) {
|
|
1282
|
+
return `"${value.message.replace(/"/g, '\\"')}"`;
|
|
1283
|
+
}
|
|
1284
|
+
if (Array.isArray(value)) {
|
|
1285
|
+
return `"${JSON.stringify(value).replace(/"/g, '\\"')}"`;
|
|
1286
|
+
}
|
|
1287
|
+
return `"${JSON.stringify(value).replace(/"/g, '\\"')}"`;
|
|
1288
|
+
}
|
|
1289
|
+
function formatLogfmt(data) {
|
|
1290
|
+
const flattened = flattenObject(data);
|
|
1291
|
+
return Object.entries(flattened).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${formatLogfmtValue(value)}`).join(" ");
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1133
1294
|
export { BaseHttpTransport, CloudWatchConfigSchema, CloudWatchTransport, ConsoleConfigSchema, DiscordConfigSchema, DiscordTransport, FileConfigSchema, HttpTransportBaseConfigSchema, LOG_LEVELS, LevelConfigObjectSchema, LevelConfigSchema, LevelRuleSchema, LogFormatSchema, LogLevelSchema, Logger, LoggerConfigSchema, LoggerStore, MessageBuffer, TelegramConfigSchema, TelegramTransport, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatLogfmt, formatLogfmtValue, generateRequestId, getOrGenerateRequestId, isValidLogLevel, maskSecrets, matchesContext, measureAsync, measureSync, safeValidateConfig, validateConfig };
|
|
1134
1295
|
//# sourceMappingURL=index.mjs.map
|
|
1135
1296
|
//# sourceMappingURL=index.mjs.map
|