UNPKG

gulp-messenger

Version:
589 lines (501 loc) 15.6 kB
/*global require */ // GULP MESSENGER // ============================================================================= // this is required to support .orange color // eventually want to restore "use strict" waiting on chalk var VERSION = require('./package.json').version; var chalk = require('chalk'); var is = require('is_js'); var mkdirp = require('mkdirp'); var moment = require('moment'); var path = require("path"); var prettyHrtime = require('pretty-hrtime'); var through = require('through2'); var Table = require('easy-table'); var Purdy = require('purdy'); var bowser = require('bowser'); var sprintf = require("sprintf-js").sprintf; var _ = require('lodash'); _.mixin(require('lodash-deep')); var winston = null; if(bowser.name.length === 0) { var winston = require('winston'); } // MODULE CONSTANTS // ============================================================================= var VALUE_REGEXP = /<%=\s*([^\s]+)\s*%>/g; var COLOR_ORANGE = chalk.red(); var COLOR_RESET = chalk.white(); var COLOR_CODES_REGEXP = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; /*eslint-disable */ if(! isStrictMode() ) { COLOR_ORANGE = '\033[38;5;214m'; COLOR_RESET = '\033[m'; } /*eslint-enable */ function isStrictMode() { return (typeof this === 'undefined'); } // SETUP DEFAULT OPTIONS // ============================================================================= var defOptions = { logToFile: false, logToConsole: true, logTimestampFormat: 'YYYY-MM-DD HH:mm:ss Z', logPath: 'logs/', logFile: 'app.log', timestamp: false, rotateLog: false, boldVariables: true, showPipeFile: true, useDumpForObjects: true, lineLength: 80, chalklineBox: '\u2584' // '\u2588' }; // unicode blocks -- http://graphemica.com/blocks/block-elements // SETUP CHALKLINE // chalkline.options({block: defOptions.chalklineBox}); // SETUP WINSTON // ============================================================================= // Initialize logger, additional settings will be created in `init` method var logger = null; if ( bowser.name.length === 0) { var logger = new (winston.Logger)({level: 'debug'}); } // MODULE DEFINITION (used by module.exports below) // ============================================================================= var messenger = { orange: function(msg) { if( !is.undefined(msg) ) { return COLOR_ORANGE + msg + COLOR_RESET; } return COLOR_ORANGE; }, init: init(), setOptions: setOptions(), name: 'gulp-messenger', info: new Message('info'), log: new Message('info'), success: new Message('success'), warning: new Message('warning'), warn: new Message('warning'), error: new Message('error'), note: new Message('note'), table: new Message('table'), time: new Message('time'), debug: new Message('debug'), line: new Message('line'), header: new Message('header'), dir: function() { Purdy.apply(Purdy, arguments); }, purdy: function() { Purdy.apply(Purdy, arguments); }, dump: function() { Purdy.apply(Purdy, arguments); }, version: function() { return VERSION; }, chalkline: false, chalk: chalk, colors: chalk, flush: { info: message('info', true), log: message('info', true), success: message('success', true), warning: message('warning', true), warn: message('warning', true), error: message('error', true), note: message('note', true), table: message('table', true), time: message('time', true), debug: message('debug', true), line: message('line', true), header: message('header',true), chalkline: false, dir: function() { Purdy.apply(Purdy, arguments); }, purdy: function() { Purdy.apply(Purdy, arguments); }, dump: function(){ Purdy.apply(Purdy, arguments); } }, Info: new Message('info'), Log: new Message('info'), Success: new Message('success'), Warning: new Message('warning'), Warn: new Message('warning'), Error: new Message('error'), Note: new Message('note'), Time: new Message('time'), Debug: new Message('debug'), Line: new Message('line'), Header: new Message('header'), Table: new Message('table'), Purdy: function() { Purdy.apply(Purdy, arguments); }, Dump: function() { Purdy.apply(Purdy, arguments); }, Version: function() { return VERSION; } }; // MODULE ENTRY POINTS // ============================================================================= function message(style, useFlush) { var totalStart = process.hrtime(); return function() { var args = getArgs(arguments); var lastFile = {}; var start = process.hrtime(); function transform(file, enc, callback) { lastFile = file; if (!useFlush) { args.data.file = _.clone(file); args.data.file.relative = path.relative(file.base, file.path); args.data.file.basename = path.basename(file.path); args.data.duration = prettyHrtime(process.hrtime(start)); args.data.totalDuration = prettyHrtime(process.hrtime(totalStart)); notify(style, args.before, args.message, args.after, args.data); } callback(null, file); } function flush(callback) { if (useFlush) { // not sure how this is going to be used as we are clearing .data below args.data.file = _.clone(lastFile); args.data.duration = prettyHrtime(process.hrtime(start)); args.data.totalDuration = prettyHrtime(process.hrtime(totalStart)); // gulp pipeline specific defOptions.timestamp = true; // timestamp always true when in pipeline args.data = {}; // no data available in gulp pipeline // this is only appropriate adjustment to message (to include the filename) var msg = args.message; if (defOptions.showPipeFile) { msg += ' [' + lastFile.relative + '] '; } notify(style, args.before, msg, args.after, args.data); } callback(); } return through.obj(transform, flush); }; } function Message(style) { return function() { var args = getArgs(arguments); if((is.object(args.message)) && (arguments.length === 1) && (defOptions.useDumpForObjects)) { /* jshint -W064 */ if(style === 'table') { console.log(Table.print(args.message)); } else { Purdy(args.message); } } else { notify(style, args.before, args.message, args.after, args.data); } }; } // MODULE PRIVATE METHOD // ============================================================================= function init(options) { var added = false; return function(options) { var isBrowser = bowser.name.length > 0; if(is.not.undefined(options)) { defOptions = _.defaults(options, defOptions); } if(defOptions.logPath[defOptions.logPath.length] !== '/') { defOptions.logPath += '/'; } if(! isBrowser) { // create log path if it doesn't already exist, only create if we have enabled fileLogging if (defOptions.logToFile) mkdirp(defOptions.logPath); defOptions.logFilename = defOptions.logPath + defOptions.logFile; if ( defOptions.rotateLog ) { logger.add(winston.transports.DailyRotateFile,{ filename: defOptions.logFilename, timestamp: function() { return moment().format(defOptions.logTimestampFormat); } }); } else { if( ! added ) { added = true; logger.add(winston.transports.File,{ filename: defOptions.logFilename, timestamp: function() { return moment().format(defOptions.logTimestampFormat); } }); } } } else { console.warn('Logging Disabled On Browser'); } // only do this once regardless so outside browser check defOptions.logInitialized = true; // update chalkine in the event supplied block or length // chalkline.options({block: defOptions.chalklineBox}); }; } function notify(style, before, message, after, data) { debugger; var text, variable; var result = ''; var tokens; // 2015.05.28 - added bounds check, exposed when adding *.line() routine if( is.undefined(message) ) { message = ''; } debugger; if ( (is.not.object(message)) && (is.not.number(message)) ) { tokens = message.split(VALUE_REGEXP); } else { tokens = message; } switch (style) { case "info": case 'log': text = chalk.cyan; variable = chalk.cyan.bold; break; case "success": text = chalk.green; variable = chalk.green.bold; break; case "warning": text = chalk.yellow; variable = chalk.yellow.bold; break; case "error": text = chalk.red; variable = chalk.red.bold; break; case "note": text = COLOR_ORANGE; variable = chalk.white; break; case "table": text = chalk.white; variable = chalk.white; case "time": text = chalk.magenta; variable = chalk.magenta.bold; break; case "debug": text = chalk.grey.dim; variable = chalk.grey.dim.bold; break; case "line": text = chalk.green; variable = chalk.green.bold; break; case "header": text = chalk.white.underline; variable = chalk.white; break; default: text = chalk.gray; variable = chalk.white; break; } // if we don't have bold variables (for merging), set variable to text color if( ! defOptions.boldVariables ) { variable = text; if ( text === chalk.gray ) { variable = chalk.white; } } for (var i = 0; i < tokens.length; i++) { if (i%2) { result += variable(_.deepGet(data, tokens[i]) || ''); } else { if ( text === COLOR_ORANGE) { result = text + tokens[i] + COLOR_RESET; } else { result += text(tokens[i] || ''); } } } // if the supplied message is an object, return object (string) as result if(! result.length ) { result = tokens; } function setConsole(data) { var callData = {}; if ( is.not.undefined(data) ) { callData = data; } var hCurrentTime = moment().format('HH:mm:ss'); if (( defOptions.logToConsole ) && ( style !== 'line')){ if ( defOptions.timestamp || (style === 'time')) { if ( style === 'time') { console.log('[' + chalk.grey(hCurrentTime) + '] ' + hCurrentTime); } else { if ( result ) { if( Object.keys(arguments[0]).length === 2 ) { console.log('[' + chalk.grey(hCurrentTime) + '] ' + result, arguments[0]); } else { console.log('[' + chalk.grey(hCurrentTime) + '] ' + result); } } } } else { if ( is.object(callData)) { if ( Object.keys(callData).length > 0 ) { if(is.array(callData)) { callData.splice(0,0,result); console.log.apply(console, callData); } } else { console.log(result); } } else { console.log(result, callData); } } } // if we are outputting a line, just spit out what we got using `lineLength` if ( style === 'line') { setLine(result); } } function setLine(line) { if (!line) { return; } var result = ''; for (var i = 0; i < defOptions.lineLength; i++) { result += line; } if ( defOptions.logToConsole ) { // we have to handle orange separately if(typeof(text) === 'function') { console.log(text(result)); } else { console.log(COLOR_ORANGE + result + COLOR_RESET); } } } function logToFile(style, result) { // make sure we received text, otherwise bail if ( ! is.string(result) ) { return; } // don't bother logging if we have no message if ( result.length === 0 ) { return; } // strip out all the color codes, etc. from message before logging var msg = result.replace(COLOR_CODES_REGEXP,''); // secondary check to make sure we have logging enabled if (defOptions.logToFile) { switch (style) { case 'error': logger.error(msg); break; case 'warning': case 'warn': logger.warn(msg); break; case 'success': logger.info(msg); break; case 'debug': logger.log('debug', msg); break; case 'note': case 'info': case 'log': case 'default': logger.info(msg); break; case 'table': return false; } } } setLine(before); setConsole(data); setLine(after); // don't bother logging if it is disabled, save some processor fumes (defOptions.logToFile) ? logToFile(style, result) : ''; } function getArgs(args) { var msg = ''; if(args.length > 0 ) { var msg = args[0]; if(is.string(msg)) { if ( msg.indexOf('%s') > 0 ) { // we are processing via sprintf var params = Array.prototype.slice.call(args); params.shift(); return { before: '', message: msg, after: '', data: params } } } } var result = { before: args[0], message: args[1], after: args[2] || null, data: args[3] || {} }; if(args.length === 1) { result.before = ''; result.message = args[0]; result.after = ''; } if(args.length === 2) { result.before = args[0]; result.message = args[1]; result.after = ''; } if( is.not.undefined(args[1]) ) { if(is.not.string(args[1])) { result.before = null; result.message = args[0]; result.after = null; result.data = args[1]; // result.data = args; } else if (is.not.string(args[2])) { result.before = args[0]; result.message = args[1]; result.after = null; result.data = args[2]; } } if( is.undefined(result.data) ) { result.data = {}; result.data.file = ''; } //result.data = _.merge({env: process.env}, result.data); return result; } function setOptions(options) { var added = true; return function(options) { if(is.not.undefined(options)) { defOptions = _.defaults(options, defOptions); } if(defOptions.logPath[defOptions.logPath.length] !== '/') { defOptions.logPath += '/'; } // create log path if it doesn't already exist mkdirp(defOptions.logPath); defOptions.logFilename = defOptions.logPath + defOptions.logFile; if ( defOptions.rotateLog ) { logger.add(winston.transports.DailyRotateFile,{filename: defOptions.logFilename}); } else { if( !added ) { added = true; logger.add(winston.transports.File,{filename: defOptions.logFilename}); } } defOptions.logInitialized = true; }; } // MODULE EXPORT // ============================================================================= module.exports = messenger;