init
This commit is contained in:
commit
4b00caf7d4
9 changed files with 187 additions and 0 deletions
45
Dispatch.ts
Normal file
45
Dispatch.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { statSync } from "node:fs";
|
||||||
|
import { IDispatch, IDispatchConfig } from "./IDispatch";
|
||||||
|
import { ILogItem } from "./ILogItem";
|
||||||
|
import { LogLevel } from "./LogLevel";
|
||||||
|
|
||||||
|
export class Dispatch implements IDispatch {
|
||||||
|
private dispatches: IDispatch[] = [];
|
||||||
|
|
||||||
|
constructor(config: IDispatchConfig = {}) {}
|
||||||
|
|
||||||
|
trace(...args: any[]): void {
|
||||||
|
this.process({ timestamp: new Date(), level: LogLevel.Trace, data: args });
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(...args: any[]): void {
|
||||||
|
this.process({ timestamp: new Date(), level: LogLevel.Debug, data: args });
|
||||||
|
}
|
||||||
|
|
||||||
|
info(...args: any[]): void {
|
||||||
|
this.process({ timestamp: new Date(), level: LogLevel.Info, data: args });
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(...args: any[]): void {
|
||||||
|
this.process({ timestamp: new Date(), level: LogLevel.Warn, data: args });
|
||||||
|
}
|
||||||
|
|
||||||
|
error(...args: any[]): void {
|
||||||
|
this.process({ timestamp: new Date(), level: LogLevel.Error, data: args });
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal(...args: any[]): void {
|
||||||
|
this.process({ timestamp: new Date(), level: LogLevel.Fatal, data: args });
|
||||||
|
}
|
||||||
|
|
||||||
|
process(item: ILogItem): void {
|
||||||
|
for (const dispatch of this.dispatches) {
|
||||||
|
dispatch.process(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(dispatch: IDispatch): Dispatch {
|
||||||
|
this.dispatches.push(dispatch);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
24
FileDispatch.ts
Normal file
24
FileDispatch.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { FormattedDispatch } from "./FormattedDispatch";
|
||||||
|
import { App } from "../App";
|
||||||
|
import { ILogItem } from "./ILogItem";
|
||||||
|
|
||||||
|
export class FileDispatch extends FormattedDispatch {
|
||||||
|
path: string;
|
||||||
|
stream: fs.WriteStream;
|
||||||
|
|
||||||
|
constructor(path: string) {
|
||||||
|
super();
|
||||||
|
this.path = path;
|
||||||
|
this.stream = fs.createWriteStream(path, { flags: "a" });
|
||||||
|
|
||||||
|
this.stream.on("error", (err) => {
|
||||||
|
App.logger.error(`Error writing to file: ${this.path}`, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
process(item: ILogItem): void {
|
||||||
|
this.stream.write(this.format(item) + "\n");
|
||||||
|
super.process(item);
|
||||||
|
}
|
||||||
|
}
|
37
FormattedDispatch.ts
Normal file
37
FormattedDispatch.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { Dispatch } from "./Dispatch";
|
||||||
|
import { ILogItem } from "./ILogItem";
|
||||||
|
import { LogLevel } from "./LogLevel";
|
||||||
|
|
||||||
|
export class FormattedDispatch extends Dispatch {
|
||||||
|
private formatString: string = "%t %l <%o>: %m";
|
||||||
|
|
||||||
|
format(item: ILogItem): string {
|
||||||
|
return this.formatString
|
||||||
|
.replace("%t", item.timestamp.toISOString())
|
||||||
|
.replace("%l", LogLevel[item.level])
|
||||||
|
.replace("%o", item.origin || "")
|
||||||
|
.replace(
|
||||||
|
"%m",
|
||||||
|
item.data
|
||||||
|
.map((item: any) => {
|
||||||
|
switch (typeof item) {
|
||||||
|
case "string":
|
||||||
|
case "number":
|
||||||
|
return item;
|
||||||
|
case "object":
|
||||||
|
return JSON.stringify(item);
|
||||||
|
default:
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join(" "),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
process(item: ILogItem): void {
|
||||||
|
super.process({
|
||||||
|
...item,
|
||||||
|
data: this.format(item),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
7
IDispatch.ts
Normal file
7
IDispatch.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { ILogItem } from "./ILogItem";
|
||||||
|
|
||||||
|
export interface IDispatchConfig {}
|
||||||
|
|
||||||
|
export interface IDispatch {
|
||||||
|
process(item: ILogItem): void;
|
||||||
|
}
|
8
ILogItem.ts
Normal file
8
ILogItem.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { LogLevel } from "./LogLevel";
|
||||||
|
|
||||||
|
export interface ILogItem {
|
||||||
|
timestamp: Date;
|
||||||
|
origin?: string;
|
||||||
|
level: LogLevel;
|
||||||
|
data: any;
|
||||||
|
}
|
8
LogLevel.ts
Normal file
8
LogLevel.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export enum LogLevel {
|
||||||
|
Trace,
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error,
|
||||||
|
Fatal
|
||||||
|
}
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# s410 logger
|
||||||
|
|
||||||
|
Dispatch based logging, created by Didier a.k.a. s410 or s41uc0.
|
44
SmartDispatch.ts
Normal file
44
SmartDispatch.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { statSync } from "fs";
|
||||||
|
import { Dispatch } from "./Dispatch";
|
||||||
|
import { ILogItem } from "./ILogItem";
|
||||||
|
|
||||||
|
export class SmartDispatch extends Dispatch {
|
||||||
|
process(item: ILogItem) {
|
||||||
|
let err = new Error();
|
||||||
|
// we need to look through the stack and keep track of intermediate dispatches
|
||||||
|
let stack = err.stack!.split("\n");
|
||||||
|
let i = 0;
|
||||||
|
while (!stack[i].includes("at SmartDispatch.process")) i++;
|
||||||
|
|
||||||
|
let src = stack[i + 2].trim();
|
||||||
|
let path = null;
|
||||||
|
|
||||||
|
// now we need to format the src (at ...:..:.. or at App.<anonymous> ..., etc)
|
||||||
|
if (src.includes("at ")) src = src.split("at ")[1];
|
||||||
|
if (src.includes(" (")) src = src.split(" (")[1];
|
||||||
|
if (src.includes(")")) src = src.split(")")[0];
|
||||||
|
|
||||||
|
let file = {
|
||||||
|
path: src.split(":")[0],
|
||||||
|
line: src.split(":")[1],
|
||||||
|
column: src.split(":")[2],
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
path = statSync(file.path).isFile() ? file.path : null;
|
||||||
|
} catch (e) {
|
||||||
|
path = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
// trim the path to the project root
|
||||||
|
if (path.startsWith(process.cwd()))
|
||||||
|
path = "." + path.slice(process.cwd().length);
|
||||||
|
src = `${path}:${file.line}:${file.column}`;
|
||||||
|
}
|
||||||
|
super.process({
|
||||||
|
...item,
|
||||||
|
origin: src,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
11
StdoutDispatch.ts
Normal file
11
StdoutDispatch.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { FormattedDispatch } from "./FormattedDispatch";
|
||||||
|
import { IDispatch } from "./IDispatch";
|
||||||
|
import { ILogItem } from "./ILogItem";
|
||||||
|
import { LogLevel } from "./LogLevel";
|
||||||
|
|
||||||
|
export class StdoutDispatch extends FormattedDispatch {
|
||||||
|
process(item: ILogItem) {
|
||||||
|
process.stdout.write(this.format(item) + "\n");
|
||||||
|
super.process(item);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue