Skip to content

Instantly share code, notes, and snippets.

@zerobias
Last active December 9, 2016 13:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zerobias/15b273b367b2be5c2780dead21deb414 to your computer and use it in GitHub Desktop.
Save zerobias/15b273b367b2be5c2780dead21deb414 to your computer and use it in GitHub Desktop.
Logger
const winston = require('winston')
const R = require('ramda')
const chalk = require('chalk') //console colorizer
const P = R.pipe //Short form for pipe: the most frequently used function
const yellowTag = chalk.bold.yellow
const redTag = chalk.bold.bgRed.black
//Simply write 'error' and its will be marked red,
//and any other wiil be yellow if its hasnt have color yet
const colorize = R.ifElse(
R.equals(`[ERROR]`),
redTag,
R.unless(chalk.hasColor, yellowTag))
//' raw tag ' => '[RAW TAG]'
const normalizeTag = P(
R.trim,
R.toUpper,
e => `[${e}]`,
colorize)
//Split tag strings and reject emtpy
//'tag1,tag2,,tag4'
// => [ 'tag1', 'tag2', '', 'tag4' ]
// => [ 'tag1', 'tag2', 'tag4' ]
const splitTagArray = P(
R.split(','),
R.reject(R.isNil))
const normalizeTags = P(
R.flatten,
// allow to send any combination of tags arrays:
// [ 'tag1', [ 'special tag', 'custom tag', [ 'index tag' ] ] ] =>
// [ 'tag1', 'special tag', 'custom tag', 'index tag' ]
R.map(splitTagArray), // [ 'tag1,tag2', 'tag3' ] into [ 'tag1', 'tag2', 'tag3' ]
R.flatten, //
R.map(normalizeTag),
R.join(''))
const isArray = R.is(Array)
const normalizeDefaults = R.ifElse(
R.isEmpty,
() => '', //TODO replace with R.identity
normalizeTags) //Normalize every non-empty tag
const throwNonArray = e => { throw new TypeError(`Recieved ${R.type(e)} (non-array) object`) }
//function arrayPrint allows ony arrays
const arrayCheck = R.unless( isArray, throwNonArray )
const maxArrayLn = 50
//trim arrays to first 50 elements
const messageArrayProtect = R.map(
R.when(
isArray,
R.take( maxArrayLn ) ) )
/**
* Allow to select log level
* @function genericLog
* @param {LoggerInstance} logger Winston logger instance
* @param {string} logLevel Log level
*/
function genericLog(logger, logLevel='info'){
const levelLogger = logger[logLevel]
/**
* tagged Logger
* @function taggedLog
* @param {...string} tags Optional message tags
*/
function taggedLog(...tags){
const tag = normalizeDefaults(tags)
/**
* message Logger
* @function messageLog
* @param {...string} message message
* @returns {void}
*/
function messageLog(...message) {
const protectedMessage = messageArrayProtect(message)
levelLogger(tag, ...protectedMessage)
}
function printArray(message) {
arrayCheck(message)
//count length + 2. Also handles edge case with objects without 'length' field
const spaceLn = P(
R.length,
R.defaultTo(0),
R.add(2) )
const ln = R.sum( R.map( spaceLn, tags ) )
const spaces = new Array(ln)
.fill(' ')
.join('')
const getFormatted = num => chalk.green(`<${num}>`)
levelLogger( tag, getFormatted(0), R.head( message ) )
const printTail = (e, i) => levelLogger(spaces, getFormatted(i+1), e)
//Special declaration in ramda to create common map function: (object,index)=>...
//Because R.map by default allow only object=>... form
const indexedMap = R.addIndex(R.map)
P(
R.tail,
indexedMap(printTail)
)(message)
}
messageLog.map = printArray
return messageLog
}
return taggedLog
}
/**
* Logging function based on winston library
* @function winLog
* @param {string} moduletag Name of apps module
*/
function winLog(moduletag) {
winston.loggers.add(moduletag, {
console: {
colorize: true,
label : moduletag
}
})
const logger = winston.loggers.get(moduletag)
const defs = genericLog(logger)
defs.warn = genericLog(logger, 'warn')
defs.error = genericLog(logger, 'error')
defs.debug = genericLog(logger, 'debug')
defs.info = genericLog(logger, 'info')
return defs
}
//TODO Implement preview print
const printable = maxLen => P( R.toString, R.take( maxLen ) )
const printable100 = printable(100)
module.exports = winLog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment