@noxfly/noxus 2.0.0 → 2.1.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/dist/main.d.mts +28 -2
- package/dist/main.d.ts +28 -2
- package/dist/main.js +246 -70
- package/dist/main.mjs +236 -70
- package/package.json +2 -2
- package/src/main.ts +3 -0
- package/src/router.ts +44 -10
- package/src/utils/logger.ts +266 -87
package/src/utils/logger.ts
CHANGED
|
@@ -4,10 +4,28 @@
|
|
|
4
4
|
* @author NoxFly
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
|
|
7
10
|
/**
|
|
8
11
|
* Logger is a utility class for logging messages to the console.
|
|
9
12
|
*/
|
|
10
|
-
export type LogLevel =
|
|
13
|
+
export type LogLevel =
|
|
14
|
+
| 'debug'
|
|
15
|
+
| 'comment'
|
|
16
|
+
| 'log'
|
|
17
|
+
| 'info'
|
|
18
|
+
| 'warn'
|
|
19
|
+
| 'error'
|
|
20
|
+
| 'critical'
|
|
21
|
+
;
|
|
22
|
+
|
|
23
|
+
interface FileLogState {
|
|
24
|
+
queue: string[];
|
|
25
|
+
isWriting: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
11
29
|
|
|
12
30
|
/**
|
|
13
31
|
* Returns a formatted timestamp for logging.
|
|
@@ -25,15 +43,24 @@ function getPrettyTimestamp(): string {
|
|
|
25
43
|
* @param color - The color to use for the log message.
|
|
26
44
|
* @returns A formatted string that includes the timestamp, process ID, message type, and callee name.
|
|
27
45
|
*/
|
|
28
|
-
function getLogPrefix(callee: string, messageType: string, color
|
|
46
|
+
function getLogPrefix(callee: string, messageType: string, color?: string): string {
|
|
29
47
|
const timestamp = getPrettyTimestamp();
|
|
30
48
|
|
|
31
|
-
const spaces =
|
|
49
|
+
const spaces = " ".repeat(10 - messageType.length);
|
|
50
|
+
|
|
51
|
+
let colReset = Logger.colors.initial;
|
|
52
|
+
let colCallee = Logger.colors.yellow;
|
|
53
|
+
|
|
54
|
+
if(color === undefined) {
|
|
55
|
+
color = "";
|
|
56
|
+
colReset = "";
|
|
57
|
+
colCallee = "";
|
|
58
|
+
}
|
|
32
59
|
|
|
33
|
-
return `${color}[APP] ${process.pid} - ${
|
|
60
|
+
return `${color}[APP] ${process.pid} - ${colReset}`
|
|
34
61
|
+ `${timestamp}${spaces}`
|
|
35
|
-
+ `${color}${messageType.toUpperCase()}${
|
|
36
|
-
+ `${
|
|
62
|
+
+ `${color}${messageType.toUpperCase()}${colReset} `
|
|
63
|
+
+ `${colCallee}[${callee}]${colReset}`;
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
/**
|
|
@@ -43,13 +70,23 @@ function getLogPrefix(callee: string, messageType: string, color: string): strin
|
|
|
43
70
|
* @param arg - The object to format.
|
|
44
71
|
* @returns A formatted string representation of the object, with each line prefixed by the specified prefix.
|
|
45
72
|
*/
|
|
46
|
-
function formatObject(prefix: string, arg: object): string {
|
|
73
|
+
function formatObject(prefix: string, arg: object, enableColor: boolean = true): string {
|
|
47
74
|
const json = JSON.stringify(arg, null, 2);
|
|
48
75
|
|
|
76
|
+
let colStart = "";
|
|
77
|
+
let colLine = "";
|
|
78
|
+
let colReset = "";
|
|
79
|
+
|
|
80
|
+
if(enableColor) {
|
|
81
|
+
colStart = Logger.colors.darkGrey;
|
|
82
|
+
colLine = Logger.colors.grey;
|
|
83
|
+
colReset = Logger.colors.initial;
|
|
84
|
+
}
|
|
85
|
+
|
|
49
86
|
const prefixedJson = json
|
|
50
87
|
.split('\n')
|
|
51
|
-
.map((line, idx) => idx === 0 ? `${
|
|
52
|
-
.join('\n') +
|
|
88
|
+
.map((line, idx) => idx === 0 ? `${colStart}${line}` : `${prefix} ${colLine}${line}`)
|
|
89
|
+
.join('\n') + colReset;
|
|
53
90
|
|
|
54
91
|
return prefixedJson;
|
|
55
92
|
}
|
|
@@ -63,14 +100,21 @@ function formatObject(prefix: string, arg: object): string {
|
|
|
63
100
|
* @param color - The color to use for the formatted arguments.
|
|
64
101
|
* @returns An array of formatted arguments, where strings are colored and objects are formatted with indentation.
|
|
65
102
|
*/
|
|
66
|
-
function formattedArgs(prefix: string, args: any[], color
|
|
103
|
+
function formattedArgs(prefix: string, args: any[], color?: string): any[] {
|
|
104
|
+
let colReset = Logger.colors.initial;
|
|
105
|
+
|
|
106
|
+
if(color === undefined) {
|
|
107
|
+
color = "";
|
|
108
|
+
colReset = "";
|
|
109
|
+
}
|
|
110
|
+
|
|
67
111
|
return args.map(arg => {
|
|
68
|
-
if(typeof arg ===
|
|
69
|
-
return `${color}${arg}${
|
|
112
|
+
if(typeof arg === "string") {
|
|
113
|
+
return `${color}${arg}${colReset}`;
|
|
70
114
|
}
|
|
71
115
|
|
|
72
|
-
else if(typeof arg ===
|
|
73
|
-
return formatObject(prefix, arg);
|
|
116
|
+
else if(typeof arg === "object") {
|
|
117
|
+
return formatObject(prefix, arg, color === "");
|
|
74
118
|
}
|
|
75
119
|
|
|
76
120
|
return arg;
|
|
@@ -88,8 +132,8 @@ function getCallee(): string {
|
|
|
88
132
|
?.trim()
|
|
89
133
|
.match(/at (.+?)(?:\..+)? .+$/)
|
|
90
134
|
?.[1]
|
|
91
|
-
?.replace(
|
|
92
|
-
.replace(/^_/,
|
|
135
|
+
?.replace("Object", "")
|
|
136
|
+
.replace(/^_/, "")
|
|
93
137
|
|| "App";
|
|
94
138
|
return caller;
|
|
95
139
|
}
|
|
@@ -101,20 +145,97 @@ function getCallee(): string {
|
|
|
101
145
|
* @returns A boolean indicating whether the log level is enabled.
|
|
102
146
|
*/
|
|
103
147
|
function canLog(level: LogLevel): boolean {
|
|
104
|
-
return
|
|
148
|
+
return logLevels.has(level);
|
|
105
149
|
}
|
|
106
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Writes a log message to a file asynchronously to avoid blocking the event loop.
|
|
153
|
+
* It batches messages if writing is already in progress.
|
|
154
|
+
* @param filepath - The path to the log file.
|
|
155
|
+
*/
|
|
156
|
+
function processLogQueue(filepath: string): void {
|
|
157
|
+
const state = fileStates.get(filepath);
|
|
158
|
+
|
|
159
|
+
if(!state || state.isWriting || state.queue.length === 0) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
state.isWriting = true;
|
|
164
|
+
|
|
165
|
+
// Optimization: Grab all pending messages to write in one go
|
|
166
|
+
const messagesToWrite = state.queue.join('\n') + '\n';
|
|
167
|
+
state.queue = []; // Clear the queue immediately
|
|
168
|
+
|
|
169
|
+
const dir = path.dirname(filepath);
|
|
170
|
+
|
|
171
|
+
// Using async IO to allow other operations
|
|
172
|
+
fs.mkdir(dir, { recursive: true }, (err) => {
|
|
173
|
+
if(err) {
|
|
174
|
+
console.error(`[Logger] Failed to create directory ${dir}`, err);
|
|
175
|
+
state.isWriting = false;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
fs.appendFile(filepath, messagesToWrite, { encoding: "utf-8" }, (err) => {
|
|
180
|
+
state.isWriting = false;
|
|
181
|
+
|
|
182
|
+
if(err) {
|
|
183
|
+
console.error(`[Logger] Failed to write log to ${filepath}`, err);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// If new messages arrived while we were writing, process them now
|
|
187
|
+
if(state.queue.length > 0) {
|
|
188
|
+
processLogQueue(filepath);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Adds a message to the file queue and triggers processing.
|
|
196
|
+
*/
|
|
197
|
+
function enqueue(filepath: string, message: string): void {
|
|
198
|
+
if(!fileStates.has(filepath)) {
|
|
199
|
+
fileStates.set(filepath, { queue: [], isWriting: false });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const state = fileStates.get(filepath)!;
|
|
203
|
+
state.queue.push(message);
|
|
204
|
+
|
|
205
|
+
processLogQueue(filepath);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
*
|
|
210
|
+
*/
|
|
211
|
+
function output(level: LogLevel, args: any[]): void {
|
|
212
|
+
if(!canLog(level)) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const callee = getCallee();
|
|
217
|
+
|
|
218
|
+
{
|
|
219
|
+
const prefix = getLogPrefix(callee, level, logLevelColors[level]);
|
|
220
|
+
const data = formattedArgs(prefix, args, logLevelColors[level]);
|
|
221
|
+
|
|
222
|
+
logLevelChannel[level](prefix, ...data);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
{
|
|
226
|
+
const prefix = getLogPrefix(callee, level);
|
|
227
|
+
const data = formattedArgs(prefix, args);
|
|
228
|
+
|
|
229
|
+
const filepath = fileSettings.get(level)?.filepath;
|
|
230
|
+
|
|
231
|
+
if(filepath) {
|
|
232
|
+
const message = prefix + " " + data.join(" ");
|
|
233
|
+
enqueue(filepath, message);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
107
237
|
|
|
108
|
-
let logLevel: LogLevel = 'debug';
|
|
109
238
|
|
|
110
|
-
const logLevelRank: Record<LogLevel, number> = {
|
|
111
|
-
debug: 0,
|
|
112
|
-
comment: 1,
|
|
113
|
-
log: 2,
|
|
114
|
-
info: 3,
|
|
115
|
-
warn: 4,
|
|
116
|
-
error: 5,
|
|
117
|
-
};
|
|
118
239
|
|
|
119
240
|
export namespace Logger {
|
|
120
241
|
|
|
@@ -122,10 +243,30 @@ export namespace Logger {
|
|
|
122
243
|
* Sets the log level for the logger.
|
|
123
244
|
* This function allows you to change the log level dynamically at runtime.
|
|
124
245
|
* This won't affect the startup logs.
|
|
246
|
+
*
|
|
247
|
+
* If the parameter is a single LogLevel, all log levels with equal or higher severity will be enabled.
|
|
248
|
+
|
|
249
|
+
* If the parameter is an array of LogLevels, only the specified levels will be enabled.
|
|
250
|
+
*
|
|
125
251
|
* @param level Sets the log level for the logger.
|
|
126
252
|
*/
|
|
127
|
-
export function setLogLevel(level: LogLevel): void {
|
|
128
|
-
|
|
253
|
+
export function setLogLevel(level: LogLevel | LogLevel[]): void {
|
|
254
|
+
logLevels.clear();
|
|
255
|
+
|
|
256
|
+
if(Array.isArray(level)) {
|
|
257
|
+
for(const lvl of level) {
|
|
258
|
+
logLevels.add(lvl);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const targetRank = logLevelRank[level];
|
|
263
|
+
|
|
264
|
+
for(const [lvl, rank] of Object.entries(logLevelRank) as [LogLevel, number][]) {
|
|
265
|
+
if(rank >= targetRank) {
|
|
266
|
+
logLevels.add(lvl);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
129
270
|
}
|
|
130
271
|
|
|
131
272
|
/**
|
|
@@ -135,12 +276,7 @@ export namespace Logger {
|
|
|
135
276
|
* @param args The arguments to log.
|
|
136
277
|
*/
|
|
137
278
|
export function log(...args: any[]): void {
|
|
138
|
-
|
|
139
|
-
return;
|
|
140
|
-
|
|
141
|
-
const callee = getCallee();
|
|
142
|
-
const prefix = getLogPrefix(callee, "log", colors.green);
|
|
143
|
-
console.log(prefix, ...formattedArgs(prefix, args, colors.green));
|
|
279
|
+
output("log", args);
|
|
144
280
|
}
|
|
145
281
|
|
|
146
282
|
/**
|
|
@@ -150,12 +286,7 @@ export namespace Logger {
|
|
|
150
286
|
* @param args The arguments to log.
|
|
151
287
|
*/
|
|
152
288
|
export function info(...args: any[]): void {
|
|
153
|
-
|
|
154
|
-
return;
|
|
155
|
-
|
|
156
|
-
const callee = getCallee();
|
|
157
|
-
const prefix = getLogPrefix(callee, "info", colors.blue);
|
|
158
|
-
console.info(prefix, ...formattedArgs(prefix, args, colors.blue));
|
|
289
|
+
output("info", args);
|
|
159
290
|
}
|
|
160
291
|
|
|
161
292
|
/**
|
|
@@ -165,12 +296,7 @@ export namespace Logger {
|
|
|
165
296
|
* @param args The arguments to log.
|
|
166
297
|
*/
|
|
167
298
|
export function warn(...args: any[]): void {
|
|
168
|
-
|
|
169
|
-
return;
|
|
170
|
-
|
|
171
|
-
const callee = getCallee();
|
|
172
|
-
const prefix = getLogPrefix(callee, "warn", colors.brown);
|
|
173
|
-
console.warn(prefix, ...formattedArgs(prefix, args, colors.brown));
|
|
299
|
+
output("warn", args);
|
|
174
300
|
}
|
|
175
301
|
|
|
176
302
|
/**
|
|
@@ -180,21 +306,14 @@ export namespace Logger {
|
|
|
180
306
|
* @param args The arguments to log.
|
|
181
307
|
*/
|
|
182
308
|
export function error(...args: any[]): void {
|
|
183
|
-
|
|
184
|
-
return;
|
|
185
|
-
|
|
186
|
-
const callee = getCallee();
|
|
187
|
-
const prefix = getLogPrefix(callee, "error", colors.red);
|
|
188
|
-
console.error(prefix, ...formattedArgs(prefix, args, colors.red));
|
|
309
|
+
output("error", args);
|
|
189
310
|
}
|
|
190
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Logs a message to the console with log level ERROR and a grey color scheme.
|
|
314
|
+
*/
|
|
191
315
|
export function errorStack(...args: any[]): void {
|
|
192
|
-
|
|
193
|
-
return;
|
|
194
|
-
|
|
195
|
-
const callee = getCallee();
|
|
196
|
-
const prefix = getLogPrefix(callee, "error", colors.grey);
|
|
197
|
-
console.error(prefix, ...formattedArgs(prefix, args, colors.grey));
|
|
316
|
+
output("error", args);
|
|
198
317
|
}
|
|
199
318
|
|
|
200
319
|
/**
|
|
@@ -204,12 +323,7 @@ export namespace Logger {
|
|
|
204
323
|
* @param args The arguments to log.
|
|
205
324
|
*/
|
|
206
325
|
export function debug(...args: any[]): void {
|
|
207
|
-
|
|
208
|
-
return;
|
|
209
|
-
|
|
210
|
-
const callee = getCallee();
|
|
211
|
-
const prefix = getLogPrefix(callee, "debug", colors.purple);
|
|
212
|
-
console.debug(prefix, ...formattedArgs(prefix, args, colors.purple));
|
|
326
|
+
output("debug", args);
|
|
213
327
|
}
|
|
214
328
|
|
|
215
329
|
/**
|
|
@@ -219,33 +333,98 @@ export namespace Logger {
|
|
|
219
333
|
* @param args The arguments to log.
|
|
220
334
|
*/
|
|
221
335
|
export function comment(...args: any[]): void {
|
|
222
|
-
|
|
223
|
-
|
|
336
|
+
output("comment", args);
|
|
337
|
+
}
|
|
224
338
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Logs a message to the console with log level CRITICAL.
|
|
341
|
+
* This function formats the message with a timestamp, process ID, and the name of the caller function or class.
|
|
342
|
+
* It uses different colors for different log levels to enhance readability.
|
|
343
|
+
* @param args The arguments to log.
|
|
344
|
+
*/
|
|
345
|
+
export function critical(...args: any[]): void {
|
|
346
|
+
output("critical", args);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Enables logging to a file output for the specified log levels.
|
|
351
|
+
* @param filepath The path to the log file.
|
|
352
|
+
* @param levels The log levels to enable file logging for. Defaults to all levels.
|
|
353
|
+
*/
|
|
354
|
+
export function enableFileLogging(filepath: string, levels: LogLevel[] = ["debug", "comment", "log", "info", "warn", "error", "critical"]): void {
|
|
355
|
+
for(const level of levels) {
|
|
356
|
+
fileSettings.set(level, { filepath });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Disables logging to a file output for the specified log levels.
|
|
362
|
+
* @param levels The log levels to disable file logging for. Defaults to all levels.
|
|
363
|
+
*/
|
|
364
|
+
export function disableFileLogging(levels: LogLevel[] = ["debug", "comment", "log", "info", "warn", "error", "critical"]): void {
|
|
365
|
+
for(const level of levels) {
|
|
366
|
+
fileSettings.delete(level);
|
|
367
|
+
}
|
|
228
368
|
}
|
|
229
369
|
|
|
230
370
|
|
|
231
371
|
export const colors = {
|
|
232
|
-
black:
|
|
233
|
-
grey:
|
|
234
|
-
red:
|
|
235
|
-
green:
|
|
236
|
-
brown:
|
|
237
|
-
blue:
|
|
238
|
-
purple:
|
|
239
|
-
|
|
240
|
-
darkGrey:
|
|
241
|
-
lightRed:
|
|
242
|
-
lightGreen:
|
|
243
|
-
yellow:
|
|
244
|
-
lightBlue:
|
|
245
|
-
magenta:
|
|
246
|
-
cyan:
|
|
247
|
-
white:
|
|
248
|
-
|
|
249
|
-
initial:
|
|
372
|
+
black: "\x1b[0;30m",
|
|
373
|
+
grey: "\x1b[0;37m",
|
|
374
|
+
red: "\x1b[0;31m",
|
|
375
|
+
green: "\x1b[0;32m",
|
|
376
|
+
brown: "\x1b[0;33m",
|
|
377
|
+
blue: "\x1b[0;34m",
|
|
378
|
+
purple: "\x1b[0;35m",
|
|
379
|
+
|
|
380
|
+
darkGrey: "\x1b[1;30m",
|
|
381
|
+
lightRed: "\x1b[1;31m",
|
|
382
|
+
lightGreen: "\x1b[1;32m",
|
|
383
|
+
yellow: "\x1b[1;33m",
|
|
384
|
+
lightBlue: "\x1b[1;34m",
|
|
385
|
+
magenta: "\x1b[1;35m",
|
|
386
|
+
cyan: "\x1b[1;36m",
|
|
387
|
+
white: "\x1b[1;37m",
|
|
388
|
+
|
|
389
|
+
initial: "\x1b[0m"
|
|
250
390
|
};
|
|
251
391
|
}
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
const fileSettings: Map<LogLevel, { filepath: string }> = new Map();
|
|
395
|
+
const fileStates: Map<string, FileLogState> = new Map(); // filepath -> state
|
|
396
|
+
|
|
397
|
+
const logLevels: Set<LogLevel> = new Set();
|
|
398
|
+
|
|
399
|
+
const logLevelRank: Record<LogLevel, number> = {
|
|
400
|
+
debug: 0,
|
|
401
|
+
comment: 1,
|
|
402
|
+
log: 2,
|
|
403
|
+
info: 3,
|
|
404
|
+
warn: 4,
|
|
405
|
+
error: 5,
|
|
406
|
+
critical: 6,
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const logLevelColors: Record<LogLevel, string> = {
|
|
410
|
+
debug: Logger.colors.purple,
|
|
411
|
+
comment: Logger.colors.grey,
|
|
412
|
+
log: Logger.colors.green,
|
|
413
|
+
info: Logger.colors.blue,
|
|
414
|
+
warn: Logger.colors.brown,
|
|
415
|
+
error: Logger.colors.red,
|
|
416
|
+
critical: Logger.colors.lightRed,
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const logLevelChannel: Record<LogLevel, (message?: any, ...optionalParams: any[]) => void> = {
|
|
420
|
+
debug: console.debug,
|
|
421
|
+
comment: console.debug,
|
|
422
|
+
log: console.log,
|
|
423
|
+
info: console.info,
|
|
424
|
+
warn: console.warn,
|
|
425
|
+
error: console.error,
|
|
426
|
+
critical: console.error,
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
Logger.setLogLevel("debug");
|