Skip to content

Instantly share code, notes, and snippets.

@nknapp
Last active June 4, 2018 19:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nknapp/3458e7ec0704061834b113f0828900e9 to your computer and use it in GitHub Desktop.
Save nknapp/3458e7ec0704061834b113f0828900e9 to your computer and use it in GitHub Desktop.
A logger that I didn't want to throw away, but I'm currently not needing it.
import { expect } from "chai";
import { Writable } from "stream";
import { logLevel, LogManager, toStream } from "../../src/utils/logger";
describe("The logger", () => {
describe("The 'for'-function", function() {
const logEntries: any[] = [];
const log = new LogManager();
let stream: Writable;
let dateNow: any;
let lastDate: number = 5000
beforeEach(function() {
dateNow = Date.now;
Date.now = () => lastDate += 15;
stream = new Writable({
write(chunk: Buffer | string, encoding: string, cb: Function): boolean {
logEntries.push(chunk.toString());
cb(null);
return true;
}
});
logEntries.length = 0;
log.configure([], toStream(stream), logLevel.debug);
});
afterEach(function() {
Date.now = dateNow
});
it("return a preconfigured LogFacade object", function() {
const logger = log.for("testchannel");
logger.debug(1, 2, 3);
logger.info(2, 3, 4);
logger.warn(3, 4, 5);
logger.error(4, 5, 6);
expect(logEntries).to.deep.equal([
"1970-01-01T00:00:05.015Z debug testchannel 1 2 3",
"+15 info testchannel 2 3 4",
"+15 warn testchannel 3 4 5",
"+15 error testchannel 4 5 6"
]);
});
});
});
import { Stream, Writable } from 'stream';
import * as util from 'util';
export const logLevel = {
debug: 1,
info: 10,
warn: 20,
error: 30,
};
// Level number -> level name
const levelName: { [levelNr: number]: string } = {};
Object.keys(logLevel).forEach(levelStr => {
levelName[logLevel[levelStr]] = levelStr;
});
export interface IChannelConfig {
/**
* The log-level of this config
*/
logLevel: number;
channelMatch: RegExp | string;
/**
* The log function that performs the actual logging (such as "console.log")
* @param channel
* @param logLevel
* @param args
*/
logFn(channel: string, logLevel: number, ...args: any[]): void;
}
export interface ILogFacade {
debug(...args: any[]): void;
info(...args: any[]): void;
warn(...args: any[]): void;
error(...args: any[]): void;
}
// Timestamp of the last log output
let lastLog: number | null = null;
export function toStream(stream: Writable) {
return function out(channel: string, level: number, ...args) {
const str = util.format.apply(util, args);
const now = Date.now();
let dateStr: string;
dateStr = lastLog ? `+${now - lastLog}` : new Date(now).toISOString();
lastLog = now;
stream.write(`${dateStr} ${levelName[level]} ${channel} ${str}`);
};
}
export class LogManager {
private channelConfigs: IChannelConfig[] = [];
private defaultConfig: IChannelConfig = {
channelMatch: /.*/,
logLevel: logLevel.info,
logFn: toStream(process.stdout),
};
public configure(channelConfigs: IChannelConfig[], defaultLogger: (...args) => void, defaultLogLevel: number): void {
this.channelConfigs = channelConfigs;
this.defaultConfig.logFn = defaultLogger;
this.defaultConfig.logLevel = defaultLogLevel;
}
public for(channel: string): ILogFacade {
return {
debug: (...args: any[]) => this.log(channel, logLevel.debug, ...args),
info: (...args: any[]) => this.log(channel, logLevel.info, ...args),
warn: (...args: any[]) => this.log(channel, logLevel.warn, ...args),
error: (...args: any[]) => this.log(channel, logLevel.error, ...args),
};
}
private log(channel: string, level: number, ...args: any[]): void {
const matchingConfig =
this.channelConfigs.find(config => {
if (config.channelMatch instanceof RegExp) {
return config.channelMatch.test(channel);
} else {
// string
return config.channelMatch === channel;
}
}) || this.defaultConfig;
if (matchingConfig.logLevel <= level) {
matchingConfig.logFn(channel, level, ...args);
}
}
}
export const log = new LogManager();
@nknapp
Copy link
Author

nknapp commented Jun 4, 2018

I wanted something more like log4j, with channels and levels and a centralized configuration. It's not finished, but I am sticking to pino fo now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment