@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.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,224 @@ 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 metaStr = Object.keys(meta).length > 0 ? "\n " + Object.entries(meta).map(([k, v]) => `${k}: ${JSON.stringify(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
|
+
`;
|
|
718
620
|
}
|
|
719
|
-
function
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
621
|
+
function createFormattedFilterStream(format, level, rules, store, destination) {
|
|
622
|
+
return new stream.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
|
+
});
|
|
728
657
|
if (config.file) {
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
)
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
658
|
+
const fileConfig = config.file;
|
|
659
|
+
promises.mkdir(fileConfig.dirname, { recursive: true }).catch(() => {
|
|
660
|
+
});
|
|
661
|
+
const rotatingStream = rotatingFileStream.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
|
+
}
|
|
742
675
|
);
|
|
676
|
+
const fileStream = createFormattedFilterStream(
|
|
677
|
+
fileConfig.format,
|
|
678
|
+
fileConfig.level,
|
|
679
|
+
fileConfig.rules,
|
|
680
|
+
store,
|
|
681
|
+
rotatingStream
|
|
682
|
+
);
|
|
683
|
+
streams.push({
|
|
684
|
+
level: "trace",
|
|
685
|
+
stream: fileStream
|
|
686
|
+
});
|
|
743
687
|
}
|
|
744
688
|
for (const discordConfig of toArray(config.discord)) {
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
+
});
|
|
751
695
|
}
|
|
752
696
|
for (const telegramConfig of toArray(config.telegram)) {
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
+
});
|
|
759
703
|
}
|
|
760
704
|
for (const cloudwatchConfig of toArray(config.cloudwatch)) {
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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
|
+
});
|
|
767
711
|
}
|
|
768
|
-
return
|
|
712
|
+
return pino__default.default.multistream(streams);
|
|
769
713
|
}
|
|
770
|
-
function
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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 stream.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
|
+
});
|
|
790
755
|
}
|
|
791
756
|
|
|
792
757
|
// src/state.ts
|
|
758
|
+
var CUSTOM_LEVELS = {
|
|
759
|
+
http: 25,
|
|
760
|
+
verbose: 25,
|
|
761
|
+
silly: 10
|
|
762
|
+
};
|
|
793
763
|
function parseLevelConfig(level) {
|
|
794
764
|
if (typeof level === "string") {
|
|
795
765
|
assertLogLevel(level);
|
|
@@ -802,37 +772,64 @@ function parseLevelConfig(level) {
|
|
|
802
772
|
});
|
|
803
773
|
return { defaultLevel: level.default, rules };
|
|
804
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
|
+
}
|
|
805
788
|
function createState(config, store) {
|
|
806
789
|
const { defaultLevel, rules } = parseLevelConfig(config.level);
|
|
807
790
|
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
791
|
const levelOverrides = /* @__PURE__ */ new Map();
|
|
818
792
|
for (const rule of rules) {
|
|
819
793
|
const key = JSON.stringify(rule.match);
|
|
820
794
|
levelOverrides.set(key, rule);
|
|
821
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__default.default(options, streams);
|
|
822
806
|
return {
|
|
823
|
-
|
|
807
|
+
pino: pinoLogger,
|
|
824
808
|
store: loggerStore,
|
|
825
809
|
defaultLevel,
|
|
826
|
-
levelOverrides
|
|
810
|
+
levelOverrides,
|
|
811
|
+
contextIndex,
|
|
812
|
+
complexRules
|
|
827
813
|
};
|
|
828
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
|
+
}
|
|
829
821
|
function shouldLog(state, level, context) {
|
|
830
822
|
const effectiveLevel = getEffectiveLevel(state, context);
|
|
823
|
+
if (effectiveLevel === "off") return false;
|
|
831
824
|
return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];
|
|
832
825
|
}
|
|
833
826
|
function getEffectiveLevel(state, loggerContext) {
|
|
827
|
+
if (loggerContext) {
|
|
828
|
+
const indexed = state.contextIndex.get(loggerContext);
|
|
829
|
+
if (indexed) return indexed.level;
|
|
830
|
+
}
|
|
834
831
|
const storeContext = state.store.getStore();
|
|
835
|
-
for (const { match, level } of state.
|
|
832
|
+
for (const { match, level } of state.complexRules) {
|
|
836
833
|
if (matchesContext(storeContext, loggerContext, match)) {
|
|
837
834
|
return level;
|
|
838
835
|
}
|
|
@@ -890,6 +887,7 @@ var DiscordConfigSchema = zod.z.object({
|
|
|
890
887
|
maxRetries: zod.z.number().int().nonnegative().optional(),
|
|
891
888
|
retryDelay: zod.z.number().int().positive().optional(),
|
|
892
889
|
webhookUrl: zod.z.string().url("webhookUrl must be a valid URL"),
|
|
890
|
+
format: zod.z.enum(["embed", "markdown"]).optional(),
|
|
893
891
|
username: zod.z.string().optional(),
|
|
894
892
|
avatarUrl: zod.z.string().url().optional(),
|
|
895
893
|
embedColors: zod.z.record(zod.z.string(), zod.z.number().int()).optional(),
|
|
@@ -955,6 +953,7 @@ var Logger = class _Logger {
|
|
|
955
953
|
this.state = state;
|
|
956
954
|
this.context = context;
|
|
957
955
|
}
|
|
956
|
+
profileTimers = /* @__PURE__ */ new Map();
|
|
958
957
|
static create(config, store) {
|
|
959
958
|
const validatedConfig = validateConfig(config);
|
|
960
959
|
const state = createState(validatedConfig, store);
|
|
@@ -971,6 +970,7 @@ var Logger = class _Logger {
|
|
|
971
970
|
assertLogLevel(level);
|
|
972
971
|
const key = JSON.stringify(match);
|
|
973
972
|
this.state.levelOverrides.set(key, { match, level });
|
|
973
|
+
rebuildIndexes(this.state);
|
|
974
974
|
}
|
|
975
975
|
removeLevelOverride(match) {
|
|
976
976
|
const key = JSON.stringify(match);
|
|
@@ -978,26 +978,50 @@ var Logger = class _Logger {
|
|
|
978
978
|
if (override?.readonly) {
|
|
979
979
|
return false;
|
|
980
980
|
}
|
|
981
|
-
|
|
981
|
+
const deleted = this.state.levelOverrides.delete(key);
|
|
982
|
+
if (deleted) {
|
|
983
|
+
rebuildIndexes(this.state);
|
|
984
|
+
}
|
|
985
|
+
return deleted;
|
|
982
986
|
}
|
|
983
987
|
clearLevelOverrides() {
|
|
988
|
+
let changed = false;
|
|
984
989
|
for (const [key, override] of this.state.levelOverrides) {
|
|
985
990
|
if (!override.readonly) {
|
|
986
991
|
this.state.levelOverrides.delete(key);
|
|
992
|
+
changed = true;
|
|
987
993
|
}
|
|
988
994
|
}
|
|
995
|
+
if (changed) {
|
|
996
|
+
rebuildIndexes(this.state);
|
|
997
|
+
}
|
|
989
998
|
}
|
|
990
999
|
getLevelOverrides() {
|
|
991
1000
|
return Array.from(this.state.levelOverrides.values());
|
|
992
1001
|
}
|
|
993
1002
|
// Profiling
|
|
994
1003
|
profile(id, meta) {
|
|
995
|
-
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
|
+
}
|
|
996
1012
|
}
|
|
997
1013
|
// Logging methods
|
|
998
|
-
error(
|
|
1014
|
+
error(errorOrMessage, messageOrMeta, meta) {
|
|
999
1015
|
if (!shouldLog(this.state, "error", this.context)) return;
|
|
1000
|
-
|
|
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
|
+
}
|
|
1001
1025
|
}
|
|
1002
1026
|
warn(message, meta) {
|
|
1003
1027
|
if (!shouldLog(this.state, "warn", this.context)) return;
|
|
@@ -1027,13 +1051,41 @@ var Logger = class _Logger {
|
|
|
1027
1051
|
log(level, message, meta, error) {
|
|
1028
1052
|
const resolved = typeof meta === "function" ? meta() : meta;
|
|
1029
1053
|
const logMeta = { context: this.context, ...resolved };
|
|
1054
|
+
const storeContext = this.state.store.getStore();
|
|
1055
|
+
if (storeContext) {
|
|
1056
|
+
Object.assign(logMeta, storeContext);
|
|
1057
|
+
}
|
|
1030
1058
|
if (error instanceof Error) {
|
|
1031
1059
|
logMeta.errorMessage = error.message;
|
|
1032
1060
|
logMeta.stack = error.stack;
|
|
1033
1061
|
} else if (error !== void 0) {
|
|
1034
1062
|
logMeta.error = error;
|
|
1035
1063
|
}
|
|
1036
|
-
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
|
+
}
|
|
1037
1089
|
}
|
|
1038
1090
|
};
|
|
1039
1091
|
|
|
@@ -1137,6 +1189,114 @@ function getOrGenerateRequestId(headers, options = {}) {
|
|
|
1137
1189
|
return extractRequestId(headers) ?? generateRequestId(options);
|
|
1138
1190
|
}
|
|
1139
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
|
+
|
|
1140
1300
|
exports.BaseHttpTransport = BaseHttpTransport;
|
|
1141
1301
|
exports.CloudWatchConfigSchema = CloudWatchConfigSchema;
|
|
1142
1302
|
exports.CloudWatchTransport = CloudWatchTransport;
|