Skip to content

Commit

Permalink
Merge pull request #12 from Benoit-Welsch/Feat/logger
Browse files Browse the repository at this point in the history
Feat/logger
  • Loading branch information
Benoit-Welsch committed Mar 19, 2024
2 parents 9b6461a + 2e20d0e commit 7ff60b1
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 2 deletions.
29 changes: 28 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

- [Check](#check)
- [Csv](#csv)
- [Log](#log)
- [Gen](#gen)
- [Parser](#parser)
- [Queue](#queue)
Expand Down Expand Up @@ -83,6 +84,33 @@ const csv2 = CSV.readString('name,age\r\nJohn,20\r\nJane,21\r\nJack,22', ',');
csv2.toString('|');
```

### 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))

### Gen

Generate pseudo-random data
Expand All @@ -93,7 +121,6 @@ Generate pseudo-random data
import { Gen } from '@lv00/toolkit';
const newName = Gen.randomName(); // antonelli-xenodochial
```
### Parser
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.1.8",
"version": "1.1.9",
"name": "@lv00/toolkit",
"module": "./dist/index.js",
"type": "module",
Expand Down
27 changes: 27 additions & 0 deletions src/Log/Readme.md
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))
```
181 changes: 181 additions & 0 deletions src/Log/index.ts
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');
}
}
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export const Url = { buildUrlWithQuery };
import { dot } from './Parser';
export const Parser = { dot };

// Logger
export * as Log from './Log';

// Gen
import { randomName } from './Gen';
export const Gen = { randomName };

0 comments on commit 7ff60b1

Please sign in to comment.