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