@rawnodes/logger 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +425 -147
- package/dist/index.d.mts +151 -3
- package/dist/index.d.ts +151 -3
- package/dist/index.js +538 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +532 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,8 @@ import { createLogger, transports, format } from 'winston';
|
|
|
2
2
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
3
3
|
import DailyRotateFile from 'winston-daily-rotate-file';
|
|
4
4
|
import { inspect } from 'util';
|
|
5
|
+
import TransportStream from 'winston-transport';
|
|
6
|
+
import { CloudWatchLogsClient, PutLogEventsCommand, CreateLogGroupCommand, CreateLogStreamCommand, DescribeLogStreamsCommand } from '@aws-sdk/client-cloudwatch-logs';
|
|
5
7
|
import { randomUUID } from 'crypto';
|
|
6
8
|
|
|
7
9
|
// src/state.ts
|
|
@@ -15,6 +17,26 @@ var LoggerStore = class {
|
|
|
15
17
|
}
|
|
16
18
|
};
|
|
17
19
|
|
|
20
|
+
// src/types.ts
|
|
21
|
+
var LOG_LEVELS = {
|
|
22
|
+
off: -1,
|
|
23
|
+
error: 0,
|
|
24
|
+
warn: 1,
|
|
25
|
+
info: 2,
|
|
26
|
+
http: 3,
|
|
27
|
+
verbose: 4,
|
|
28
|
+
debug: 5,
|
|
29
|
+
silly: 6
|
|
30
|
+
};
|
|
31
|
+
function isValidLogLevel(level) {
|
|
32
|
+
return level in LOG_LEVELS;
|
|
33
|
+
}
|
|
34
|
+
function assertLogLevel(level) {
|
|
35
|
+
if (!isValidLogLevel(level)) {
|
|
36
|
+
throw new Error(`Invalid log level: "${level}". Valid levels: ${Object.keys(LOG_LEVELS).join(", ")}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
18
40
|
// src/utils/mask-secrets.ts
|
|
19
41
|
var DEFAULT_SECRET_PATTERNS = [
|
|
20
42
|
"password",
|
|
@@ -169,6 +191,20 @@ function maskSecretsFormat(options) {
|
|
|
169
191
|
return maskSecrets(info, options);
|
|
170
192
|
})();
|
|
171
193
|
}
|
|
194
|
+
function createFilterFormat(defaultLevel, rules, store) {
|
|
195
|
+
if (!rules?.length && defaultLevel === void 0) {
|
|
196
|
+
return format((info) => info)();
|
|
197
|
+
}
|
|
198
|
+
return format((info) => {
|
|
199
|
+
const logLevel = info.level;
|
|
200
|
+
const context = info.context;
|
|
201
|
+
const storeContext = store.getStore();
|
|
202
|
+
const matchingRule = rules?.find((rule) => matchesContext(storeContext, context, rule.match));
|
|
203
|
+
const effectiveLevel = matchingRule?.level ?? defaultLevel ?? "silly";
|
|
204
|
+
if (effectiveLevel === "off") return false;
|
|
205
|
+
return LOG_LEVELS[logLevel] <= LOG_LEVELS[effectiveLevel] ? info : false;
|
|
206
|
+
})();
|
|
207
|
+
}
|
|
172
208
|
function createPlainFormat(store) {
|
|
173
209
|
return format.combine(
|
|
174
210
|
format.errors({ stack: true }),
|
|
@@ -233,17 +269,457 @@ function createFormat(logFormat, store) {
|
|
|
233
269
|
}
|
|
234
270
|
}
|
|
235
271
|
|
|
272
|
+
// src/transports/buffer.ts
|
|
273
|
+
var MessageBuffer = class {
|
|
274
|
+
constructor(options) {
|
|
275
|
+
this.options = options;
|
|
276
|
+
}
|
|
277
|
+
queue = [];
|
|
278
|
+
timer = null;
|
|
279
|
+
flushing = false;
|
|
280
|
+
closed = false;
|
|
281
|
+
add(message) {
|
|
282
|
+
if (this.closed) return;
|
|
283
|
+
this.queue.push(message);
|
|
284
|
+
if (this.queue.length >= this.options.batchSize) {
|
|
285
|
+
void this.flush();
|
|
286
|
+
} else {
|
|
287
|
+
this.scheduleFlush();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async flush() {
|
|
291
|
+
if (this.flushing || this.queue.length === 0) return;
|
|
292
|
+
this.flushing = true;
|
|
293
|
+
this.clearTimer();
|
|
294
|
+
const messages = this.queue.splice(0, this.options.batchSize);
|
|
295
|
+
try {
|
|
296
|
+
await this.sendWithRetry(messages);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
this.options.onError?.(error, messages);
|
|
299
|
+
} finally {
|
|
300
|
+
this.flushing = false;
|
|
301
|
+
if (this.queue.length > 0 && !this.closed) {
|
|
302
|
+
void this.flush();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async close() {
|
|
307
|
+
this.closed = true;
|
|
308
|
+
this.clearTimer();
|
|
309
|
+
while (this.queue.length > 0) {
|
|
310
|
+
await this.flush();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
scheduleFlush() {
|
|
314
|
+
if (this.timer || this.closed) return;
|
|
315
|
+
this.timer = setTimeout(() => {
|
|
316
|
+
this.timer = null;
|
|
317
|
+
void this.flush();
|
|
318
|
+
}, this.options.flushInterval);
|
|
319
|
+
}
|
|
320
|
+
clearTimer() {
|
|
321
|
+
if (this.timer) {
|
|
322
|
+
clearTimeout(this.timer);
|
|
323
|
+
this.timer = null;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async sendWithRetry(messages) {
|
|
327
|
+
let lastError = null;
|
|
328
|
+
for (let attempt = 0; attempt < this.options.maxRetries; attempt++) {
|
|
329
|
+
try {
|
|
330
|
+
await this.options.onFlush(messages);
|
|
331
|
+
return;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
lastError = error;
|
|
334
|
+
if (attempt < this.options.maxRetries - 1) {
|
|
335
|
+
await this.delay(this.options.retryDelay * Math.pow(2, attempt));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
throw lastError;
|
|
340
|
+
}
|
|
341
|
+
delay(ms) {
|
|
342
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// src/transports/base-http.ts
|
|
347
|
+
var DEFAULT_OPTIONS = {
|
|
348
|
+
batchSize: 10,
|
|
349
|
+
flushInterval: 5e3,
|
|
350
|
+
maxRetries: 3,
|
|
351
|
+
retryDelay: 1e3
|
|
352
|
+
};
|
|
353
|
+
var BaseHttpTransport = class extends TransportStream {
|
|
354
|
+
buffer;
|
|
355
|
+
constructor(opts = {}) {
|
|
356
|
+
super();
|
|
357
|
+
this.buffer = new MessageBuffer({
|
|
358
|
+
batchSize: opts.batchSize ?? DEFAULT_OPTIONS.batchSize,
|
|
359
|
+
flushInterval: opts.flushInterval ?? DEFAULT_OPTIONS.flushInterval,
|
|
360
|
+
maxRetries: opts.maxRetries ?? DEFAULT_OPTIONS.maxRetries,
|
|
361
|
+
retryDelay: opts.retryDelay ?? DEFAULT_OPTIONS.retryDelay,
|
|
362
|
+
onFlush: this.sendBatch.bind(this),
|
|
363
|
+
onError: this.handleError.bind(this)
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
log(info, callback) {
|
|
367
|
+
const message = this.transformMessage(info);
|
|
368
|
+
this.buffer.add(message);
|
|
369
|
+
callback();
|
|
370
|
+
}
|
|
371
|
+
close() {
|
|
372
|
+
return this.buffer.close();
|
|
373
|
+
}
|
|
374
|
+
transformMessage(info) {
|
|
375
|
+
const { level, message, timestamp, context, ...meta } = info;
|
|
376
|
+
return {
|
|
377
|
+
level,
|
|
378
|
+
message: String(message),
|
|
379
|
+
timestamp: timestamp ? new Date(String(timestamp)) : /* @__PURE__ */ new Date(),
|
|
380
|
+
context,
|
|
381
|
+
meta: Object.keys(meta).length > 0 ? meta : void 0
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
handleError(error, messages) {
|
|
385
|
+
console.error(
|
|
386
|
+
`[${this.constructor.name}] Failed to send ${messages.length} messages:`,
|
|
387
|
+
error.message
|
|
388
|
+
);
|
|
389
|
+
this.emit("error", error);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// src/transports/discord.ts
|
|
394
|
+
var DEFAULT_EMBED_COLORS = {
|
|
395
|
+
off: 0,
|
|
396
|
+
error: 15548997,
|
|
397
|
+
warn: 16705372,
|
|
398
|
+
info: 5763719,
|
|
399
|
+
http: 5793266,
|
|
400
|
+
verbose: 10181046,
|
|
401
|
+
debug: 3447003,
|
|
402
|
+
silly: 9807270
|
|
403
|
+
};
|
|
404
|
+
var DiscordTransport = class extends BaseHttpTransport {
|
|
405
|
+
config;
|
|
406
|
+
constructor(config) {
|
|
407
|
+
super({
|
|
408
|
+
batchSize: config.batchSize ?? 10,
|
|
409
|
+
flushInterval: config.flushInterval ?? 2e3,
|
|
410
|
+
maxRetries: config.maxRetries,
|
|
411
|
+
retryDelay: config.retryDelay
|
|
412
|
+
});
|
|
413
|
+
this.config = config;
|
|
414
|
+
}
|
|
415
|
+
async sendBatch(messages) {
|
|
416
|
+
const chunks = this.chunkArray(messages, 10);
|
|
417
|
+
for (const chunk of chunks) {
|
|
418
|
+
const payload = {
|
|
419
|
+
username: this.config.username,
|
|
420
|
+
avatar_url: this.config.avatarUrl,
|
|
421
|
+
embeds: chunk.map((msg) => this.createEmbed(msg))
|
|
422
|
+
};
|
|
423
|
+
await this.sendWebhook(payload);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
createEmbed(msg) {
|
|
427
|
+
const color = this.config.embedColors?.[msg.level] ?? DEFAULT_EMBED_COLORS[msg.level];
|
|
428
|
+
const embed = {
|
|
429
|
+
title: `[${msg.level.toUpperCase()}] ${msg.context || "APP"}`,
|
|
430
|
+
description: msg.message.slice(0, 4096),
|
|
431
|
+
// Discord limit
|
|
432
|
+
color
|
|
433
|
+
};
|
|
434
|
+
if (this.config.includeTimestamp !== false) {
|
|
435
|
+
embed.timestamp = msg.timestamp.toISOString();
|
|
436
|
+
}
|
|
437
|
+
if (this.config.includeMeta !== false && msg.meta) {
|
|
438
|
+
embed.fields = this.metaToFields(msg.meta);
|
|
439
|
+
}
|
|
440
|
+
return embed;
|
|
441
|
+
}
|
|
442
|
+
metaToFields(meta) {
|
|
443
|
+
const maxFields = this.config.maxEmbedFields ?? 25;
|
|
444
|
+
const fields = [];
|
|
445
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
446
|
+
if (fields.length >= maxFields) break;
|
|
447
|
+
let strValue;
|
|
448
|
+
if (typeof value === "object") {
|
|
449
|
+
strValue = "```json\n" + JSON.stringify(value, null, 2).slice(0, 1e3) + "\n```";
|
|
450
|
+
} else {
|
|
451
|
+
strValue = String(value).slice(0, 1024);
|
|
452
|
+
}
|
|
453
|
+
fields.push({
|
|
454
|
+
name: key.slice(0, 256),
|
|
455
|
+
value: strValue,
|
|
456
|
+
inline: typeof value !== "object" && String(value).length < 50
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
return fields;
|
|
460
|
+
}
|
|
461
|
+
async sendWebhook(payload) {
|
|
462
|
+
const response = await fetch(this.config.webhookUrl, {
|
|
463
|
+
method: "POST",
|
|
464
|
+
headers: { "Content-Type": "application/json" },
|
|
465
|
+
body: JSON.stringify(payload)
|
|
466
|
+
});
|
|
467
|
+
if (!response.ok) {
|
|
468
|
+
const text = await response.text();
|
|
469
|
+
throw new Error(`Discord webhook failed: ${response.status} ${text}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
chunkArray(array, size) {
|
|
473
|
+
const chunks = [];
|
|
474
|
+
for (let i = 0; i < array.length; i += size) {
|
|
475
|
+
chunks.push(array.slice(i, i + size));
|
|
476
|
+
}
|
|
477
|
+
return chunks;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
// src/transports/telegram.ts
|
|
482
|
+
var LEVEL_EMOJI = {
|
|
483
|
+
off: "",
|
|
484
|
+
error: "\u{1F534}",
|
|
485
|
+
warn: "\u{1F7E1}",
|
|
486
|
+
info: "\u{1F7E2}",
|
|
487
|
+
http: "\u{1F535}",
|
|
488
|
+
verbose: "\u{1F7E3}",
|
|
489
|
+
debug: "\u26AA",
|
|
490
|
+
silly: "\u26AB"
|
|
491
|
+
};
|
|
492
|
+
var TelegramTransport = class extends BaseHttpTransport {
|
|
493
|
+
config;
|
|
494
|
+
apiUrl;
|
|
495
|
+
constructor(config) {
|
|
496
|
+
super({
|
|
497
|
+
batchSize: config.batchSize ?? 20,
|
|
498
|
+
flushInterval: config.flushInterval ?? 1e3,
|
|
499
|
+
maxRetries: config.maxRetries,
|
|
500
|
+
retryDelay: config.retryDelay
|
|
501
|
+
});
|
|
502
|
+
this.config = config;
|
|
503
|
+
this.apiUrl = `https://api.telegram.org/bot${config.botToken}`;
|
|
504
|
+
}
|
|
505
|
+
async sendBatch(messages) {
|
|
506
|
+
const text = this.formatBatchMessage(messages);
|
|
507
|
+
await this.sendMessage(text, messages);
|
|
508
|
+
}
|
|
509
|
+
formatBatchMessage(messages) {
|
|
510
|
+
const parseMode = this.config.parseMode ?? "Markdown";
|
|
511
|
+
return messages.map((msg) => {
|
|
512
|
+
if (parseMode === "HTML") {
|
|
513
|
+
return this.formatHtml(msg);
|
|
514
|
+
}
|
|
515
|
+
return this.formatMarkdown(msg, parseMode === "MarkdownV2");
|
|
516
|
+
}).join("\n\n---\n\n");
|
|
517
|
+
}
|
|
518
|
+
formatMarkdown(msg, v2) {
|
|
519
|
+
const emoji = LEVEL_EMOJI[msg.level];
|
|
520
|
+
const escape = v2 ? this.escapeMarkdownV2.bind(this) : (s) => s;
|
|
521
|
+
let text = `${emoji} *${msg.level.toUpperCase()}* \\[${escape(msg.context || "APP")}\\]
|
|
522
|
+
`;
|
|
523
|
+
text += escape(msg.message);
|
|
524
|
+
if (msg.meta && Object.keys(msg.meta).length > 0) {
|
|
525
|
+
const metaStr = JSON.stringify(msg.meta, null, 2);
|
|
526
|
+
text += "\n```json\n" + metaStr + "\n```";
|
|
527
|
+
}
|
|
528
|
+
return text;
|
|
529
|
+
}
|
|
530
|
+
formatHtml(msg) {
|
|
531
|
+
const emoji = LEVEL_EMOJI[msg.level];
|
|
532
|
+
let text = `${emoji} <b>${msg.level.toUpperCase()}</b> [${this.escapeHtml(msg.context || "APP")}]
|
|
533
|
+
`;
|
|
534
|
+
text += this.escapeHtml(msg.message);
|
|
535
|
+
if (msg.meta && Object.keys(msg.meta).length > 0) {
|
|
536
|
+
const metaStr = JSON.stringify(msg.meta, null, 2);
|
|
537
|
+
text += "\n<pre>" + this.escapeHtml(metaStr) + "</pre>";
|
|
538
|
+
}
|
|
539
|
+
return text;
|
|
540
|
+
}
|
|
541
|
+
shouldMute(messages) {
|
|
542
|
+
if (this.config.disableNotification !== void 0) {
|
|
543
|
+
return this.config.disableNotification;
|
|
544
|
+
}
|
|
545
|
+
return !messages.some((m) => m.level === "error");
|
|
546
|
+
}
|
|
547
|
+
async sendMessage(text, messages) {
|
|
548
|
+
const body = {
|
|
549
|
+
chat_id: this.config.chatId,
|
|
550
|
+
text,
|
|
551
|
+
parse_mode: this.config.parseMode ?? "Markdown",
|
|
552
|
+
disable_notification: this.shouldMute(messages)
|
|
553
|
+
};
|
|
554
|
+
if (this.config.threadId) {
|
|
555
|
+
body.message_thread_id = this.config.threadId;
|
|
556
|
+
}
|
|
557
|
+
if (this.config.replyToMessageId) {
|
|
558
|
+
body.reply_to_message_id = this.config.replyToMessageId;
|
|
559
|
+
}
|
|
560
|
+
const response = await fetch(`${this.apiUrl}/sendMessage`, {
|
|
561
|
+
method: "POST",
|
|
562
|
+
headers: { "Content-Type": "application/json" },
|
|
563
|
+
body: JSON.stringify(body)
|
|
564
|
+
});
|
|
565
|
+
if (!response.ok) {
|
|
566
|
+
const result = await response.json();
|
|
567
|
+
throw new Error(`Telegram API failed: ${response.status} ${JSON.stringify(result)}`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
escapeMarkdownV2(text) {
|
|
571
|
+
return text.replace(/[_*[\]()~`>#+\-=|{}.!]/g, "\\$&");
|
|
572
|
+
}
|
|
573
|
+
escapeHtml(text) {
|
|
574
|
+
const entities = {
|
|
575
|
+
"&": "&",
|
|
576
|
+
"<": "<",
|
|
577
|
+
">": ">",
|
|
578
|
+
'"': """,
|
|
579
|
+
"'": "'"
|
|
580
|
+
};
|
|
581
|
+
return text.replace(/[&<>"']/g, (c) => entities[c] || c);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
var CloudWatchTransport = class extends BaseHttpTransport {
|
|
585
|
+
config;
|
|
586
|
+
client;
|
|
587
|
+
sequenceToken;
|
|
588
|
+
initialized = false;
|
|
589
|
+
initPromise = null;
|
|
590
|
+
constructor(config) {
|
|
591
|
+
super({
|
|
592
|
+
batchSize: config.batchSize ?? 100,
|
|
593
|
+
flushInterval: config.flushInterval ?? 1e3,
|
|
594
|
+
maxRetries: config.maxRetries,
|
|
595
|
+
retryDelay: config.retryDelay
|
|
596
|
+
});
|
|
597
|
+
this.config = config;
|
|
598
|
+
this.client = new CloudWatchLogsClient({
|
|
599
|
+
region: config.region,
|
|
600
|
+
credentials: {
|
|
601
|
+
accessKeyId: config.accessKeyId,
|
|
602
|
+
secretAccessKey: config.secretAccessKey
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
async sendBatch(messages) {
|
|
607
|
+
await this.ensureInitialized();
|
|
608
|
+
const logEvents = messages.map((msg) => ({
|
|
609
|
+
timestamp: msg.timestamp.getTime(),
|
|
610
|
+
message: JSON.stringify({
|
|
611
|
+
level: msg.level,
|
|
612
|
+
message: msg.message,
|
|
613
|
+
context: msg.context,
|
|
614
|
+
...msg.meta
|
|
615
|
+
})
|
|
616
|
+
}));
|
|
617
|
+
logEvents.sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
|
|
618
|
+
const command = new PutLogEventsCommand({
|
|
619
|
+
logGroupName: this.config.logGroupName,
|
|
620
|
+
logStreamName: this.config.logStreamName,
|
|
621
|
+
logEvents,
|
|
622
|
+
sequenceToken: this.sequenceToken
|
|
623
|
+
});
|
|
624
|
+
try {
|
|
625
|
+
const response = await this.client.send(command);
|
|
626
|
+
this.sequenceToken = response.nextSequenceToken;
|
|
627
|
+
} catch (error) {
|
|
628
|
+
if (this.isInvalidSequenceTokenError(error)) {
|
|
629
|
+
await this.fetchSequenceToken();
|
|
630
|
+
const retryCommand = new PutLogEventsCommand({
|
|
631
|
+
logGroupName: this.config.logGroupName,
|
|
632
|
+
logStreamName: this.config.logStreamName,
|
|
633
|
+
logEvents,
|
|
634
|
+
sequenceToken: this.sequenceToken
|
|
635
|
+
});
|
|
636
|
+
const response = await this.client.send(retryCommand);
|
|
637
|
+
this.sequenceToken = response.nextSequenceToken;
|
|
638
|
+
} else {
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
async ensureInitialized() {
|
|
644
|
+
if (this.initialized) return;
|
|
645
|
+
if (!this.initPromise) {
|
|
646
|
+
this.initPromise = this.initialize();
|
|
647
|
+
}
|
|
648
|
+
await this.initPromise;
|
|
649
|
+
}
|
|
650
|
+
async initialize() {
|
|
651
|
+
if (this.config.createLogGroup) {
|
|
652
|
+
await this.createLogGroupIfNotExists();
|
|
653
|
+
}
|
|
654
|
+
if (this.config.createLogStream !== false) {
|
|
655
|
+
await this.createLogStreamIfNotExists();
|
|
656
|
+
}
|
|
657
|
+
await this.fetchSequenceToken();
|
|
658
|
+
this.initialized = true;
|
|
659
|
+
}
|
|
660
|
+
async createLogGroupIfNotExists() {
|
|
661
|
+
try {
|
|
662
|
+
await this.client.send(
|
|
663
|
+
new CreateLogGroupCommand({
|
|
664
|
+
logGroupName: this.config.logGroupName
|
|
665
|
+
})
|
|
666
|
+
);
|
|
667
|
+
} catch (error) {
|
|
668
|
+
if (!this.isResourceAlreadyExistsError(error)) {
|
|
669
|
+
throw error;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
async createLogStreamIfNotExists() {
|
|
674
|
+
try {
|
|
675
|
+
await this.client.send(
|
|
676
|
+
new CreateLogStreamCommand({
|
|
677
|
+
logGroupName: this.config.logGroupName,
|
|
678
|
+
logStreamName: this.config.logStreamName
|
|
679
|
+
})
|
|
680
|
+
);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
if (!this.isResourceAlreadyExistsError(error)) {
|
|
683
|
+
throw error;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
async fetchSequenceToken() {
|
|
688
|
+
const response = await this.client.send(
|
|
689
|
+
new DescribeLogStreamsCommand({
|
|
690
|
+
logGroupName: this.config.logGroupName,
|
|
691
|
+
logStreamNamePrefix: this.config.logStreamName,
|
|
692
|
+
limit: 1
|
|
693
|
+
})
|
|
694
|
+
);
|
|
695
|
+
const stream = response.logStreams?.find((s) => s.logStreamName === this.config.logStreamName);
|
|
696
|
+
this.sequenceToken = stream?.uploadSequenceToken;
|
|
697
|
+
}
|
|
698
|
+
isResourceAlreadyExistsError(error) {
|
|
699
|
+
return typeof error === "object" && error !== null && "name" in error && error.name === "ResourceAlreadyExistsException";
|
|
700
|
+
}
|
|
701
|
+
isInvalidSequenceTokenError(error) {
|
|
702
|
+
return typeof error === "object" && error !== null && "name" in error && error.name === "InvalidSequenceTokenException";
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
|
|
236
706
|
// src/transports.ts
|
|
237
707
|
function createTransports(config, store) {
|
|
238
708
|
const result = [
|
|
239
709
|
new transports.Console({
|
|
240
|
-
format:
|
|
710
|
+
format: format.combine(
|
|
711
|
+
createFilterFormat(config.console.level, config.console.rules, store),
|
|
712
|
+
createFormat(config.console.format, store)
|
|
713
|
+
)
|
|
241
714
|
})
|
|
242
715
|
];
|
|
243
716
|
if (config.file) {
|
|
244
717
|
result.push(
|
|
245
718
|
new DailyRotateFile({
|
|
246
|
-
format:
|
|
719
|
+
format: format.combine(
|
|
720
|
+
createFilterFormat(config.file.level, config.file.rules, store),
|
|
721
|
+
createFormat(config.file.format, store)
|
|
722
|
+
),
|
|
247
723
|
dirname: config.file.dirname,
|
|
248
724
|
filename: config.file.filename,
|
|
249
725
|
datePattern: config.file.datePattern ?? "YYYY-MM-DD",
|
|
@@ -253,6 +729,30 @@ function createTransports(config, store) {
|
|
|
253
729
|
})
|
|
254
730
|
);
|
|
255
731
|
}
|
|
732
|
+
if (config.discord) {
|
|
733
|
+
const discord = new DiscordTransport(config.discord);
|
|
734
|
+
discord.format = format.combine(
|
|
735
|
+
createFilterFormat(config.discord.level, config.discord.rules, store),
|
|
736
|
+
format.timestamp()
|
|
737
|
+
);
|
|
738
|
+
result.push(discord);
|
|
739
|
+
}
|
|
740
|
+
if (config.telegram) {
|
|
741
|
+
const telegram = new TelegramTransport(config.telegram);
|
|
742
|
+
telegram.format = format.combine(
|
|
743
|
+
createFilterFormat(config.telegram.level, config.telegram.rules, store),
|
|
744
|
+
format.timestamp()
|
|
745
|
+
);
|
|
746
|
+
result.push(telegram);
|
|
747
|
+
}
|
|
748
|
+
if (config.cloudwatch) {
|
|
749
|
+
const cloudwatch = new CloudWatchTransport(config.cloudwatch);
|
|
750
|
+
cloudwatch.format = format.combine(
|
|
751
|
+
createFilterFormat(config.cloudwatch.level, config.cloudwatch.rules, store),
|
|
752
|
+
format.timestamp()
|
|
753
|
+
);
|
|
754
|
+
result.push(cloudwatch);
|
|
755
|
+
}
|
|
256
756
|
return result;
|
|
257
757
|
}
|
|
258
758
|
function createExceptionHandlers(config, store) {
|
|
@@ -277,28 +777,21 @@ function createExceptionHandlers(config, store) {
|
|
|
277
777
|
return result;
|
|
278
778
|
}
|
|
279
779
|
|
|
280
|
-
// src/
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
http: 3,
|
|
286
|
-
verbose: 4,
|
|
287
|
-
debug: 5,
|
|
288
|
-
silly: 6
|
|
289
|
-
};
|
|
290
|
-
function isValidLogLevel(level) {
|
|
291
|
-
return level in LOG_LEVELS;
|
|
292
|
-
}
|
|
293
|
-
function assertLogLevel(level) {
|
|
294
|
-
if (!isValidLogLevel(level)) {
|
|
295
|
-
throw new Error(`Invalid log level: "${level}". Valid levels: ${Object.keys(LOG_LEVELS).join(", ")}`);
|
|
780
|
+
// src/state.ts
|
|
781
|
+
function parseLevelConfig(level) {
|
|
782
|
+
if (typeof level === "string") {
|
|
783
|
+
assertLogLevel(level);
|
|
784
|
+
return { defaultLevel: level, rules: [] };
|
|
296
785
|
}
|
|
786
|
+
assertLogLevel(level.default);
|
|
787
|
+
const rules = (level.rules ?? []).map((rule) => {
|
|
788
|
+
assertLogLevel(rule.level);
|
|
789
|
+
return { match: rule.match, level: rule.level, readonly: true };
|
|
790
|
+
});
|
|
791
|
+
return { defaultLevel: level.default, rules };
|
|
297
792
|
}
|
|
298
|
-
|
|
299
|
-
// src/state.ts
|
|
300
793
|
function createState(config, store) {
|
|
301
|
-
|
|
794
|
+
const { defaultLevel, rules } = parseLevelConfig(config.level);
|
|
302
795
|
const loggerStore = store ?? new LoggerStore();
|
|
303
796
|
const exceptionHandlers = createExceptionHandlers(config, loggerStore);
|
|
304
797
|
const winston = createLogger({
|
|
@@ -309,11 +802,16 @@ function createState(config, store) {
|
|
|
309
802
|
rejectionHandlers: exceptionHandlers,
|
|
310
803
|
exitOnError: false
|
|
311
804
|
});
|
|
805
|
+
const levelOverrides = /* @__PURE__ */ new Map();
|
|
806
|
+
for (const rule of rules) {
|
|
807
|
+
const key = JSON.stringify(rule.match);
|
|
808
|
+
levelOverrides.set(key, rule);
|
|
809
|
+
}
|
|
312
810
|
return {
|
|
313
811
|
winston,
|
|
314
812
|
store: loggerStore,
|
|
315
|
-
defaultLevel
|
|
316
|
-
levelOverrides
|
|
813
|
+
defaultLevel,
|
|
814
|
+
levelOverrides
|
|
317
815
|
};
|
|
318
816
|
}
|
|
319
817
|
function shouldLog(state, level, context) {
|
|
@@ -358,10 +856,18 @@ var Logger = class _Logger {
|
|
|
358
856
|
}
|
|
359
857
|
removeLevelOverride(match) {
|
|
360
858
|
const key = JSON.stringify(match);
|
|
361
|
-
this.state.levelOverrides.
|
|
859
|
+
const override = this.state.levelOverrides.get(key);
|
|
860
|
+
if (override?.readonly) {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
return this.state.levelOverrides.delete(key);
|
|
362
864
|
}
|
|
363
865
|
clearLevelOverrides() {
|
|
364
|
-
this.state.levelOverrides
|
|
866
|
+
for (const [key, override] of this.state.levelOverrides) {
|
|
867
|
+
if (!override.readonly) {
|
|
868
|
+
this.state.levelOverrides.delete(key);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
365
871
|
}
|
|
366
872
|
getLevelOverrides() {
|
|
367
873
|
return Array.from(this.state.levelOverrides.values());
|
|
@@ -513,6 +1019,6 @@ function getOrGenerateRequestId(headers, options = {}) {
|
|
|
513
1019
|
return extractRequestId(headers) ?? generateRequestId(options);
|
|
514
1020
|
}
|
|
515
1021
|
|
|
516
|
-
export { LOG_LEVELS, Logger, LoggerStore, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatLogfmt, formatLogfmtValue, generateRequestId, getOrGenerateRequestId, isValidLogLevel, maskSecrets, measureAsync, measureSync };
|
|
1022
|
+
export { BaseHttpTransport, CloudWatchTransport, DiscordTransport, LOG_LEVELS, Logger, LoggerStore, MessageBuffer, TelegramTransport, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatLogfmt, formatLogfmtValue, generateRequestId, getOrGenerateRequestId, isValidLogLevel, maskSecrets, matchesContext, measureAsync, measureSync };
|
|
517
1023
|
//# sourceMappingURL=index.mjs.map
|
|
518
1024
|
//# sourceMappingURL=index.mjs.map
|