@rawnodes/logger 1.10.0 → 2.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/dist/index.d.mts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +494 -328
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +493 -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,230 @@ 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 formatValue = (key, value) => {
|
|
602
|
+
if (typeof value === "string" && value.includes("\n")) {
|
|
603
|
+
return "\n " + value.split("\n").join("\n ");
|
|
604
|
+
}
|
|
605
|
+
return JSON.stringify(value);
|
|
606
|
+
};
|
|
607
|
+
const metaStr = Object.keys(meta).length > 0 ? "\n " + Object.entries(meta).map(([k, v]) => `${k}: ${formatValue(k, v)}`).join("\n ") : "";
|
|
608
|
+
return `[${timestamp}] ${coloredLevel} [${context}] ${message}${metaStr}
|
|
609
|
+
`;
|
|
610
|
+
}
|
|
611
|
+
if (format === "logfmt") {
|
|
612
|
+
const parts = [`level=${levelName}`, `msg="${message}"`, `context=${context}`, `ts=${timestamp}`];
|
|
613
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
614
|
+
parts.push(`${k}=${JSON.stringify(v)}`);
|
|
615
|
+
}
|
|
616
|
+
return parts.join(" ") + "\n";
|
|
617
|
+
}
|
|
618
|
+
return `[${timestamp}] ${levelName}: ${message}
|
|
619
|
+
`;
|
|
711
620
|
}
|
|
712
|
-
function
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
621
|
+
function createFormattedFilterStream(format, level, rules, store, destination) {
|
|
622
|
+
return new Transform({
|
|
623
|
+
transform(chunk, _encoding, callback) {
|
|
624
|
+
const line = chunk.toString().trim();
|
|
625
|
+
if (!line) {
|
|
626
|
+
callback();
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
const log = parseLogLine(line);
|
|
630
|
+
if (!log) {
|
|
631
|
+
callback();
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
if (!shouldPassTransport(log, level, rules, store)) {
|
|
635
|
+
callback();
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const formatted = formatLog(log, format, store);
|
|
639
|
+
destination.write(formatted);
|
|
640
|
+
callback();
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
function createStreams(config, store) {
|
|
645
|
+
const streams = [];
|
|
646
|
+
const consoleStream = createFormattedFilterStream(
|
|
647
|
+
config.console.format,
|
|
648
|
+
config.console.level,
|
|
649
|
+
config.console.rules,
|
|
650
|
+
store,
|
|
651
|
+
process.stdout
|
|
652
|
+
);
|
|
653
|
+
streams.push({
|
|
654
|
+
level: "trace",
|
|
655
|
+
stream: consoleStream
|
|
656
|
+
});
|
|
721
657
|
if (config.file) {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
)
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
658
|
+
const fileConfig = config.file;
|
|
659
|
+
mkdir(fileConfig.dirname, { recursive: true }).catch(() => {
|
|
660
|
+
});
|
|
661
|
+
const rotatingStream = createStream(
|
|
662
|
+
(time, index) => {
|
|
663
|
+
const date = time instanceof Date ? time : /* @__PURE__ */ new Date();
|
|
664
|
+
const dateStr = date.toISOString().split("T")[0];
|
|
665
|
+
const base = fileConfig.filename.replace(".log", "");
|
|
666
|
+
return `${base}-${dateStr}${index ? `.${index}` : ""}.log`;
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
path: fileConfig.dirname,
|
|
670
|
+
size: fileConfig.maxSize || "20M",
|
|
671
|
+
interval: fileConfig.datePattern === "YYYY-MM-DD-HH" ? "1h" : "1d",
|
|
672
|
+
compress: fileConfig.zippedArchive ? "gzip" : false,
|
|
673
|
+
maxFiles: parseInt(fileConfig.maxFiles?.replace("d", "") || "14")
|
|
674
|
+
}
|
|
675
|
+
);
|
|
676
|
+
const fileStream = createFormattedFilterStream(
|
|
677
|
+
fileConfig.format,
|
|
678
|
+
fileConfig.level,
|
|
679
|
+
fileConfig.rules,
|
|
680
|
+
store,
|
|
681
|
+
rotatingStream
|
|
735
682
|
);
|
|
683
|
+
streams.push({
|
|
684
|
+
level: "trace",
|
|
685
|
+
stream: fileStream
|
|
686
|
+
});
|
|
736
687
|
}
|
|
737
688
|
for (const discordConfig of toArray(config.discord)) {
|
|
738
|
-
const
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
689
|
+
const transport = new DiscordTransport(discordConfig);
|
|
690
|
+
const discordStream = createHttpTransportStream(transport, discordConfig.level, discordConfig.rules, store);
|
|
691
|
+
streams.push({
|
|
692
|
+
level: "trace",
|
|
693
|
+
stream: discordStream
|
|
694
|
+
});
|
|
744
695
|
}
|
|
745
696
|
for (const telegramConfig of toArray(config.telegram)) {
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
697
|
+
const transport = new TelegramTransport(telegramConfig);
|
|
698
|
+
const telegramStream = createHttpTransportStream(transport, telegramConfig.level, telegramConfig.rules, store);
|
|
699
|
+
streams.push({
|
|
700
|
+
level: "trace",
|
|
701
|
+
stream: telegramStream
|
|
702
|
+
});
|
|
752
703
|
}
|
|
753
704
|
for (const cloudwatchConfig of toArray(config.cloudwatch)) {
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
705
|
+
const transport = new CloudWatchTransport(cloudwatchConfig);
|
|
706
|
+
const cwStream = createHttpTransportStream(transport, cloudwatchConfig.level, cloudwatchConfig.rules, store);
|
|
707
|
+
streams.push({
|
|
708
|
+
level: "trace",
|
|
709
|
+
stream: cwStream
|
|
710
|
+
});
|
|
760
711
|
}
|
|
761
|
-
return
|
|
712
|
+
return pino.multistream(streams);
|
|
762
713
|
}
|
|
763
|
-
function
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
714
|
+
function toArray(value) {
|
|
715
|
+
if (!value) return [];
|
|
716
|
+
return Array.isArray(value) ? value : [value];
|
|
717
|
+
}
|
|
718
|
+
function createHttpTransportStream(transport, level, rules, store) {
|
|
719
|
+
return new Writable({
|
|
720
|
+
write(chunk, _encoding, callback) {
|
|
721
|
+
const line = chunk.toString().trim();
|
|
722
|
+
if (!line) {
|
|
723
|
+
callback();
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
const log = parseLogLine(line);
|
|
727
|
+
if (!log) {
|
|
728
|
+
callback();
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
if (!shouldPassTransport(log, level, rules, store)) {
|
|
732
|
+
callback();
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const levelName = getLevelName(log.level);
|
|
736
|
+
const storeContext = store.getStore();
|
|
737
|
+
const meta = {};
|
|
738
|
+
for (const [key, value] of Object.entries(log)) {
|
|
739
|
+
if (!["level", "time", "msg", "context"].includes(key)) {
|
|
740
|
+
meta[key] = value;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (storeContext) {
|
|
744
|
+
Object.assign(meta, storeContext);
|
|
745
|
+
}
|
|
746
|
+
transport.log({
|
|
747
|
+
level: levelName,
|
|
748
|
+
message: log.msg || "",
|
|
749
|
+
context: log.context,
|
|
750
|
+
timestamp: new Date(log.time),
|
|
751
|
+
...meta
|
|
752
|
+
}, callback);
|
|
753
|
+
}
|
|
754
|
+
});
|
|
783
755
|
}
|
|
784
756
|
|
|
785
757
|
// src/state.ts
|
|
758
|
+
var CUSTOM_LEVELS = {
|
|
759
|
+
http: 25,
|
|
760
|
+
verbose: 25,
|
|
761
|
+
silly: 10
|
|
762
|
+
};
|
|
786
763
|
function parseLevelConfig(level) {
|
|
787
764
|
if (typeof level === "string") {
|
|
788
765
|
assertLogLevel(level);
|
|
@@ -795,37 +772,64 @@ function parseLevelConfig(level) {
|
|
|
795
772
|
});
|
|
796
773
|
return { defaultLevel: level.default, rules };
|
|
797
774
|
}
|
|
775
|
+
function buildIndexes(overrides) {
|
|
776
|
+
const contextIndex = /* @__PURE__ */ new Map();
|
|
777
|
+
const complexRules = [];
|
|
778
|
+
for (const override of overrides.values()) {
|
|
779
|
+
const keys = Object.keys(override.match);
|
|
780
|
+
if (keys.length === 1 && keys[0] === "context" && typeof override.match.context === "string") {
|
|
781
|
+
contextIndex.set(override.match.context, override);
|
|
782
|
+
} else {
|
|
783
|
+
complexRules.push(override);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return { contextIndex, complexRules };
|
|
787
|
+
}
|
|
798
788
|
function createState(config, store) {
|
|
799
789
|
const { defaultLevel, rules } = parseLevelConfig(config.level);
|
|
800
790
|
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
791
|
const levelOverrides = /* @__PURE__ */ new Map();
|
|
811
792
|
for (const rule of rules) {
|
|
812
793
|
const key = JSON.stringify(rule.match);
|
|
813
794
|
levelOverrides.set(key, rule);
|
|
814
795
|
}
|
|
796
|
+
const { contextIndex, complexRules } = buildIndexes(levelOverrides);
|
|
797
|
+
const streams = createStreams(config, loggerStore);
|
|
798
|
+
const options = {
|
|
799
|
+
level: "trace",
|
|
800
|
+
// Accept all, we filter in shouldLog()
|
|
801
|
+
customLevels: CUSTOM_LEVELS,
|
|
802
|
+
base: void 0
|
|
803
|
+
// Disable pid and hostname
|
|
804
|
+
};
|
|
805
|
+
const pinoLogger = pino(options, streams);
|
|
815
806
|
return {
|
|
816
|
-
|
|
807
|
+
pino: pinoLogger,
|
|
817
808
|
store: loggerStore,
|
|
818
809
|
defaultLevel,
|
|
819
|
-
levelOverrides
|
|
810
|
+
levelOverrides,
|
|
811
|
+
contextIndex,
|
|
812
|
+
complexRules
|
|
820
813
|
};
|
|
821
814
|
}
|
|
815
|
+
function rebuildIndexes(state) {
|
|
816
|
+
const { contextIndex, complexRules } = buildIndexes(state.levelOverrides);
|
|
817
|
+
state.contextIndex = contextIndex;
|
|
818
|
+
state.complexRules.length = 0;
|
|
819
|
+
state.complexRules.push(...complexRules);
|
|
820
|
+
}
|
|
822
821
|
function shouldLog(state, level, context) {
|
|
823
822
|
const effectiveLevel = getEffectiveLevel(state, context);
|
|
823
|
+
if (effectiveLevel === "off") return false;
|
|
824
824
|
return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];
|
|
825
825
|
}
|
|
826
826
|
function getEffectiveLevel(state, loggerContext) {
|
|
827
|
+
if (loggerContext) {
|
|
828
|
+
const indexed = state.contextIndex.get(loggerContext);
|
|
829
|
+
if (indexed) return indexed.level;
|
|
830
|
+
}
|
|
827
831
|
const storeContext = state.store.getStore();
|
|
828
|
-
for (const { match, level } of state.
|
|
832
|
+
for (const { match, level } of state.complexRules) {
|
|
829
833
|
if (matchesContext(storeContext, loggerContext, match)) {
|
|
830
834
|
return level;
|
|
831
835
|
}
|
|
@@ -883,6 +887,7 @@ var DiscordConfigSchema = z.object({
|
|
|
883
887
|
maxRetries: z.number().int().nonnegative().optional(),
|
|
884
888
|
retryDelay: z.number().int().positive().optional(),
|
|
885
889
|
webhookUrl: z.string().url("webhookUrl must be a valid URL"),
|
|
890
|
+
format: z.enum(["embed", "markdown"]).optional(),
|
|
886
891
|
username: z.string().optional(),
|
|
887
892
|
avatarUrl: z.string().url().optional(),
|
|
888
893
|
embedColors: z.record(z.string(), z.number().int()).optional(),
|
|
@@ -948,6 +953,7 @@ var Logger = class _Logger {
|
|
|
948
953
|
this.state = state;
|
|
949
954
|
this.context = context;
|
|
950
955
|
}
|
|
956
|
+
profileTimers = /* @__PURE__ */ new Map();
|
|
951
957
|
static create(config, store) {
|
|
952
958
|
const validatedConfig = validateConfig(config);
|
|
953
959
|
const state = createState(validatedConfig, store);
|
|
@@ -964,6 +970,7 @@ var Logger = class _Logger {
|
|
|
964
970
|
assertLogLevel(level);
|
|
965
971
|
const key = JSON.stringify(match);
|
|
966
972
|
this.state.levelOverrides.set(key, { match, level });
|
|
973
|
+
rebuildIndexes(this.state);
|
|
967
974
|
}
|
|
968
975
|
removeLevelOverride(match) {
|
|
969
976
|
const key = JSON.stringify(match);
|
|
@@ -971,26 +978,50 @@ var Logger = class _Logger {
|
|
|
971
978
|
if (override?.readonly) {
|
|
972
979
|
return false;
|
|
973
980
|
}
|
|
974
|
-
|
|
981
|
+
const deleted = this.state.levelOverrides.delete(key);
|
|
982
|
+
if (deleted) {
|
|
983
|
+
rebuildIndexes(this.state);
|
|
984
|
+
}
|
|
985
|
+
return deleted;
|
|
975
986
|
}
|
|
976
987
|
clearLevelOverrides() {
|
|
988
|
+
let changed = false;
|
|
977
989
|
for (const [key, override] of this.state.levelOverrides) {
|
|
978
990
|
if (!override.readonly) {
|
|
979
991
|
this.state.levelOverrides.delete(key);
|
|
992
|
+
changed = true;
|
|
980
993
|
}
|
|
981
994
|
}
|
|
995
|
+
if (changed) {
|
|
996
|
+
rebuildIndexes(this.state);
|
|
997
|
+
}
|
|
982
998
|
}
|
|
983
999
|
getLevelOverrides() {
|
|
984
1000
|
return Array.from(this.state.levelOverrides.values());
|
|
985
1001
|
}
|
|
986
1002
|
// Profiling
|
|
987
1003
|
profile(id, meta) {
|
|
988
|
-
this.
|
|
1004
|
+
const existing = this.profileTimers.get(id);
|
|
1005
|
+
if (existing) {
|
|
1006
|
+
const duration = Date.now() - existing;
|
|
1007
|
+
this.profileTimers.delete(id);
|
|
1008
|
+
this.info(`${id} completed`, { ...meta, durationMs: duration });
|
|
1009
|
+
} else {
|
|
1010
|
+
this.profileTimers.set(id, Date.now());
|
|
1011
|
+
}
|
|
989
1012
|
}
|
|
990
1013
|
// Logging methods
|
|
991
|
-
error(
|
|
1014
|
+
error(errorOrMessage, messageOrMeta, meta) {
|
|
992
1015
|
if (!shouldLog(this.state, "error", this.context)) return;
|
|
993
|
-
|
|
1016
|
+
if (errorOrMessage instanceof Error) {
|
|
1017
|
+
if (typeof messageOrMeta === "string") {
|
|
1018
|
+
this.log("error", messageOrMeta, meta, errorOrMessage);
|
|
1019
|
+
} else {
|
|
1020
|
+
this.log("error", errorOrMessage.message, messageOrMeta, errorOrMessage);
|
|
1021
|
+
}
|
|
1022
|
+
} else {
|
|
1023
|
+
this.log("error", errorOrMessage, messageOrMeta);
|
|
1024
|
+
}
|
|
994
1025
|
}
|
|
995
1026
|
warn(message, meta) {
|
|
996
1027
|
if (!shouldLog(this.state, "warn", this.context)) return;
|
|
@@ -1020,13 +1051,41 @@ var Logger = class _Logger {
|
|
|
1020
1051
|
log(level, message, meta, error) {
|
|
1021
1052
|
const resolved = typeof meta === "function" ? meta() : meta;
|
|
1022
1053
|
const logMeta = { context: this.context, ...resolved };
|
|
1054
|
+
const storeContext = this.state.store.getStore();
|
|
1055
|
+
if (storeContext) {
|
|
1056
|
+
Object.assign(logMeta, storeContext);
|
|
1057
|
+
}
|
|
1023
1058
|
if (error instanceof Error) {
|
|
1024
1059
|
logMeta.errorMessage = error.message;
|
|
1025
1060
|
logMeta.stack = error.stack;
|
|
1026
1061
|
} else if (error !== void 0) {
|
|
1027
1062
|
logMeta.error = error;
|
|
1028
1063
|
}
|
|
1029
|
-
this.
|
|
1064
|
+
const pinoMethod = this.getPinoMethod(level);
|
|
1065
|
+
pinoMethod.call(this.state.pino, logMeta, message);
|
|
1066
|
+
}
|
|
1067
|
+
getPinoMethod(level) {
|
|
1068
|
+
switch (level) {
|
|
1069
|
+
case "error":
|
|
1070
|
+
return this.state.pino.error.bind(this.state.pino);
|
|
1071
|
+
case "warn":
|
|
1072
|
+
return this.state.pino.warn.bind(this.state.pino);
|
|
1073
|
+
case "info":
|
|
1074
|
+
return this.state.pino.info.bind(this.state.pino);
|
|
1075
|
+
case "http":
|
|
1076
|
+
case "verbose":
|
|
1077
|
+
return (obj, msg) => {
|
|
1078
|
+
this.state.pino[level](obj, msg);
|
|
1079
|
+
};
|
|
1080
|
+
case "debug":
|
|
1081
|
+
return this.state.pino.debug.bind(this.state.pino);
|
|
1082
|
+
case "silly":
|
|
1083
|
+
return (obj, msg) => {
|
|
1084
|
+
this.state.pino.silly(obj, msg);
|
|
1085
|
+
};
|
|
1086
|
+
default:
|
|
1087
|
+
return this.state.pino.info.bind(this.state.pino);
|
|
1088
|
+
}
|
|
1030
1089
|
}
|
|
1031
1090
|
};
|
|
1032
1091
|
|
|
@@ -1130,6 +1189,114 @@ function getOrGenerateRequestId(headers, options = {}) {
|
|
|
1130
1189
|
return extractRequestId(headers) ?? generateRequestId(options);
|
|
1131
1190
|
}
|
|
1132
1191
|
|
|
1192
|
+
// src/utils/mask-secrets.ts
|
|
1193
|
+
var DEFAULT_SECRET_PATTERNS = [
|
|
1194
|
+
"password",
|
|
1195
|
+
"secret",
|
|
1196
|
+
"token",
|
|
1197
|
+
"apikey",
|
|
1198
|
+
"api_key",
|
|
1199
|
+
"api-key",
|
|
1200
|
+
"auth",
|
|
1201
|
+
"credential",
|
|
1202
|
+
"private"
|
|
1203
|
+
];
|
|
1204
|
+
var DEFAULT_MASK = "***";
|
|
1205
|
+
function isSecretKey(key, patterns) {
|
|
1206
|
+
const lowerKey = key.toLowerCase();
|
|
1207
|
+
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
1208
|
+
}
|
|
1209
|
+
function maskUrlCredentials(url, mask) {
|
|
1210
|
+
try {
|
|
1211
|
+
const parsed = new URL(url);
|
|
1212
|
+
if (parsed.password) {
|
|
1213
|
+
parsed.password = mask;
|
|
1214
|
+
}
|
|
1215
|
+
if (parsed.username && parsed.password) {
|
|
1216
|
+
parsed.username = mask;
|
|
1217
|
+
}
|
|
1218
|
+
return parsed.toString();
|
|
1219
|
+
} catch {
|
|
1220
|
+
return url;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
function maskSecrets(obj, options = {}) {
|
|
1224
|
+
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
1225
|
+
if (obj === null || obj === void 0) {
|
|
1226
|
+
return obj;
|
|
1227
|
+
}
|
|
1228
|
+
if (typeof obj === "string") {
|
|
1229
|
+
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
1230
|
+
return maskUrlCredentials(obj, mask);
|
|
1231
|
+
}
|
|
1232
|
+
return obj;
|
|
1233
|
+
}
|
|
1234
|
+
if (Array.isArray(obj)) {
|
|
1235
|
+
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
1236
|
+
}
|
|
1237
|
+
if (typeof obj === "object") {
|
|
1238
|
+
const result = {};
|
|
1239
|
+
for (const sym of Object.getOwnPropertySymbols(obj)) {
|
|
1240
|
+
result[sym] = obj[sym];
|
|
1241
|
+
}
|
|
1242
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1243
|
+
if (isSecretKey(key, patterns)) {
|
|
1244
|
+
result[key] = mask;
|
|
1245
|
+
} else if (deep && typeof value === "object" && value !== null) {
|
|
1246
|
+
result[key] = maskSecrets(value, options);
|
|
1247
|
+
} else if (typeof value === "string") {
|
|
1248
|
+
result[key] = maskSecrets(value, options);
|
|
1249
|
+
} else {
|
|
1250
|
+
result[key] = value;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
return result;
|
|
1254
|
+
}
|
|
1255
|
+
return obj;
|
|
1256
|
+
}
|
|
1257
|
+
function createMasker(options = {}) {
|
|
1258
|
+
return (obj) => maskSecrets(obj, options);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/formatters.ts
|
|
1262
|
+
function flattenObject(obj, prefix = "") {
|
|
1263
|
+
const result = {};
|
|
1264
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1265
|
+
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
1266
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Error)) {
|
|
1267
|
+
Object.assign(result, flattenObject(value, newKey));
|
|
1268
|
+
} else {
|
|
1269
|
+
result[newKey] = value;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
return result;
|
|
1273
|
+
}
|
|
1274
|
+
function formatLogfmtValue(value) {
|
|
1275
|
+
if (value === null || value === void 0) {
|
|
1276
|
+
return "";
|
|
1277
|
+
}
|
|
1278
|
+
if (typeof value === "string") {
|
|
1279
|
+
if (value.includes(" ") || value.includes('"') || value.includes("=")) {
|
|
1280
|
+
return `"${value.replace(/"/g, '\\"')}"`;
|
|
1281
|
+
}
|
|
1282
|
+
return value;
|
|
1283
|
+
}
|
|
1284
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1285
|
+
return String(value);
|
|
1286
|
+
}
|
|
1287
|
+
if (value instanceof Error) {
|
|
1288
|
+
return `"${value.message.replace(/"/g, '\\"')}"`;
|
|
1289
|
+
}
|
|
1290
|
+
if (Array.isArray(value)) {
|
|
1291
|
+
return `"${JSON.stringify(value).replace(/"/g, '\\"')}"`;
|
|
1292
|
+
}
|
|
1293
|
+
return `"${JSON.stringify(value).replace(/"/g, '\\"')}"`;
|
|
1294
|
+
}
|
|
1295
|
+
function formatLogfmt(data) {
|
|
1296
|
+
const flattened = flattenObject(data);
|
|
1297
|
+
return Object.entries(flattened).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${formatLogfmtValue(value)}`).join(" ");
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1133
1300
|
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
1301
|
//# sourceMappingURL=index.mjs.map
|
|
1135
1302
|
//# sourceMappingURL=index.mjs.map
|