src/logger/nodeLogger.ts
import { isEmpty, difference, keys, omit } from 'lodash';
import { Logger as WLogger, createLogger, transports, format } from 'winston';
import { Logger, ELoggingLevel } from './logger';
const LoggerHash = {
[ELoggingLevel.Silly]: 'silly',
[ELoggingLevel.Verbose]: 'verbose',
[ELoggingLevel.Debug]: 'debug',
[ELoggingLevel.Log]: 'log',
[ELoggingLevel.Warn]: 'warn',
[ELoggingLevel.Error]: 'error',
[ELoggingLevel.Silent]: 'silent',
};
export class NodeLogger extends Logger {
public set level( level: ELoggingLevel ) {
this.logger.level = LoggerHash[level];
this._level = level;
}
public get level() {
return this._level;
}
protected logger: WLogger;
public constructor() {
const { combine, json } = format;
const log = createLogger( {
level: LoggerHash[ELoggingLevel.Silly],
format: json(),
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
],
} );
log.add( new transports.Console( {
format: combine(
format.colorize(),
format.printf( NodeLogger.format )
),
} ) );
super( {
silly: log.silly.bind( log ),
verbose: log.verbose.bind( log ),
debug: log.debug.bind( log ),
log: log.info.bind( log ),
warn: log.warn.bind( log ),
error: log.error.bind( log ),
} );
this.logger = log;
}
/**
* Trims the string to the provided length, using the sufficient number of filler characters on the left or rigth
*
* @author Gerkin
* @param str - String to trim to the target length
* @param len - Desired length of the string, that will be reached using filler chars
* @param filler - Chars to repeat in order to fill the missing space in string
* @param left - Set to false to trim on the right
*/
protected static trimToLength(
str: string | number,
len: number = 2,
filler = '0',
left = true
){
filler = filler.repeat( len );
str = left ? filler + str : str + filler;
return str.slice( left ? -len : len );
}
/**
* Format the date to a readable format
*
* @author Gerkin
* @param date - Date to convert to string
*/
protected static formatDate( date = new Date() ){
const datePart = `${NodeLogger.trimToLength( date.getDay() )}/${NodeLogger.trimToLength( date.getMonth() + 1 )}/${NodeLogger.trimToLength( date.getFullYear(), 4 )}`;
const timePart = `${NodeLogger.trimToLength( date.getHours() )}:${NodeLogger.trimToLength( date.getMinutes() )}:${NodeLogger.trimToLength( date.getSeconds() )}`;
return `${datePart} ${timePart}:${NodeLogger.trimToLength( date.getMilliseconds(), 3 )}`;
}
/**
* Main logger function used by Diaspora on node environment, disaplying `Diaspora`, colors & the date
*
* @author Gerkin
* @param infos - Winston message infos
*/
protected static format( infos: { [x: string]: any; level: string; message: any } ){
const LEVEL = Symbol.for( 'level' );
// Ugly patch related to [a known typescript missing feature](https://github.com/Microsoft/TypeScript/issues/24587)
// TODO: Remove this `any` cast.
const level = infos[LEVEL as any];
// Add 'Diaspora: ' before the log level name
infos.level = infos.level.replace( level, 'Diaspora: ' + level );
let message = `${infos.level} @ ${NodeLogger.formatDate()} => ${infos.message}`;
const omittedKeys = ['level', 'message', 'splat'];
if ( !isEmpty( difference( keys( infos ), omittedKeys ) ) ) {
message += ' ' + JSON.stringify( omit( infos, omittedKeys ) );
}
return message;
}
}