zario 0.3.1 → 0.3.6
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 +164 -4
- package/dist/cjs/aggregation/LogAggregator.js +131 -0
- package/dist/cjs/aggregation/index.js +17 -0
- package/dist/cjs/core/Formatter.js +3 -4
- package/dist/cjs/core/Logger.js +100 -4
- package/dist/cjs/filters/Filter.js +90 -0
- package/dist/cjs/filters/index.js +17 -0
- package/dist/cjs/index.js +20 -1
- package/dist/cjs/structured/StructuredExtensions.js +112 -0
- package/dist/cjs/structured/index.js +17 -0
- package/dist/cjs/transports/FilterableTransport.js +39 -0
- package/dist/cjs/transports/index.js +1 -0
- package/dist/cjs/utils/index.js +78 -0
- package/dist/esm/aggregation/LogAggregator.d.ts +37 -0
- package/dist/esm/aggregation/LogAggregator.js +125 -0
- package/dist/esm/aggregation/index.d.ts +1 -0
- package/dist/esm/aggregation/index.js +1 -0
- package/dist/esm/core/Formatter.js +1 -2
- package/dist/esm/core/Logger.d.ts +35 -1
- package/dist/esm/core/Logger.js +99 -3
- package/dist/esm/filters/Filter.d.ts +49 -0
- package/dist/esm/filters/Filter.js +79 -0
- package/dist/esm/filters/index.d.ts +1 -0
- package/dist/esm/filters/index.js +1 -0
- package/dist/esm/index.d.ts +7 -3
- package/dist/esm/index.js +14 -2
- package/dist/esm/structured/StructuredExtensions.d.ts +31 -0
- package/dist/esm/structured/StructuredExtensions.js +74 -0
- package/dist/esm/structured/index.d.ts +1 -0
- package/dist/esm/structured/index.js +1 -0
- package/dist/esm/transports/FilterableTransport.d.ts +14 -0
- package/dist/esm/transports/FilterableTransport.js +35 -0
- package/dist/esm/transports/index.d.ts +1 -0
- package/dist/esm/transports/index.js +1 -0
- package/dist/esm/utils/index.d.ts +15 -0
- package/dist/esm/utils/index.js +72 -0
- package/package.json +11 -6
- package/dist/cjs/utils/ColorUtil.js +0 -42
- package/dist/cjs/utils/TimeUtil.js +0 -26
- package/dist/cjs/utils/Timerutil.js +0 -22
- package/dist/esm/utils/ColorUtil.d.ts +0 -4
- package/dist/esm/utils/ColorUtil.js +0 -38
- package/dist/esm/utils/TimeUtil.d.ts +0 -3
- package/dist/esm/utils/TimeUtil.js +0 -22
- package/dist/esm/utils/Timerutil.d.ts +0 -8
- package/dist/esm/utils/Timerutil.js +0 -18
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LogEnrichmentPipeline = exports.MetadataEnricher = void 0;
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
/**
|
|
39
|
+
* Enriches logs with additional metadata
|
|
40
|
+
*/
|
|
41
|
+
class MetadataEnricher {
|
|
42
|
+
static addStaticFields(staticFields) {
|
|
43
|
+
return (logData) => {
|
|
44
|
+
return {
|
|
45
|
+
...logData,
|
|
46
|
+
metadata: {
|
|
47
|
+
...logData.metadata,
|
|
48
|
+
...staticFields
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
static addDynamicFields(dynamicFields) {
|
|
54
|
+
return (logData) => {
|
|
55
|
+
const fields = dynamicFields();
|
|
56
|
+
return {
|
|
57
|
+
...logData,
|
|
58
|
+
metadata: {
|
|
59
|
+
...logData.metadata,
|
|
60
|
+
...fields
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
static addProcessInfo() {
|
|
66
|
+
return (logData) => {
|
|
67
|
+
return {
|
|
68
|
+
...logData,
|
|
69
|
+
metadata: {
|
|
70
|
+
...logData.metadata,
|
|
71
|
+
pid: process.pid,
|
|
72
|
+
hostname: os.hostname(),
|
|
73
|
+
nodeVersion: process.version
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
static addEnvironmentInfo() {
|
|
79
|
+
return (logData) => {
|
|
80
|
+
return {
|
|
81
|
+
...logData,
|
|
82
|
+
metadata: {
|
|
83
|
+
...logData.metadata,
|
|
84
|
+
environment: process.env.NODE_ENV || 'development',
|
|
85
|
+
platform: process.platform,
|
|
86
|
+
arch: process.arch
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.MetadataEnricher = MetadataEnricher;
|
|
93
|
+
MetadataEnricher.addContext = MetadataEnricher.addStaticFields;
|
|
94
|
+
/**
|
|
95
|
+
* Applies a series of enrichers to a log record
|
|
96
|
+
*/
|
|
97
|
+
class LogEnrichmentPipeline {
|
|
98
|
+
constructor(enrichers = []) {
|
|
99
|
+
this.enrichers = enrichers;
|
|
100
|
+
}
|
|
101
|
+
add(enricher) {
|
|
102
|
+
this.enrichers.push(enricher);
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
process(logData) {
|
|
106
|
+
return this.enrichers.reduce((data, enricher) => enricher(data), logData);
|
|
107
|
+
}
|
|
108
|
+
getEnrichers() {
|
|
109
|
+
return [...this.enrichers]; // Return a copy to prevent external modification
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.LogEnrichmentPipeline = LogEnrichmentPipeline;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./StructuredExtensions.js"), exports);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FilterableTransport = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A transport wrapper that applies filters before writing logs
|
|
6
|
+
*/
|
|
7
|
+
class FilterableTransport {
|
|
8
|
+
constructor(transport, filters) {
|
|
9
|
+
this.transport = transport;
|
|
10
|
+
this.filters = filters;
|
|
11
|
+
}
|
|
12
|
+
write(data, formatter) {
|
|
13
|
+
// Check if the log should be emitted based on all filters
|
|
14
|
+
if (this.filters.every(filter => filter.shouldEmit(data))) {
|
|
15
|
+
this.transport.write(data, formatter);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
writeAsync(data, formatter) {
|
|
19
|
+
// Check if the log should be emitted based on all filters
|
|
20
|
+
if (this.filters.every(filter => filter.shouldEmit(data))) {
|
|
21
|
+
if (this.transport.writeAsync) {
|
|
22
|
+
return this.transport.writeAsync(data, formatter);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
try {
|
|
27
|
+
this.transport.write(data, formatter);
|
|
28
|
+
resolve();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
reject(error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.FilterableTransport = FilterableTransport;
|
|
@@ -18,3 +18,4 @@ __exportStar(require("./Transport.js"), exports);
|
|
|
18
18
|
__exportStar(require("./ConsoleTransport.js"), exports);
|
|
19
19
|
__exportStar(require("./FileTransport.js"), exports);
|
|
20
20
|
__exportStar(require("./HttpTransport.js"), exports);
|
|
21
|
+
__exportStar(require("./FilterableTransport.js"), exports);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Timer = exports.TimeUtil = exports.ColorUtil = void 0;
|
|
4
|
+
class ColorUtil {
|
|
5
|
+
static colorize(text, color) {
|
|
6
|
+
const supportsColor = process.env.FORCE_COLOR !== "0" &&
|
|
7
|
+
(process.stdout.isTTY || process.env.FORCE_COLOR === "1");
|
|
8
|
+
if (!supportsColor) {
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
const colorCode = ColorUtil.ANSI_COLORS[color] || ColorUtil.ANSI_COLORS.reset;
|
|
12
|
+
return `${colorCode}${text}${ColorUtil.ANSI_COLORS.reset}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.ColorUtil = ColorUtil;
|
|
16
|
+
ColorUtil.ANSI_COLORS = {
|
|
17
|
+
black: "\x1b[30m",
|
|
18
|
+
red: "\x1b[31m",
|
|
19
|
+
green: "\x1b[32m",
|
|
20
|
+
yellow: "\x1b[33m",
|
|
21
|
+
blue: "\x1b[34m",
|
|
22
|
+
magenta: "\x1b[35m",
|
|
23
|
+
cyan: "\x1b[36m",
|
|
24
|
+
white: "\x1b[37m",
|
|
25
|
+
brightRed: "\x1b[91m",
|
|
26
|
+
brightGreen: "\x1b[92m",
|
|
27
|
+
brightYellow: "\x1b[93m",
|
|
28
|
+
brightBlue: "\x1b[94m",
|
|
29
|
+
brightMagenta: "\x1b[95m",
|
|
30
|
+
brightCyan: "\x1b[96m",
|
|
31
|
+
brightWhite: "\x1b[97m",
|
|
32
|
+
info: "\x1b[32m",
|
|
33
|
+
warn: "\x1b[33m",
|
|
34
|
+
error: "\x1b[31m",
|
|
35
|
+
debug: "\x1b[36m",
|
|
36
|
+
boring: "\x1b[37m",
|
|
37
|
+
reset: "\x1b[0m",
|
|
38
|
+
};
|
|
39
|
+
class TimeUtil {
|
|
40
|
+
static format(date, format) {
|
|
41
|
+
if (format === "ISO")
|
|
42
|
+
return date.toISOString();
|
|
43
|
+
if (format === "UTC")
|
|
44
|
+
return date.toUTCString();
|
|
45
|
+
if (format === "LOCAL")
|
|
46
|
+
return date.toLocaleString();
|
|
47
|
+
const pad = (n, width = 2) => n.toString().padStart(width, "0");
|
|
48
|
+
const tokens = {
|
|
49
|
+
YYYY: pad(date.getFullYear(), 4),
|
|
50
|
+
MM: pad(date.getMonth() + 1),
|
|
51
|
+
DD: pad(date.getDate()),
|
|
52
|
+
HH: pad(date.getHours()),
|
|
53
|
+
mm: pad(date.getMinutes()),
|
|
54
|
+
ss: pad(date.getSeconds()),
|
|
55
|
+
SSS: pad(date.getMilliseconds(), 3),
|
|
56
|
+
};
|
|
57
|
+
return format.replace(/YYYY|MM|DD|HH|mm|ss|SSS/g, (match) => tokens[match] || match);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.TimeUtil = TimeUtil;
|
|
61
|
+
class Timer {
|
|
62
|
+
constructor(name, logFn) {
|
|
63
|
+
this.hasEnded = false;
|
|
64
|
+
this.name = name;
|
|
65
|
+
this.logFn = logFn;
|
|
66
|
+
this.startTime = Date.now();
|
|
67
|
+
}
|
|
68
|
+
end() {
|
|
69
|
+
if (this.hasEnded) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const endTime = Date.now();
|
|
73
|
+
const duration = endTime - this.startTime;
|
|
74
|
+
this.logFn(`${this.name} took ${duration}ms`);
|
|
75
|
+
this.hasEnded = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.Timer = Timer;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LogData } from "../types/index.js";
|
|
2
|
+
import { Formatter } from "../core/Formatter.js";
|
|
3
|
+
export interface LogAggregator {
|
|
4
|
+
aggregate(logData: LogData, formatter: Formatter): void;
|
|
5
|
+
flush(): Promise<void> | void;
|
|
6
|
+
}
|
|
7
|
+
export declare class BatchAggregator implements LogAggregator {
|
|
8
|
+
private logs;
|
|
9
|
+
private maxSize;
|
|
10
|
+
private flushCallback;
|
|
11
|
+
private pendingFlush;
|
|
12
|
+
constructor(maxSize: number | undefined, flushCallback: (logs: {
|
|
13
|
+
logData: LogData;
|
|
14
|
+
formatter: Formatter;
|
|
15
|
+
}[]) => Promise<void> | void);
|
|
16
|
+
aggregate(logData: LogData, formatter: Formatter): void;
|
|
17
|
+
flush(): Promise<void> | void;
|
|
18
|
+
}
|
|
19
|
+
export declare class TimeBasedAggregator implements LogAggregator {
|
|
20
|
+
private logs;
|
|
21
|
+
private flushInterval;
|
|
22
|
+
private flushCallback;
|
|
23
|
+
private timer;
|
|
24
|
+
constructor(flushInterval: number, flushCallback: (logs: {
|
|
25
|
+
logData: LogData;
|
|
26
|
+
formatter: Formatter;
|
|
27
|
+
}[]) => Promise<void> | void);
|
|
28
|
+
aggregate(logData: LogData, formatter: Formatter): void;
|
|
29
|
+
flush(): Promise<void> | void;
|
|
30
|
+
stop(): void;
|
|
31
|
+
}
|
|
32
|
+
export declare class CompositeAggregator implements LogAggregator {
|
|
33
|
+
private aggregators;
|
|
34
|
+
constructor(aggregators: LogAggregator[]);
|
|
35
|
+
aggregate(logData: LogData, formatter: Formatter): void;
|
|
36
|
+
flush(): Promise<void> | void;
|
|
37
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
//Aggregates logs in memory and flushes them in batches
|
|
2
|
+
export class BatchAggregator {
|
|
3
|
+
constructor(maxSize = 100, flushCallback) {
|
|
4
|
+
this.logs = [];
|
|
5
|
+
this.pendingFlush = null;
|
|
6
|
+
this.maxSize = maxSize;
|
|
7
|
+
this.flushCallback = flushCallback;
|
|
8
|
+
}
|
|
9
|
+
aggregate(logData, formatter) {
|
|
10
|
+
this.logs.push({ logData, formatter });
|
|
11
|
+
if (this.logs.length >= this.maxSize && !this.pendingFlush) {
|
|
12
|
+
const result = this.flush();
|
|
13
|
+
if (result instanceof Promise) {
|
|
14
|
+
this.pendingFlush = result.finally(() => {
|
|
15
|
+
this.pendingFlush = null;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
flush() {
|
|
21
|
+
if (this.pendingFlush) {
|
|
22
|
+
return this.pendingFlush;
|
|
23
|
+
}
|
|
24
|
+
if (this.logs.length === 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const logsToFlush = [...this.logs];
|
|
28
|
+
const originalLogs = [...this.logs];
|
|
29
|
+
this.logs = [];
|
|
30
|
+
try {
|
|
31
|
+
const callbackResult = this.flushCallback(logsToFlush);
|
|
32
|
+
if (callbackResult instanceof Promise) {
|
|
33
|
+
return callbackResult.catch((error) => {
|
|
34
|
+
this.logs = originalLogs;
|
|
35
|
+
throw error;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
this.logs = originalLogs;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//Aggregates logs based on a time interval
|
|
46
|
+
export class TimeBasedAggregator {
|
|
47
|
+
constructor(flushInterval, flushCallback) {
|
|
48
|
+
this.logs = [];
|
|
49
|
+
this.timer = null;
|
|
50
|
+
this.flushInterval = flushInterval;
|
|
51
|
+
this.flushCallback = flushCallback;
|
|
52
|
+
}
|
|
53
|
+
aggregate(logData, formatter) {
|
|
54
|
+
this.logs.push({ logData, formatter });
|
|
55
|
+
// Start the timer if it's not already running
|
|
56
|
+
if (!this.timer) {
|
|
57
|
+
this.timer = setTimeout(() => {
|
|
58
|
+
const result = this.flush();
|
|
59
|
+
// Handle the case where flush returns a Promise (async flushCallback)
|
|
60
|
+
if (result instanceof Promise) {
|
|
61
|
+
result.catch((error) => {
|
|
62
|
+
console.error("Error in TimeBasedAggregator flush callback:", error);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}, this.flushInterval);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
flush() {
|
|
69
|
+
if (this.logs.length > 0) {
|
|
70
|
+
// Clear the timer if it exists
|
|
71
|
+
if (this.timer) {
|
|
72
|
+
clearTimeout(this.timer);
|
|
73
|
+
this.timer = null;
|
|
74
|
+
}
|
|
75
|
+
const logsToFlush = [...this.logs];
|
|
76
|
+
const originalLogs = [...this.logs];
|
|
77
|
+
this.logs = [];
|
|
78
|
+
try {
|
|
79
|
+
const callbackResult = this.flushCallback(logsToFlush);
|
|
80
|
+
if (callbackResult instanceof Promise) {
|
|
81
|
+
return callbackResult.catch((error) => {
|
|
82
|
+
this.logs = originalLogs;
|
|
83
|
+
throw error;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.logs = originalLogs;
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//Stop the aggregator and cancel any pending timer without flushing
|
|
94
|
+
stop() {
|
|
95
|
+
if (this.timer) {
|
|
96
|
+
clearTimeout(this.timer);
|
|
97
|
+
this.timer = null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//Combines multiple aggregators
|
|
102
|
+
export class CompositeAggregator {
|
|
103
|
+
constructor(aggregators) {
|
|
104
|
+
this.aggregators = aggregators;
|
|
105
|
+
}
|
|
106
|
+
aggregate(logData, formatter) {
|
|
107
|
+
for (const aggregator of this.aggregators) {
|
|
108
|
+
aggregator.aggregate(logData, formatter);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
flush() {
|
|
112
|
+
const results = [];
|
|
113
|
+
for (const aggregator of this.aggregators) {
|
|
114
|
+
const result = aggregator.flush();
|
|
115
|
+
if (result) {
|
|
116
|
+
results.push(result);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// If any aggregator returns a promise, wait for all of them
|
|
120
|
+
if (results.some((r) => r instanceof Promise)) {
|
|
121
|
+
const promiseResults = results.filter((r) => r instanceof Promise);
|
|
122
|
+
return Promise.all(promiseResults).then(() => { });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LogAggregator.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LogAggregator.js';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { TimeUtil } from "../utils/
|
|
2
|
-
import { ColorUtil } from "../utils/ColorUtil.js";
|
|
1
|
+
import { TimeUtil, ColorUtil } from "../utils/index.js";
|
|
3
2
|
export class Formatter {
|
|
4
3
|
constructor(options = {}) {
|
|
5
4
|
const { colorize = true, json = false, timestampFormat = "YYYY-MM-DD HH:mm:ss", timestamp = false, customColors = {}, } = options;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { LogLevel } from "./LogLevel.js";
|
|
2
2
|
import { Transport } from "../transports/Transport.js";
|
|
3
3
|
import { TransportConfig } from "../types/index.js";
|
|
4
|
+
import { Filter } from "../filters/Filter.js";
|
|
5
|
+
import { LogAggregator } from "../aggregation/LogAggregator.js";
|
|
6
|
+
import { LogEnricher, LogEnrichmentPipeline } from "../structured/StructuredExtensions.js";
|
|
7
|
+
import { Timer } from "../utils/index.js";
|
|
4
8
|
export interface LoggerOptions {
|
|
5
9
|
level?: LogLevel;
|
|
6
10
|
colorize?: boolean;
|
|
@@ -18,6 +22,9 @@ export interface LoggerOptions {
|
|
|
18
22
|
customColors?: {
|
|
19
23
|
[level: string]: string;
|
|
20
24
|
};
|
|
25
|
+
filters?: Filter[];
|
|
26
|
+
aggregators?: LogAggregator[];
|
|
27
|
+
enrichers?: LogEnrichmentPipeline;
|
|
21
28
|
}
|
|
22
29
|
export declare class Logger {
|
|
23
30
|
private level;
|
|
@@ -27,6 +34,9 @@ export declare class Logger {
|
|
|
27
34
|
private parent;
|
|
28
35
|
private asyncMode;
|
|
29
36
|
private customLevels;
|
|
37
|
+
private filters;
|
|
38
|
+
private aggregators;
|
|
39
|
+
private enrichers;
|
|
30
40
|
private static _global;
|
|
31
41
|
static defaultTransportsFactory: ((isProd: boolean) => TransportConfig[]) | null;
|
|
32
42
|
private static readonly LEVEL_PRIORITIES;
|
|
@@ -62,5 +72,29 @@ export declare class Logger {
|
|
|
62
72
|
getTimestampSetting(): boolean;
|
|
63
73
|
static get global(): Logger;
|
|
64
74
|
createChild(options?: LoggerOptions): Logger;
|
|
65
|
-
startTimer(name: string):
|
|
75
|
+
startTimer(name: string): Timer;
|
|
76
|
+
/**
|
|
77
|
+
* Add a filter to the logger
|
|
78
|
+
*/
|
|
79
|
+
addFilter(filter: Filter): void;
|
|
80
|
+
/**
|
|
81
|
+
* Remove a filter from the logger
|
|
82
|
+
*/
|
|
83
|
+
removeFilter(filter: Filter): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Add an aggregator to the logger
|
|
86
|
+
*/
|
|
87
|
+
addAggregator(aggregator: LogAggregator): void;
|
|
88
|
+
/**
|
|
89
|
+
* Remove an aggregator from the logger
|
|
90
|
+
*/
|
|
91
|
+
removeAggregator(aggregator: LogAggregator): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Add an enricher to the logger
|
|
94
|
+
*/
|
|
95
|
+
addEnricher(enricher: LogEnricher): void;
|
|
96
|
+
/**
|
|
97
|
+
* Flush all aggregators
|
|
98
|
+
*/
|
|
99
|
+
flushAggregators(): Promise<void>;
|
|
66
100
|
}
|
package/dist/esm/core/Logger.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { Formatter } from "./Formatter.js";
|
|
2
2
|
import { ConsoleTransport } from "../transports/ConsoleTransport.js";
|
|
3
|
+
import { LogEnrichmentPipeline } from "../structured/StructuredExtensions.js";
|
|
4
|
+
import { Timer } from "../utils/index.js";
|
|
3
5
|
export class Logger {
|
|
4
6
|
constructor(options = {}) {
|
|
5
7
|
this.transports = [];
|
|
6
|
-
|
|
8
|
+
this.filters = [];
|
|
9
|
+
this.aggregators = [];
|
|
10
|
+
const { level, colorize, json, transports = [], timestampFormat = "YYYY-MM-DD HH:mm:ss", prefix, timestamp, context = {}, parent, asyncMode, customLevels = {}, customColors = {}, filters = [], aggregators = [], enrichers, } = options;
|
|
7
11
|
this.parent = parent; // Set parent
|
|
8
12
|
this.context = { ...context }; // Init context
|
|
9
13
|
this.customLevels = customLevels; // custom log store
|
|
10
14
|
this.asyncMode = false;
|
|
15
|
+
this.filters = [...filters]; // Copy filters
|
|
16
|
+
this.aggregators = [...aggregators]; // Copy aggregators
|
|
17
|
+
this.enrichers = enrichers ?? new LogEnrichmentPipeline(); // Set enrichers, default to new instance
|
|
11
18
|
if (this.parent) {
|
|
12
19
|
this.level = level ?? this.parent.level;
|
|
13
20
|
this.prefix = prefix ?? this.parent.prefix;
|
|
@@ -33,6 +40,21 @@ export class Logger {
|
|
|
33
40
|
this.context = { ...this.parent.context, ...this.context };
|
|
34
41
|
// Merge custom levels with parent's custom levels
|
|
35
42
|
this.customLevels = { ...this.parent.customLevels, ...customLevels };
|
|
43
|
+
// Merge filters with parent's filters
|
|
44
|
+
this.filters = [...this.parent.filters, ...filters];
|
|
45
|
+
// Merge aggregators with parent's aggregators
|
|
46
|
+
this.aggregators = [...this.parent.aggregators, ...aggregators];
|
|
47
|
+
// If child logger doesn't provide its own enrichers, use parent's
|
|
48
|
+
// If child logger provides enrichers, merge parent and child enrichers
|
|
49
|
+
if (enrichers) {
|
|
50
|
+
// Create a new pipeline that combines parent and child enrichers
|
|
51
|
+
const parentEnrichers = this.parent.enrichers.getEnrichers();
|
|
52
|
+
const childEnrichers = enrichers.getEnrichers();
|
|
53
|
+
this.enrichers = new LogEnrichmentPipeline([...parentEnrichers, ...childEnrichers]);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.enrichers = this.parent.enrichers;
|
|
57
|
+
}
|
|
36
58
|
}
|
|
37
59
|
else {
|
|
38
60
|
// Auto-configure based on environment
|
|
@@ -137,7 +159,7 @@ export class Logger {
|
|
|
137
159
|
finalMetadata = metadata;
|
|
138
160
|
}
|
|
139
161
|
// Only add metadata if it's not empty after merging
|
|
140
|
-
|
|
162
|
+
let logData = {
|
|
141
163
|
level,
|
|
142
164
|
message,
|
|
143
165
|
timestamp,
|
|
@@ -146,6 +168,17 @@ export class Logger {
|
|
|
146
168
|
: undefined,
|
|
147
169
|
prefix: this.prefix,
|
|
148
170
|
};
|
|
171
|
+
// Apply enrichers to the log data
|
|
172
|
+
logData = this.enrichers.process(logData);
|
|
173
|
+
// Check if the log should be emitted based on filters
|
|
174
|
+
// Use a copy to prevent concurrent modification issues if filters are modified during logging
|
|
175
|
+
const currentFilters = [...this.filters];
|
|
176
|
+
if (currentFilters.length > 0) {
|
|
177
|
+
const shouldEmit = currentFilters.every(filter => filter.shouldEmit(logData));
|
|
178
|
+
if (!shouldEmit) {
|
|
179
|
+
return; // Don't emit if any filter rejects the log
|
|
180
|
+
}
|
|
181
|
+
}
|
|
149
182
|
if (this.asyncMode) {
|
|
150
183
|
for (const transport of this.transports) {
|
|
151
184
|
if (transport.writeAsync) {
|
|
@@ -165,6 +198,17 @@ export class Logger {
|
|
|
165
198
|
transport.write(logData, this.formatter);
|
|
166
199
|
}
|
|
167
200
|
}
|
|
201
|
+
// Send to aggregators if any exist
|
|
202
|
+
if (this.aggregators.length > 0) {
|
|
203
|
+
for (const aggregator of this.aggregators) {
|
|
204
|
+
try {
|
|
205
|
+
aggregator.aggregate(logData, this.formatter);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.error('Error in aggregator:', error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
168
212
|
}
|
|
169
213
|
debug(message, metadata) {
|
|
170
214
|
this.log("debug", message, metadata);
|
|
@@ -215,9 +259,61 @@ export class Logger {
|
|
|
215
259
|
return new Logger({ ...options, parent: this });
|
|
216
260
|
}
|
|
217
261
|
startTimer(name) {
|
|
218
|
-
const { Timer } = require("../utils/Timerutil");
|
|
219
262
|
return new Timer(name, (message) => this.info(message));
|
|
220
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Add a filter to the logger
|
|
266
|
+
*/
|
|
267
|
+
addFilter(filter) {
|
|
268
|
+
this.filters.push(filter);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Remove a filter from the logger
|
|
272
|
+
*/
|
|
273
|
+
removeFilter(filter) {
|
|
274
|
+
const index = this.filters.indexOf(filter);
|
|
275
|
+
if (index !== -1) {
|
|
276
|
+
this.filters.splice(index, 1);
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Add an aggregator to the logger
|
|
283
|
+
*/
|
|
284
|
+
addAggregator(aggregator) {
|
|
285
|
+
this.aggregators.push(aggregator);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Remove an aggregator from the logger
|
|
289
|
+
*/
|
|
290
|
+
removeAggregator(aggregator) {
|
|
291
|
+
const index = this.aggregators.indexOf(aggregator);
|
|
292
|
+
if (index !== -1) {
|
|
293
|
+
this.aggregators.splice(index, 1);
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Add an enricher to the logger
|
|
300
|
+
*/
|
|
301
|
+
addEnricher(enricher) {
|
|
302
|
+
this.enrichers.add(enricher);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Flush all aggregators
|
|
306
|
+
*/
|
|
307
|
+
async flushAggregators() {
|
|
308
|
+
const flushPromises = [];
|
|
309
|
+
for (const aggregator of this.aggregators) {
|
|
310
|
+
const result = aggregator.flush();
|
|
311
|
+
if (result instanceof Promise) {
|
|
312
|
+
flushPromises.push(result);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
await Promise.all(flushPromises);
|
|
316
|
+
}
|
|
221
317
|
}
|
|
222
318
|
Logger.defaultTransportsFactory = null;
|
|
223
319
|
Logger.LEVEL_PRIORITIES = {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { LogData } from '../types/index.js';
|
|
2
|
+
import { LogLevel } from '../core/LogLevel.js';
|
|
3
|
+
export interface Filter {
|
|
4
|
+
shouldEmit(logData: LogData): boolean;
|
|
5
|
+
}
|
|
6
|
+
export type FilterPredicate = (logData: LogData) => boolean;
|
|
7
|
+
export declare class CompositeFilter implements Filter {
|
|
8
|
+
private filters;
|
|
9
|
+
constructor(filters: Filter[]);
|
|
10
|
+
shouldEmit(logData: LogData): boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class OrFilter implements Filter {
|
|
13
|
+
private filters;
|
|
14
|
+
constructor(filters: Filter[]);
|
|
15
|
+
shouldEmit(logData: LogData): boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare class NotFilter implements Filter {
|
|
18
|
+
private filter;
|
|
19
|
+
constructor(filter: Filter);
|
|
20
|
+
shouldEmit(logData: LogData): boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare class PredicateFilter implements Filter {
|
|
23
|
+
private predicate;
|
|
24
|
+
constructor(predicate: FilterPredicate);
|
|
25
|
+
shouldEmit(logData: LogData): boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare class LevelFilter implements Filter {
|
|
28
|
+
private allowedLevels;
|
|
29
|
+
constructor(allowedLevels: LogLevel[]);
|
|
30
|
+
shouldEmit(logData: LogData): boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare class PrefixFilter implements Filter {
|
|
33
|
+
private allowedPrefixes;
|
|
34
|
+
constructor(allowedPrefixes: string[]);
|
|
35
|
+
shouldEmit(logData: LogData): boolean;
|
|
36
|
+
}
|
|
37
|
+
export declare class MetadataFilter implements Filter {
|
|
38
|
+
private requiredMetadata;
|
|
39
|
+
constructor(requiredMetadata: {
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
});
|
|
42
|
+
shouldEmit(logData: LogData): boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare class FieldFilter implements Filter {
|
|
45
|
+
private fieldName;
|
|
46
|
+
private expectedValue;
|
|
47
|
+
constructor(fieldName: string, expectedValue: any);
|
|
48
|
+
shouldEmit(logData: LogData): boolean;
|
|
49
|
+
}
|