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.
Files changed (46) hide show
  1. package/README.md +164 -4
  2. package/dist/cjs/aggregation/LogAggregator.js +131 -0
  3. package/dist/cjs/aggregation/index.js +17 -0
  4. package/dist/cjs/core/Formatter.js +3 -4
  5. package/dist/cjs/core/Logger.js +100 -4
  6. package/dist/cjs/filters/Filter.js +90 -0
  7. package/dist/cjs/filters/index.js +17 -0
  8. package/dist/cjs/index.js +20 -1
  9. package/dist/cjs/structured/StructuredExtensions.js +112 -0
  10. package/dist/cjs/structured/index.js +17 -0
  11. package/dist/cjs/transports/FilterableTransport.js +39 -0
  12. package/dist/cjs/transports/index.js +1 -0
  13. package/dist/cjs/utils/index.js +78 -0
  14. package/dist/esm/aggregation/LogAggregator.d.ts +37 -0
  15. package/dist/esm/aggregation/LogAggregator.js +125 -0
  16. package/dist/esm/aggregation/index.d.ts +1 -0
  17. package/dist/esm/aggregation/index.js +1 -0
  18. package/dist/esm/core/Formatter.js +1 -2
  19. package/dist/esm/core/Logger.d.ts +35 -1
  20. package/dist/esm/core/Logger.js +99 -3
  21. package/dist/esm/filters/Filter.d.ts +49 -0
  22. package/dist/esm/filters/Filter.js +79 -0
  23. package/dist/esm/filters/index.d.ts +1 -0
  24. package/dist/esm/filters/index.js +1 -0
  25. package/dist/esm/index.d.ts +7 -3
  26. package/dist/esm/index.js +14 -2
  27. package/dist/esm/structured/StructuredExtensions.d.ts +31 -0
  28. package/dist/esm/structured/StructuredExtensions.js +74 -0
  29. package/dist/esm/structured/index.d.ts +1 -0
  30. package/dist/esm/structured/index.js +1 -0
  31. package/dist/esm/transports/FilterableTransport.d.ts +14 -0
  32. package/dist/esm/transports/FilterableTransport.js +35 -0
  33. package/dist/esm/transports/index.d.ts +1 -0
  34. package/dist/esm/transports/index.js +1 -0
  35. package/dist/esm/utils/index.d.ts +15 -0
  36. package/dist/esm/utils/index.js +72 -0
  37. package/package.json +11 -6
  38. package/dist/cjs/utils/ColorUtil.js +0 -42
  39. package/dist/cjs/utils/TimeUtil.js +0 -26
  40. package/dist/cjs/utils/Timerutil.js +0 -22
  41. package/dist/esm/utils/ColorUtil.d.ts +0 -4
  42. package/dist/esm/utils/ColorUtil.js +0 -38
  43. package/dist/esm/utils/TimeUtil.d.ts +0 -3
  44. package/dist/esm/utils/TimeUtil.js +0 -22
  45. package/dist/esm/utils/Timerutil.d.ts +0 -8
  46. 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/TimeUtil.js";
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): any;
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
  }
@@ -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
- const { level, colorize, json, transports = [], timestampFormat = "YYYY-MM-DD HH:mm:ss", prefix, timestamp, context = {}, parent, asyncMode, customLevels = {}, customColors = {}, } = options;
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
- const logData = {
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
+ }