-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from Benoit-Welsch/Feat/logger
Feat/logger
- Loading branch information
Showing
5 changed files
with
240 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
### Log | ||
|
||
Easily log to various outputs. | ||
|
||
```typescript | ||
import { Log } from "lv00/toolkit"; | ||
|
||
const {Logger, Console, Level, File, Csv, Json} = Log; | ||
|
||
// Define the endpoint of the log (transporter) | ||
const logger = new Logger({ | ||
t: [ | ||
new Console(), // Log all levels to the console | ||
new File({ l: [Level.INFO], path: 'log.txt' }), // Log only INFO to a text based file | ||
new Csv({ l: [Level.ERROR], path: 'log.csv' }), // Log only ERROR to a CSV file | ||
new Json({ l: [Level.DEBUG], path: 'log.json' }), // Log only DEBUG to a JSON file | ||
] | ||
}); | ||
|
||
logger.log('Hello, World!'); // log to all transports registered for the level INFO | ||
logger.log('Hello, World!', Level.ERROR); // log to all transports registered for the level ERROR | ||
|
||
// Log an error | ||
new Promise((_, reject) => { | ||
reject(new Error('Promise Error')); | ||
}).catch((e) => logger.catch(e)) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import fs from 'fs'; | ||
|
||
import { CSV as CSVo } from '../index'; | ||
|
||
export enum Level { | ||
INFO, | ||
OK, | ||
WARN, | ||
ERROR, | ||
DEBUG, | ||
} | ||
|
||
export type Payload = { | ||
message: string; | ||
level: Level; | ||
meta?: any; | ||
}; | ||
|
||
export class Logger { | ||
transports: Transporter[] = []; | ||
|
||
constructor(options: { t: Transporter[] }) { | ||
if (options.t) { | ||
this.transports = options.t; | ||
} | ||
} | ||
|
||
addTransport({ t }: { t: Transporter }) { | ||
if (this.transports === undefined) { | ||
this.transports = []; | ||
} | ||
this.transports.push(t); | ||
} | ||
|
||
log(message: string, l = Level.INFO) { | ||
this.transports.forEach((t) => { | ||
if (t.reacToLevels.includes(l)) t.send({ message, level: l }); | ||
}); | ||
} | ||
|
||
catch(err: Error) { | ||
this.transports.forEach((t) => { | ||
if (t.reacToLevels.includes(Level.ERROR)) t.catch(err); | ||
}); | ||
} | ||
} | ||
|
||
export abstract class Transporter { | ||
protected level = { | ||
[Level.INFO]: { | ||
title: 'INFO', | ||
emoji: 'ℹ️ ', | ||
}, | ||
[Level.OK]: { | ||
title: 'OK', | ||
emoji: '✅', | ||
}, | ||
[Level.WARN]: { | ||
title: 'WARN', | ||
emoji: '🚨', | ||
}, | ||
[Level.ERROR]: { | ||
title: 'ERROR', | ||
emoji: '❌', | ||
}, | ||
[Level.DEBUG]: { | ||
title: 'DEBUG', | ||
emoji: '🐛', | ||
}, | ||
}; | ||
|
||
reacToLevels: Level[]; | ||
|
||
constructor({ l }: { l: Level[] } = { l: [] }) { | ||
if (l === undefined || l.length === 0) { | ||
l = [Level.INFO, Level.OK, Level.WARN, Level.ERROR, Level.DEBUG]; | ||
} | ||
this.reacToLevels = l; | ||
} | ||
|
||
abstract send(log: Payload): void; | ||
catch(err: Error) { | ||
this.send({ message: err.message, level: Level.ERROR }); | ||
} | ||
} | ||
|
||
export class Console extends Transporter { | ||
async send(log: Payload) { | ||
const { message, level: l } = log; | ||
if (l === Level.DEBUG && process.env.NODE_ENV !== 'development') return; | ||
const { title, emoji } = this.level[l] || this.level[Level.ERROR]; | ||
const out = `${emoji}[${title}] ${message}`; | ||
console.log(out); | ||
} | ||
|
||
async catch(err: Error) { | ||
this.send({ message: err.message, level: Level.ERROR }); | ||
} | ||
} | ||
|
||
export class File extends Transporter { | ||
private path: string; | ||
|
||
constructor({ l, path }: { l?: Level[]; path: string }) { | ||
super({ l: l || [] }); | ||
this.path = path; | ||
} | ||
|
||
send(log: Payload) { | ||
const { message, level: l } = log; | ||
if (l === Level.DEBUG && process.env.NODE_ENV !== 'development') return; | ||
const { title } = this.level[l] || this.level[Level.ERROR]; | ||
const out = `[${title}] ${message}`; | ||
fs.appendFile(this.path, out + '\n', (err) => { | ||
if (err) throw err; | ||
}); | ||
} | ||
|
||
catch(err: Error) { | ||
this.send({ message: err.message, level: Level.ERROR }); | ||
} | ||
} | ||
|
||
export class Csv extends Transporter { | ||
private path: string; | ||
private csv: CSVo; | ||
|
||
constructor({ l, path }: { l?: Level[]; path: string }) { | ||
super({ l: l || [] }); | ||
this.csv = new CSVo({ header: ['date', 'level', 'message', 'meta'] }); | ||
this.path = path; | ||
} | ||
|
||
send(log: Payload) { | ||
const { message, level: l, meta } = log; | ||
const { title } = this.level[l] || this.level[Level.ERROR]; | ||
const date = new Date().toISOString(); | ||
|
||
this.csv.addLine([date, title, message, JSON.stringify(meta)]); | ||
|
||
if (!fs.existsSync(this.path) || fs.statSync(this.path).size === 0) { | ||
const csvString = this.csv.toString(';'); | ||
fs.writeFileSync(this.path, csvString, 'utf8'); | ||
} else { | ||
const csvString = '\r\n' + this.csv.toString(';', false); | ||
fs.appendFileSync(this.path, csvString, 'utf8'); | ||
} | ||
|
||
this.csv.clear(); | ||
} | ||
} | ||
|
||
export class Json extends Transporter { | ||
private path: string; | ||
|
||
constructor({ l, path }: { l?: Level[]; path: string }) { | ||
super({ l: l || [] }); | ||
this.path = path; | ||
} | ||
|
||
send(log: Payload) { | ||
const { message, level: l, meta } = log; | ||
const { title } = this.level[l] || this.level[Level.ERROR]; | ||
const date = new Date().toISOString(); | ||
|
||
const logLine = { | ||
date, | ||
level: title, | ||
message, | ||
meta, | ||
}; | ||
|
||
if (!fs.existsSync(this.path) || fs.statSync(this.path).size === 0) { | ||
fs.writeFileSync(this.path, JSON.stringify([logLine]), 'utf8'); | ||
} else { | ||
const data = JSON.parse(fs.readFileSync(this.path, 'utf8')); | ||
data.push(logLine); | ||
fs.writeFileSync(this.path, JSON.stringify(data), 'utf8'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters