forked from Acode-Foundation/Acode
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathlogger.js
116 lines (105 loc) · 3.3 KB
/
logger.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import fsOperation from "fileSystem";
import Url from "utils/Url";
import constants from "./constants";
/*
/**
* Logger class for handling application logging with buffer and file output.
* @class
*/
/**
* Creates a new Logger instance.
* @constructor
* @param {number} [maxBufferSize=1000] - Maximum number of log entries to keep in buffer.
* @param {string} [logLevel="info"] - Minimum log level to record ("error", "warn", "info", "debug").
* @param {number} [flushInterval=30000] - Interval in milliseconds for automatic log flushing.
*/
class Logger {
#logBuffer;
#maxBufferSize;
#logLevel;
#logFileName;
#flushInterval;
#autoFlushInterval;
constructor(maxBufferSize = 1000, logLevel = "info", flushInterval = 30000) {
this.#logBuffer = new Map();
this.#maxBufferSize = maxBufferSize;
this.#logLevel = logLevel;
this.#logFileName = constants.LOG_FILE_NAME;
this.#flushInterval = flushInterval;
this.#startAutoFlush(); // Automatically flush logs at intervals
this.#setupAppLifecycleHandlers(); // Handle app lifecycle events for safe log saving
}
/**
* Logs a message with the specified log level.
* @param {'error' | 'warn' | 'info' | 'debug'} level - The log level.
* @param {string} message - The message to be logged.
*/
log(level, message) {
const levels = ["error", "warn", "info", "debug"];
if (levels.indexOf(level) <= levels.indexOf(this.#logLevel)) {
let logEntry;
// Check if the message is an instance of Error
if (message instanceof Error) {
logEntry = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message.name}: ${message.message}\nStack trace: ${message.stack}`;
} else {
logEntry = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
}
// LRU Mechanism for efficient log buffer management
if (this.#logBuffer.size >= this.#maxBufferSize) {
// Remove oldest entry
const oldestKey = this.#logBuffer.keys().next().value;
this.#logBuffer.delete(oldestKey);
}
this.#logBuffer.set(Date.now(), logEntry); // Using timestamp as key
}
}
flushLogs() {
if (this.#logBuffer.size > 0) {
const logContent = Array.from(this.#logBuffer.values()).join("\n");
this.#writeLogToFile(logContent);
this.#logBuffer.clear(); // Clear the buffer after flushing
}
}
#writeLogToFile = async (logContent) => {
try {
if (
!(await fsOperation(
Url.join(DATA_STORAGE, constants.LOG_FILE_NAME),
).exists())
) {
await fsOperation(window.DATA_STORAGE).createFile(
constants.LOG_FILE_NAME,
logContent,
);
} else {
let existingData = await fsOperation(
Url.join(DATA_STORAGE, constants.LOG_FILE_NAME),
).readFile("utf8");
let newData = existingData + "\n" + logContent;
await fsOperation(
Url.join(DATA_STORAGE, constants.LOG_FILE_NAME),
).writeFile(newData);
}
} catch (error) {
console.error("Error in handling fs operation on log file. Error:", err);
}
};
#startAutoFlush = () => {
this.#autoFlushInterval = setInterval(() => {
this.flushLogs();
}, this.#flushInterval);
};
stopAutoFlush() {
clearInterval(this.#autoFlushInterval);
}
#setupAppLifecycleHandlers = () => {
document.addEventListener(
"pause",
() => {
this.flushLogs(); // Flush logs when app is paused (background)
},
false,
);
};
}
export default Logger;