@nu-art/logger 0.401.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BeLogged.d.ts +92 -0
- package/BeLogged.js +124 -0
- package/LogClient.d.ts +126 -0
- package/LogClient.js +143 -0
- package/LogClient_BaseRotate.d.ts +91 -0
- package/LogClient_BaseRotate.js +109 -0
- package/LogClient_Browser.d.ts +38 -0
- package/LogClient_Browser.js +92 -0
- package/LogClient_BrowserGroups.d.ts +50 -0
- package/LogClient_BrowserGroups.js +112 -0
- package/LogClient_ConsoleProxy.d.ts +108 -0
- package/LogClient_ConsoleProxy.js +179 -0
- package/LogClient_File.d.ts +58 -0
- package/LogClient_File.js +89 -0
- package/LogClient_Function.d.ts +31 -0
- package/LogClient_Function.js +63 -0
- package/LogClient_MemBuffer.d.ts +88 -0
- package/LogClient_MemBuffer.js +139 -0
- package/LogClient_Terminal.d.ts +49 -0
- package/LogClient_Terminal.js +81 -0
- package/Logger.d.ts +237 -0
- package/Logger.js +316 -0
- package/debug-flags.d.ts +145 -0
- package/debug-flags.js +196 -0
- package/get-log-style.d.ts +27 -0
- package/get-log-style.js +29 -0
- package/index.d.ts +15 -0
- package/index.js +20 -0
- package/package.json +52 -0
- package/types.d.ts +32 -0
- package/types.js +30 -0
- package/utils.d.ts +49 -0
- package/utils.js +106 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LogLevel, LogParam } from './types.js';
|
|
2
|
+
import { LogClient } from './LogClient.js';
|
|
3
|
+
/**
|
|
4
|
+
* Log client implementation for browser console output with CSS styling.
|
|
5
|
+
*
|
|
6
|
+
* Uses browser console's `%c` formatting to apply CSS styles to log messages.
|
|
7
|
+
* Different log levels are styled with different colors for visual distinction.
|
|
8
|
+
*/
|
|
9
|
+
declare class LogClient_Browser_class extends LogClient {
|
|
10
|
+
/** CSS styles for different log levels */
|
|
11
|
+
private style;
|
|
12
|
+
/**
|
|
13
|
+
* Gets the CSS style string for a log level.
|
|
14
|
+
*
|
|
15
|
+
* Returns a CSS style string compatible with browser console's `%c` formatting
|
|
16
|
+
* for the given log level. Combines base styles with level-specific colors.
|
|
17
|
+
*
|
|
18
|
+
* @param level - Log level
|
|
19
|
+
* @param bold - Whether to apply bold formatting (not currently used)
|
|
20
|
+
* @returns CSS style string for console.log formatting
|
|
21
|
+
*/
|
|
22
|
+
getColor(level: LogLevel, bold: boolean): string;
|
|
23
|
+
/**
|
|
24
|
+
* Outputs a log message to the browser console with CSS styling.
|
|
25
|
+
*
|
|
26
|
+
* Uses `%c` formatting to apply styles. Strings are concatenated with the prefix,
|
|
27
|
+
* while objects are passed as separate arguments to preserve browser console's
|
|
28
|
+
* object inspection capabilities.
|
|
29
|
+
*
|
|
30
|
+
* @param level - Log level
|
|
31
|
+
* @param bold - Whether to apply bold formatting (not currently used in browser)
|
|
32
|
+
* @param prefix - Composed prefix string
|
|
33
|
+
* @param toLog - Array of values to log
|
|
34
|
+
*/
|
|
35
|
+
protected logMessage(level: LogLevel, bold: boolean, prefix: string, toLog: LogParam[]): void;
|
|
36
|
+
}
|
|
37
|
+
export declare const LogClient_Browser: LogClient_Browser_class;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @nu-art/logger - Flexible logging infrastructure with multiple output targets
|
|
3
|
+
* Copyright (C) 2024 Adam van der Kruk aka TacB0sS
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
import { LogLevel } from './types.js';
|
|
7
|
+
import { LogClient } from './LogClient.js';
|
|
8
|
+
import { getLogStyle } from './get-log-style.js';
|
|
9
|
+
/**
|
|
10
|
+
* Log client implementation for browser console output with CSS styling.
|
|
11
|
+
*
|
|
12
|
+
* Uses browser console's `%c` formatting to apply CSS styles to log messages.
|
|
13
|
+
* Different log levels are styled with different colors for visual distinction.
|
|
14
|
+
*/
|
|
15
|
+
class LogClient_Browser_class extends LogClient {
|
|
16
|
+
/** CSS styles for different log levels */
|
|
17
|
+
style = {
|
|
18
|
+
base: {
|
|
19
|
+
// 'background-color': '#fff',
|
|
20
|
+
'padding': '2px 0px',
|
|
21
|
+
'border-radius': '2px',
|
|
22
|
+
},
|
|
23
|
+
verbose: {
|
|
24
|
+
'color': '#808080',
|
|
25
|
+
'background-color': 'unset'
|
|
26
|
+
},
|
|
27
|
+
debug: {
|
|
28
|
+
'color': '#6564c9',
|
|
29
|
+
},
|
|
30
|
+
info: {
|
|
31
|
+
'color': '#189702',
|
|
32
|
+
},
|
|
33
|
+
warning: {
|
|
34
|
+
'color': '#926E00',
|
|
35
|
+
},
|
|
36
|
+
error: {
|
|
37
|
+
'color': '#B40000',
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Gets the CSS style string for a log level.
|
|
42
|
+
*
|
|
43
|
+
* Returns a CSS style string compatible with browser console's `%c` formatting
|
|
44
|
+
* for the given log level. Combines base styles with level-specific colors.
|
|
45
|
+
*
|
|
46
|
+
* @param level - Log level
|
|
47
|
+
* @param bold - Whether to apply bold formatting (not currently used)
|
|
48
|
+
* @returns CSS style string for console.log formatting
|
|
49
|
+
*/
|
|
50
|
+
getColor(level, bold) {
|
|
51
|
+
switch (level) {
|
|
52
|
+
case LogLevel.Verbose:
|
|
53
|
+
return getLogStyle(this.style.base, this.style.verbose);
|
|
54
|
+
case LogLevel.Debug:
|
|
55
|
+
return getLogStyle(this.style.base, this.style.debug);
|
|
56
|
+
case LogLevel.Info:
|
|
57
|
+
return getLogStyle(this.style.base, this.style.info);
|
|
58
|
+
case LogLevel.Warning:
|
|
59
|
+
return getLogStyle(this.style.base, this.style.warning);
|
|
60
|
+
case LogLevel.Error:
|
|
61
|
+
return getLogStyle(this.style.base, this.style.error);
|
|
62
|
+
default:
|
|
63
|
+
return getLogStyle({ 'color': '#000000' });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Outputs a log message to the browser console with CSS styling.
|
|
68
|
+
*
|
|
69
|
+
* Uses `%c` formatting to apply styles. Strings are concatenated with the prefix,
|
|
70
|
+
* while objects are passed as separate arguments to preserve browser console's
|
|
71
|
+
* object inspection capabilities.
|
|
72
|
+
*
|
|
73
|
+
* @param level - Log level
|
|
74
|
+
* @param bold - Whether to apply bold formatting (not currently used in browser)
|
|
75
|
+
* @param prefix - Composed prefix string
|
|
76
|
+
* @param toLog - Array of values to log
|
|
77
|
+
*/
|
|
78
|
+
logMessage(level, bold, prefix, toLog) {
|
|
79
|
+
for (const param of toLog) {
|
|
80
|
+
if (typeof param === 'string') {
|
|
81
|
+
console.log(`%c${prefix}${param}`, this.getColor(level, bold));
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (typeof param === 'object') {
|
|
85
|
+
console.log(`%c${prefix}`, this.getColor(level, bold), param);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
console.log(`%c${prefix}`, this.getColor(level, bold), param);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export const LogClient_Browser = new LogClient_Browser_class();
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { LogClient } from './LogClient.js';
|
|
2
|
+
import { LogLevel, LogParam } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* CSS style object for browser console styling.
|
|
5
|
+
*
|
|
6
|
+
* Defines CSS properties that can be applied to log messages using browser
|
|
7
|
+
* console's `%c` formatting. Used by LogClient_BrowserGroups for styled output.
|
|
8
|
+
*/
|
|
9
|
+
export type LoggerStyleObject = {
|
|
10
|
+
color?: string;
|
|
11
|
+
'background-color'?: string;
|
|
12
|
+
'font-weight'?: 'bold' | 'normal';
|
|
13
|
+
padding?: string;
|
|
14
|
+
'border-radius'?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Log client for browser console with grouped output and styled prefixes.
|
|
18
|
+
*
|
|
19
|
+
* Uses browser console's grouping feature (console.groupCollapsed) to organize
|
|
20
|
+
* logs. Applies CSS styling to different parts of the log prefix (level, timestamp, tag)
|
|
21
|
+
* for visual distinction. If the first log parameter is a primitive, it's combined
|
|
22
|
+
* with the prefix for cleaner output.
|
|
23
|
+
*/
|
|
24
|
+
declare class LogClient_BrowserGroups_Class extends LogClient {
|
|
25
|
+
constructor();
|
|
26
|
+
private newComposer;
|
|
27
|
+
/**
|
|
28
|
+
* Outputs log messages with browser console grouping and styling.
|
|
29
|
+
*
|
|
30
|
+
* If the first parameter is a primitive (string/number/boolean), it's combined
|
|
31
|
+
* with the prefix for cleaner single-line output. Otherwise, uses console.groupCollapsed
|
|
32
|
+
* to create a collapsible group with the prefix as the header and remaining parameters
|
|
33
|
+
* as grouped content.
|
|
34
|
+
*
|
|
35
|
+
* @param level - Log level
|
|
36
|
+
* @param bold - Whether to apply bold formatting
|
|
37
|
+
* @param prefix - Composed prefix string (with %c markers for styling)
|
|
38
|
+
* @param toLog - Array of values to log
|
|
39
|
+
*/
|
|
40
|
+
protected logMessage(level: LogLevel, bold: boolean, prefix: string, toLog: LogParam[]): void;
|
|
41
|
+
private logSingle;
|
|
42
|
+
private logGroup;
|
|
43
|
+
private getLogLevelColor;
|
|
44
|
+
private composeStyleString;
|
|
45
|
+
private getLogLevelStyling;
|
|
46
|
+
private getTimestampStyling;
|
|
47
|
+
private getTagStyling;
|
|
48
|
+
}
|
|
49
|
+
export declare const LogClient_BrowserGroups: LogClient_BrowserGroups_Class;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @nu-art/logger - Flexible logging infrastructure with multiple output targets
|
|
3
|
+
* Copyright (C) 2024 Adam van der Kruk aka TacB0sS
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
import { _logger_finalDate, _logger_getPrefix, _logger_timezoneOffset, LogClient } from './LogClient.js';
|
|
7
|
+
import { LogLevel } from './types.js';
|
|
8
|
+
/** Array of primitive types that can be combined with prefix */
|
|
9
|
+
const PrimitiveLogParams = ['string', 'number', 'boolean'];
|
|
10
|
+
/**
|
|
11
|
+
* Log client for browser console with grouped output and styled prefixes.
|
|
12
|
+
*
|
|
13
|
+
* Uses browser console's grouping feature (console.groupCollapsed) to organize
|
|
14
|
+
* logs. Applies CSS styling to different parts of the log prefix (level, timestamp, tag)
|
|
15
|
+
* for visual distinction. If the first log parameter is a primitive, it's combined
|
|
16
|
+
* with the prefix for cleaner output.
|
|
17
|
+
*/
|
|
18
|
+
class LogClient_BrowserGroups_Class extends LogClient {
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.setComposer(this.newComposer);
|
|
22
|
+
}
|
|
23
|
+
// ################## Class Methods - Logging ##################
|
|
24
|
+
newComposer(tag, level) {
|
|
25
|
+
_logger_finalDate.setTime(Date.now() - _logger_timezoneOffset);
|
|
26
|
+
const date = _logger_finalDate.toISOString().replace(/T/, '_').replace(/Z/, '').substring(0, 23);
|
|
27
|
+
return `%c${_logger_getPrefix(level)}%c${date}%c${tag}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Outputs log messages with browser console grouping and styling.
|
|
31
|
+
*
|
|
32
|
+
* If the first parameter is a primitive (string/number/boolean), it's combined
|
|
33
|
+
* with the prefix for cleaner single-line output. Otherwise, uses console.groupCollapsed
|
|
34
|
+
* to create a collapsible group with the prefix as the header and remaining parameters
|
|
35
|
+
* as grouped content.
|
|
36
|
+
*
|
|
37
|
+
* @param level - Log level
|
|
38
|
+
* @param bold - Whether to apply bold formatting
|
|
39
|
+
* @param prefix - Composed prefix string (with %c markers for styling)
|
|
40
|
+
* @param toLog - Array of values to log
|
|
41
|
+
*/
|
|
42
|
+
logMessage(level, bold, prefix, toLog) {
|
|
43
|
+
if (!prefix.startsWith('%c'))
|
|
44
|
+
prefix = `%c ${prefix}`;
|
|
45
|
+
//If the first log param is a primitive combine it with the prefix
|
|
46
|
+
if (toLog[0] != null && PrimitiveLogParams.includes(typeof toLog[0])) {
|
|
47
|
+
prefix += ` ${String(toLog[0])}`;
|
|
48
|
+
toLog.shift();
|
|
49
|
+
}
|
|
50
|
+
//If no more items to log
|
|
51
|
+
if (!toLog.length)
|
|
52
|
+
return this.logSingle(level, bold, prefix);
|
|
53
|
+
this.logGroup(level, bold, prefix, toLog);
|
|
54
|
+
}
|
|
55
|
+
logSingle = (logLevel, bold, toLog) => {
|
|
56
|
+
console.log(toLog, this.getLogLevelStyling(logLevel, bold), this.getTimestampStyling(bold, logLevel), this.getTagStyling(logLevel, bold));
|
|
57
|
+
};
|
|
58
|
+
logGroup = (logLevel, bold, prefix, toLog) => {
|
|
59
|
+
// group & groupCollapsed print the same thing, only groupCollapsed is collapsed by default.
|
|
60
|
+
// console.group(
|
|
61
|
+
console.groupCollapsed(prefix, this.getLogLevelStyling(logLevel, bold), this.getTimestampStyling(bold, logLevel), this.getTagStyling(logLevel, bold));
|
|
62
|
+
toLog.forEach(logParam => console.log(logParam));
|
|
63
|
+
console.groupEnd();
|
|
64
|
+
};
|
|
65
|
+
// ################## Class Methods - Styling ##################
|
|
66
|
+
getLogLevelColor = (logLevel) => {
|
|
67
|
+
switch (logLevel) {
|
|
68
|
+
case LogLevel.Verbose:
|
|
69
|
+
return '#444444';
|
|
70
|
+
case LogLevel.Debug:
|
|
71
|
+
return '#3066be';
|
|
72
|
+
case LogLevel.Info:
|
|
73
|
+
return '#52a447';
|
|
74
|
+
case LogLevel.Warning:
|
|
75
|
+
return '#ed820e';
|
|
76
|
+
case LogLevel.Error:
|
|
77
|
+
return '#d14348';
|
|
78
|
+
default:
|
|
79
|
+
return 'transparent';
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
composeStyleString = (styleObject) => {
|
|
83
|
+
const styleArr = Object.keys(styleObject).map((key) => `${key}: ${styleObject[key]}`);
|
|
84
|
+
return styleArr.join(';') + ';';
|
|
85
|
+
};
|
|
86
|
+
getLogLevelStyling = (logLevel, bold) => {
|
|
87
|
+
return this.composeStyleString({
|
|
88
|
+
color: '#ffffff',
|
|
89
|
+
'background-color': this.getLogLevelColor(logLevel),
|
|
90
|
+
'font-weight': bold ? 'bold' : 'normal',
|
|
91
|
+
padding: '2px 5px',
|
|
92
|
+
'border-radius': '4px 0 0 4px',
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
getTimestampStyling = (bold, logLevel) => {
|
|
96
|
+
return this.composeStyleString({
|
|
97
|
+
color: '#ffffff',
|
|
98
|
+
'background-color': this.getLogLevelColor(logLevel),
|
|
99
|
+
'font-weight': bold ? 'bold' : 'normal',
|
|
100
|
+
padding: '2px 5px',
|
|
101
|
+
'border-radius': '0 4px 4px 0',
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
getTagStyling = (logLevel, bold) => {
|
|
105
|
+
return this.composeStyleString({
|
|
106
|
+
color: this.getLogLevelColor(logLevel),
|
|
107
|
+
'font-weight': bold ? 'bold' : 'normal',
|
|
108
|
+
padding: '2px 5px',
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export const LogClient_BrowserGroups = new LogClient_BrowserGroups_Class();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { LogClient } from './LogClient.js';
|
|
2
|
+
import { LogLevel, LogParam } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Structure for log entries sent to remote endpoints.
|
|
5
|
+
*
|
|
6
|
+
* Used by LogClient_ConsoleProxy and its subclasses to format log messages
|
|
7
|
+
* before sending them to remote logging services.
|
|
8
|
+
*/
|
|
9
|
+
export type LogToStream = {
|
|
10
|
+
/** Log severity level */
|
|
11
|
+
severity: LogLevel;
|
|
12
|
+
/** Formatted log content */
|
|
13
|
+
logContent: string;
|
|
14
|
+
/** Logger tag/reporter name */
|
|
15
|
+
reporter: string;
|
|
16
|
+
/** Timestamp string */
|
|
17
|
+
timestamp: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Abstract base class for log clients that proxy logs to remote endpoints.
|
|
21
|
+
*
|
|
22
|
+
* Buffers log messages and sends them in batches to reduce network overhead.
|
|
23
|
+
* Automatically intercepts `console.error` calls and includes them in the log stream.
|
|
24
|
+
*
|
|
25
|
+
* Features:
|
|
26
|
+
* - Batched sending (flushes when buffer reaches maxBuffers or after timeout)
|
|
27
|
+
* - Automatic retry logic with exponential backoff
|
|
28
|
+
* - Immediate flush on error-level logs
|
|
29
|
+
* - Periodic flushing via setInterval (every 2 minutes)
|
|
30
|
+
*
|
|
31
|
+
* Subclasses must implement `sendLogsToEndpoint()` to define the actual sending mechanism.
|
|
32
|
+
*/
|
|
33
|
+
export declare abstract class LogClient_ConsoleProxy extends LogClient {
|
|
34
|
+
/** Buffer of log entries waiting to be sent */
|
|
35
|
+
private buffers;
|
|
36
|
+
/** Maximum number of logs to buffer before forcing a flush */
|
|
37
|
+
private readonly maxBuffers;
|
|
38
|
+
/** Interval handle for periodic log flushing */
|
|
39
|
+
private flushInterval?;
|
|
40
|
+
/** Original console.error function (saved before interception) */
|
|
41
|
+
private readonly originalConsoleError;
|
|
42
|
+
/** Flag indicating if a send request is currently in progress */
|
|
43
|
+
private activeRequest;
|
|
44
|
+
/** Timeout handle for error log flushing */
|
|
45
|
+
private errorLogTimeout?;
|
|
46
|
+
/**
|
|
47
|
+
* Application name - must be set by subclasses.
|
|
48
|
+
* Used to identify the source of logs in the remote system.
|
|
49
|
+
*/
|
|
50
|
+
protected abstract appName: string;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new console proxy log client.
|
|
53
|
+
*
|
|
54
|
+
* Sets up console.error interception and debounced flushing.
|
|
55
|
+
*/
|
|
56
|
+
constructor();
|
|
57
|
+
/**
|
|
58
|
+
* Initializes the log client by intercepting console.error and setting up flushing.
|
|
59
|
+
*
|
|
60
|
+
* Intercepts all `console.error` calls and routes them through this log client.
|
|
61
|
+
* Sets up periodic flushing via setInterval (every 2 minutes).
|
|
62
|
+
*/
|
|
63
|
+
init(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Buffers log messages and triggers flushing when thresholds are met.
|
|
66
|
+
*
|
|
67
|
+
* Logs are converted to LogToStream format and added to the buffer. Flushing occurs:
|
|
68
|
+
* - Immediately if buffer reaches maxBuffers
|
|
69
|
+
* - After a short delay (500ms) for error-level logs
|
|
70
|
+
* - Periodically via setInterval (every 2 minutes)
|
|
71
|
+
*
|
|
72
|
+
* @param level - Log level
|
|
73
|
+
* @param bold - Whether to apply bold formatting (not used)
|
|
74
|
+
* @param prefix - Composed prefix string (parsed to extract timestamp and reporter)
|
|
75
|
+
* @param toLog - Array of values to log
|
|
76
|
+
*/
|
|
77
|
+
protected logMessage(level: LogLevel, bold: boolean, prefix: string, toLog: LogParam[]): void;
|
|
78
|
+
/**
|
|
79
|
+
* Flushes buffered logs to the remote endpoint.
|
|
80
|
+
*
|
|
81
|
+
* Removes up to maxBuffers logs from the buffer and sends them. Uses retry logic
|
|
82
|
+
* to handle transient network failures.
|
|
83
|
+
*/
|
|
84
|
+
private flushLogs;
|
|
85
|
+
/**
|
|
86
|
+
* Sends logs with retry logic.
|
|
87
|
+
*
|
|
88
|
+
* Attempts to send logs up to 10 times with 1 second delay between retries.
|
|
89
|
+
* Logs errors to console if all retries fail.
|
|
90
|
+
*
|
|
91
|
+
* @param logs - Log entries to send
|
|
92
|
+
* @param retries - Maximum number of retry attempts (default: 10)
|
|
93
|
+
*/
|
|
94
|
+
private retrySendLogs;
|
|
95
|
+
/**
|
|
96
|
+
* Abstract method that subclasses must implement to send logs to the remote endpoint.
|
|
97
|
+
*
|
|
98
|
+
* @param logs - Array of log entries to send
|
|
99
|
+
*/
|
|
100
|
+
protected abstract sendLogsToEndpoint: (logs: LogToStream[]) => Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Stops the log client and performs cleanup.
|
|
103
|
+
*
|
|
104
|
+
* Clears any pending error log timeouts and flush intervals, restores the original
|
|
105
|
+
* console.error function, and calls the parent stop() method.
|
|
106
|
+
*/
|
|
107
|
+
stop(): void;
|
|
108
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @nu-art/logger - Flexible logging infrastructure with multiple output targets
|
|
3
|
+
* Copyright (C) 2024 Adam van der Kruk aka TacB0sS
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
import { _logger_getPrefix, LogClient } from './LogClient.js';
|
|
7
|
+
import { LogLevel } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Abstract base class for log clients that proxy logs to remote endpoints.
|
|
10
|
+
*
|
|
11
|
+
* Buffers log messages and sends them in batches to reduce network overhead.
|
|
12
|
+
* Automatically intercepts `console.error` calls and includes them in the log stream.
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - Batched sending (flushes when buffer reaches maxBuffers or after timeout)
|
|
16
|
+
* - Automatic retry logic with exponential backoff
|
|
17
|
+
* - Immediate flush on error-level logs
|
|
18
|
+
* - Periodic flushing via setInterval (every 2 minutes)
|
|
19
|
+
*
|
|
20
|
+
* Subclasses must implement `sendLogsToEndpoint()` to define the actual sending mechanism.
|
|
21
|
+
*/
|
|
22
|
+
export class LogClient_ConsoleProxy extends LogClient {
|
|
23
|
+
/** Buffer of log entries waiting to be sent */
|
|
24
|
+
buffers;
|
|
25
|
+
/** Maximum number of logs to buffer before forcing a flush */
|
|
26
|
+
maxBuffers = 50;
|
|
27
|
+
/** Interval handle for periodic log flushing */
|
|
28
|
+
flushInterval;
|
|
29
|
+
/** Original console.error function (saved before interception) */
|
|
30
|
+
originalConsoleError;
|
|
31
|
+
/** Flag indicating if a send request is currently in progress */
|
|
32
|
+
activeRequest;
|
|
33
|
+
/** Timeout handle for error log flushing */
|
|
34
|
+
errorLogTimeout;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new console proxy log client.
|
|
37
|
+
*
|
|
38
|
+
* Sets up console.error interception and debounced flushing.
|
|
39
|
+
*/
|
|
40
|
+
constructor() {
|
|
41
|
+
super();
|
|
42
|
+
this.buffers = [];
|
|
43
|
+
this.activeRequest = false;
|
|
44
|
+
// pipe console.error to this log client
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Initializes the log client by intercepting console.error and setting up flushing.
|
|
48
|
+
*
|
|
49
|
+
* Intercepts all `console.error` calls and routes them through this log client.
|
|
50
|
+
* Sets up periodic flushing via setInterval (every 2 minutes).
|
|
51
|
+
*/
|
|
52
|
+
init() {
|
|
53
|
+
super.init();
|
|
54
|
+
// Guard against multiple initializations - only save original if not already saved
|
|
55
|
+
if (!this.originalConsoleError) {
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
this['originalConsoleError'] = console.error;
|
|
58
|
+
}
|
|
59
|
+
console.error = (...args) => {
|
|
60
|
+
this.originalConsoleError(...args);
|
|
61
|
+
this.logMessage.bind(this)(LogLevel.Error, false, `${new Date().toISOString()} ${_logger_getPrefix(LogLevel.Error)} unhandled error`, args);
|
|
62
|
+
};
|
|
63
|
+
// Only set up interval if not already set
|
|
64
|
+
if (!this.flushInterval) {
|
|
65
|
+
// Flush logs every 60 seconds (not 2 minutes as comment says)
|
|
66
|
+
this.flushInterval = setInterval(async () => {
|
|
67
|
+
if (!this.activeRequest && this.buffers.length > 0)
|
|
68
|
+
await this.flushLogs();
|
|
69
|
+
}, 60 * 1000);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Buffers log messages and triggers flushing when thresholds are met.
|
|
74
|
+
*
|
|
75
|
+
* Logs are converted to LogToStream format and added to the buffer. Flushing occurs:
|
|
76
|
+
* - Immediately if buffer reaches maxBuffers
|
|
77
|
+
* - After a short delay (500ms) for error-level logs
|
|
78
|
+
* - Periodically via setInterval (every 2 minutes)
|
|
79
|
+
*
|
|
80
|
+
* @param level - Log level
|
|
81
|
+
* @param bold - Whether to apply bold formatting (not used)
|
|
82
|
+
* @param prefix - Composed prefix string (parsed to extract timestamp and reporter)
|
|
83
|
+
* @param toLog - Array of values to log
|
|
84
|
+
*/
|
|
85
|
+
logMessage(level, bold, prefix, toLog) {
|
|
86
|
+
const levelPrefix = _logger_getPrefix(level);
|
|
87
|
+
const logs = toLog
|
|
88
|
+
.map(param => {
|
|
89
|
+
if (!param)
|
|
90
|
+
return null;
|
|
91
|
+
let logContent = '';
|
|
92
|
+
if (typeof param === 'object')
|
|
93
|
+
logContent = JSON.stringify(param);
|
|
94
|
+
else
|
|
95
|
+
logContent = param.toString();
|
|
96
|
+
const [timestamp, reporter] = prefix.split(levelPrefix);
|
|
97
|
+
return {
|
|
98
|
+
severity: level,
|
|
99
|
+
logContent: logContent.trim(),
|
|
100
|
+
reporter: reporter.trim(),
|
|
101
|
+
timestamp: timestamp.trim()
|
|
102
|
+
};
|
|
103
|
+
})
|
|
104
|
+
.filter((log) => log != null);
|
|
105
|
+
this.buffers.push(...logs);
|
|
106
|
+
if (this.buffers.length >= this.maxBuffers && !this.activeRequest) {
|
|
107
|
+
setTimeout(async () => {
|
|
108
|
+
await this.flushLogs();
|
|
109
|
+
}, 0); // 2 minutes
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// trigger flush on error
|
|
113
|
+
if (level === LogLevel.Error && !this.errorLogTimeout)
|
|
114
|
+
this.errorLogTimeout = setTimeout(async () => {
|
|
115
|
+
this.errorLogTimeout = undefined;
|
|
116
|
+
if (!this.activeRequest)
|
|
117
|
+
await this.flushLogs();
|
|
118
|
+
}, 500);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Flushes buffered logs to the remote endpoint.
|
|
123
|
+
*
|
|
124
|
+
* Removes up to maxBuffers logs from the buffer and sends them. Uses retry logic
|
|
125
|
+
* to handle transient network failures.
|
|
126
|
+
*/
|
|
127
|
+
async flushLogs() {
|
|
128
|
+
this.activeRequest = true;
|
|
129
|
+
const logsToSend = this.buffers.splice(0, this.maxBuffers);
|
|
130
|
+
await this.retrySendLogs(logsToSend);
|
|
131
|
+
this.activeRequest = false;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Sends logs with retry logic.
|
|
135
|
+
*
|
|
136
|
+
* Attempts to send logs up to 10 times with 1 second delay between retries.
|
|
137
|
+
* Logs errors to console if all retries fail.
|
|
138
|
+
*
|
|
139
|
+
* @param logs - Log entries to send
|
|
140
|
+
* @param retries - Maximum number of retry attempts (default: 10)
|
|
141
|
+
*/
|
|
142
|
+
async retrySendLogs(logs, retries = 10) {
|
|
143
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
144
|
+
try {
|
|
145
|
+
await this.sendLogsToEndpoint(logs);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (attempt === retries) {
|
|
150
|
+
this.originalConsoleError('Failed to send logs after multiple attempts', error);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.warn(`Retrying to send logs, attempt ${attempt} failed`, error);
|
|
154
|
+
await new Promise(resolve => setTimeout(resolve, 1000)); // add a bit of delay between retries
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Stops the log client and performs cleanup.
|
|
161
|
+
*
|
|
162
|
+
* Clears any pending error log timeouts and flush intervals, restores the original
|
|
163
|
+
* console.error function, and calls the parent stop() method.
|
|
164
|
+
*/
|
|
165
|
+
stop() {
|
|
166
|
+
if (this.errorLogTimeout) {
|
|
167
|
+
clearTimeout(this.errorLogTimeout);
|
|
168
|
+
this.errorLogTimeout = undefined;
|
|
169
|
+
}
|
|
170
|
+
if (this.flushInterval) {
|
|
171
|
+
clearInterval(this.flushInterval);
|
|
172
|
+
this.flushInterval = undefined;
|
|
173
|
+
}
|
|
174
|
+
if (this.originalConsoleError) {
|
|
175
|
+
console.error = this.originalConsoleError;
|
|
176
|
+
}
|
|
177
|
+
super.stop();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { LogClient_BaseRotate } from './LogClient_BaseRotate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Log client that writes logs to rotating files on disk.
|
|
4
|
+
*
|
|
5
|
+
* Creates log files in the format `{name}-{index}.txt` where index 0 is the current log.
|
|
6
|
+
* When the current log exceeds maxSize, it rotates: log-0.txt → log-1.txt, log-1.txt → log-2.txt, etc.
|
|
7
|
+
* The oldest log (log-{maxEntries-1}.txt) is deleted during rotation.
|
|
8
|
+
*
|
|
9
|
+
* The log folder is created automatically if it doesn't exist. If a log file already
|
|
10
|
+
* exists, its size is used to initialize the bufferSize counter.
|
|
11
|
+
*/
|
|
12
|
+
export declare class LogClient_File extends LogClient_BaseRotate {
|
|
13
|
+
/** Directory path where log files are stored */
|
|
14
|
+
private pathToFolder;
|
|
15
|
+
/** WriteStream for the current log file */
|
|
16
|
+
private buffer;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new file-based log client.
|
|
19
|
+
*
|
|
20
|
+
* @param name - Log file name prefix (e.g., "app" creates "app-0.txt", "app-1.txt", etc.)
|
|
21
|
+
* @param pathToFolder - Directory path for log files (created if it doesn't exist)
|
|
22
|
+
* @param maxEntries - Maximum number of rotated log files to keep (default: 10)
|
|
23
|
+
* @param maxSize - Maximum file size in bytes before rotation (default: 1MB)
|
|
24
|
+
*/
|
|
25
|
+
constructor(name: string, pathToFolder: string, maxEntries?: number, maxSize?: number);
|
|
26
|
+
/**
|
|
27
|
+
* Gets the filename for a log file at the given index.
|
|
28
|
+
*
|
|
29
|
+
* @param index - Log file index (0 = current, 1+ = rotated)
|
|
30
|
+
* @returns Full path to the log file
|
|
31
|
+
*/
|
|
32
|
+
private getFileName;
|
|
33
|
+
/**
|
|
34
|
+
* Writes a log message to the current log file.
|
|
35
|
+
*
|
|
36
|
+
* @param log - Formatted log string (includes newline)
|
|
37
|
+
*/
|
|
38
|
+
protected printLogMessage(log: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Rotates a log file by renaming it to the next index.
|
|
41
|
+
*
|
|
42
|
+
* @param fromIndex - Source index
|
|
43
|
+
* @param toIndex - Destination index
|
|
44
|
+
*/
|
|
45
|
+
protected rotateBuffer(fromIndex: number, toIndex: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Cleans up the oldest log file and closes the current write stream.
|
|
48
|
+
*
|
|
49
|
+
* Called during rotation to delete the oldest log and prepare for a new current log.
|
|
50
|
+
*/
|
|
51
|
+
protected cleanup(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Prepares a new log file by creating a write stream.
|
|
54
|
+
*
|
|
55
|
+
* Opens the current log file (index 0) in append mode.
|
|
56
|
+
*/
|
|
57
|
+
protected prepare(): void;
|
|
58
|
+
}
|