You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							309 lines
						
					
					
						
							8.4 KiB
						
					
					
				
			
		
		
	
	
							309 lines
						
					
					
						
							8.4 KiB
						
					
					
				'use strict' | 
						|
var Progress = require('are-we-there-yet') | 
						|
var Gauge = require('gauge') | 
						|
var EE = require('events').EventEmitter | 
						|
var log = exports = module.exports = new EE() | 
						|
var util = require('util') | 
						|
 | 
						|
var setBlocking = require('set-blocking') | 
						|
var consoleControl = require('console-control-strings') | 
						|
 | 
						|
setBlocking(true) | 
						|
var stream = process.stderr | 
						|
Object.defineProperty(log, 'stream', { | 
						|
  set: function (newStream) { | 
						|
    stream = newStream | 
						|
    if (this.gauge) this.gauge.setWriteTo(stream, stream) | 
						|
  }, | 
						|
  get: function () { | 
						|
    return stream | 
						|
  } | 
						|
}) | 
						|
 | 
						|
// by default, decide based on tty-ness. | 
						|
var colorEnabled | 
						|
log.useColor = function () { | 
						|
  return colorEnabled != null ? colorEnabled : stream.isTTY | 
						|
} | 
						|
 | 
						|
log.enableColor = function () { | 
						|
  colorEnabled = true | 
						|
  this.gauge.setTheme({hasColor: colorEnabled, hasUnicode: unicodeEnabled}) | 
						|
} | 
						|
log.disableColor = function () { | 
						|
  colorEnabled = false | 
						|
  this.gauge.setTheme({hasColor: colorEnabled, hasUnicode: unicodeEnabled}) | 
						|
} | 
						|
 | 
						|
// default level | 
						|
log.level = 'info' | 
						|
 | 
						|
log.gauge = new Gauge(stream, { | 
						|
  enabled: false, // no progress bars unless asked | 
						|
  theme: {hasColor: log.useColor()}, | 
						|
  template: [ | 
						|
    {type: 'progressbar', length: 20}, | 
						|
    {type: 'activityIndicator', kerning: 1, length: 1}, | 
						|
    {type: 'section', default: ''}, | 
						|
    ':', | 
						|
    {type: 'logline', kerning: 1, default: ''} | 
						|
  ] | 
						|
}) | 
						|
 | 
						|
log.tracker = new Progress.TrackerGroup() | 
						|
 | 
						|
// we track this separately as we may need to temporarily disable the | 
						|
// display of the status bar for our own loggy purposes. | 
						|
log.progressEnabled = log.gauge.isEnabled() | 
						|
 | 
						|
var unicodeEnabled | 
						|
 | 
						|
log.enableUnicode = function () { | 
						|
  unicodeEnabled = true | 
						|
  this.gauge.setTheme({hasColor: this.useColor(), hasUnicode: unicodeEnabled}) | 
						|
} | 
						|
 | 
						|
log.disableUnicode = function () { | 
						|
  unicodeEnabled = false | 
						|
  this.gauge.setTheme({hasColor: this.useColor(), hasUnicode: unicodeEnabled}) | 
						|
} | 
						|
 | 
						|
log.setGaugeThemeset = function (themes) { | 
						|
  this.gauge.setThemeset(themes) | 
						|
} | 
						|
 | 
						|
log.setGaugeTemplate = function (template) { | 
						|
  this.gauge.setTemplate(template) | 
						|
} | 
						|
 | 
						|
log.enableProgress = function () { | 
						|
  if (this.progressEnabled) return | 
						|
  this.progressEnabled = true | 
						|
  this.tracker.on('change', this.showProgress) | 
						|
  if (this._pause) return | 
						|
  this.gauge.enable() | 
						|
} | 
						|
 | 
						|
log.disableProgress = function () { | 
						|
  if (!this.progressEnabled) return | 
						|
  this.progressEnabled = false | 
						|
  this.tracker.removeListener('change', this.showProgress) | 
						|
  this.gauge.disable() | 
						|
} | 
						|
 | 
						|
var trackerConstructors = ['newGroup', 'newItem', 'newStream'] | 
						|
 | 
						|
var mixinLog = function (tracker) { | 
						|
  // mixin the public methods from log into the tracker | 
						|
  // (except: conflicts and one's we handle specially) | 
						|
  Object.keys(log).forEach(function (P) { | 
						|
    if (P[0] === '_') return | 
						|
    if (trackerConstructors.filter(function (C) { return C === P }).length) return | 
						|
    if (tracker[P]) return | 
						|
    if (typeof log[P] !== 'function') return | 
						|
    var func = log[P] | 
						|
    tracker[P] = function () { | 
						|
      return func.apply(log, arguments) | 
						|
    } | 
						|
  }) | 
						|
  // if the new tracker is a group, make sure any subtrackers get | 
						|
  // mixed in too | 
						|
  if (tracker instanceof Progress.TrackerGroup) { | 
						|
    trackerConstructors.forEach(function (C) { | 
						|
      var func = tracker[C] | 
						|
      tracker[C] = function () { return mixinLog(func.apply(tracker, arguments)) } | 
						|
    }) | 
						|
  } | 
						|
  return tracker | 
						|
} | 
						|
 | 
						|
// Add tracker constructors to the top level log object | 
						|
trackerConstructors.forEach(function (C) { | 
						|
  log[C] = function () { return mixinLog(this.tracker[C].apply(this.tracker, arguments)) } | 
						|
}) | 
						|
 | 
						|
log.clearProgress = function (cb) { | 
						|
  if (!this.progressEnabled) return cb && process.nextTick(cb) | 
						|
  this.gauge.hide(cb) | 
						|
} | 
						|
 | 
						|
log.showProgress = function (name, completed) { | 
						|
  if (!this.progressEnabled) return | 
						|
  var values = {} | 
						|
  if (name) values.section = name | 
						|
  var last = log.record[log.record.length - 1] | 
						|
  if (last) { | 
						|
    values.subsection = last.prefix | 
						|
    var disp = log.disp[last.level] || last.level | 
						|
    var logline = this._format(disp, log.style[last.level]) | 
						|
    if (last.prefix) logline += ' ' + this._format(last.prefix, this.prefixStyle) | 
						|
    logline += ' ' + last.message.split(/\r?\n/)[0] | 
						|
    values.logline = logline | 
						|
  } | 
						|
  values.completed = completed || this.tracker.completed() | 
						|
  this.gauge.show(values) | 
						|
}.bind(log) // bind for use in tracker's on-change listener | 
						|
 | 
						|
// temporarily stop emitting, but don't drop | 
						|
log.pause = function () { | 
						|
  this._paused = true | 
						|
  if (this.progressEnabled) this.gauge.disable() | 
						|
} | 
						|
 | 
						|
log.resume = function () { | 
						|
  if (!this._paused) return | 
						|
  this._paused = false | 
						|
 | 
						|
  var b = this._buffer | 
						|
  this._buffer = [] | 
						|
  b.forEach(function (m) { | 
						|
    this.emitLog(m) | 
						|
  }, this) | 
						|
  if (this.progressEnabled) this.gauge.enable() | 
						|
} | 
						|
 | 
						|
log._buffer = [] | 
						|
 | 
						|
var id = 0 | 
						|
log.record = [] | 
						|
log.maxRecordSize = 10000 | 
						|
log.log = function (lvl, prefix, message) { | 
						|
  var l = this.levels[lvl] | 
						|
  if (l === undefined) { | 
						|
    return this.emit('error', new Error(util.format( | 
						|
      'Undefined log level: %j', lvl))) | 
						|
  } | 
						|
 | 
						|
  var a = new Array(arguments.length - 2) | 
						|
  var stack = null | 
						|
  for (var i = 2; i < arguments.length; i++) { | 
						|
    var arg = a[i - 2] = arguments[i] | 
						|
 | 
						|
    // resolve stack traces to a plain string. | 
						|
    if (typeof arg === 'object' && arg && | 
						|
        (arg instanceof Error) && arg.stack) { | 
						|
 | 
						|
      Object.defineProperty(arg, 'stack', { | 
						|
        value: stack = arg.stack + '', | 
						|
        enumerable: true, | 
						|
        writable: true | 
						|
      }) | 
						|
    } | 
						|
  } | 
						|
  if (stack) a.unshift(stack + '\n') | 
						|
  message = util.format.apply(util, a) | 
						|
 | 
						|
  var m = { id: id++, | 
						|
            level: lvl, | 
						|
            prefix: String(prefix || ''), | 
						|
            message: message, | 
						|
            messageRaw: a } | 
						|
 | 
						|
  this.emit('log', m) | 
						|
  this.emit('log.' + lvl, m) | 
						|
  if (m.prefix) this.emit(m.prefix, m) | 
						|
 | 
						|
  this.record.push(m) | 
						|
  var mrs = this.maxRecordSize | 
						|
  var n = this.record.length - mrs | 
						|
  if (n > mrs / 10) { | 
						|
    var newSize = Math.floor(mrs * 0.9) | 
						|
    this.record = this.record.slice(-1 * newSize) | 
						|
  } | 
						|
 | 
						|
  this.emitLog(m) | 
						|
}.bind(log) | 
						|
 | 
						|
log.emitLog = function (m) { | 
						|
  if (this._paused) { | 
						|
    this._buffer.push(m) | 
						|
    return | 
						|
  } | 
						|
  if (this.progressEnabled) this.gauge.pulse(m.prefix) | 
						|
  var l = this.levels[m.level] | 
						|
  if (l === undefined) return | 
						|
  if (l < this.levels[this.level]) return | 
						|
  if (l > 0 && !isFinite(l)) return | 
						|
 | 
						|
  // If 'disp' is null or undefined, use the lvl as a default | 
						|
  // Allows: '', 0 as valid disp | 
						|
  var disp = log.disp[m.level] != null ? log.disp[m.level] : m.level | 
						|
  this.clearProgress() | 
						|
  m.message.split(/\r?\n/).forEach(function (line) { | 
						|
    if (this.heading) { | 
						|
      this.write(this.heading, this.headingStyle) | 
						|
      this.write(' ') | 
						|
    } | 
						|
    this.write(disp, log.style[m.level]) | 
						|
    var p = m.prefix || '' | 
						|
    if (p) this.write(' ') | 
						|
    this.write(p, this.prefixStyle) | 
						|
    this.write(' ' + line + '\n') | 
						|
  }, this) | 
						|
  this.showProgress() | 
						|
} | 
						|
 | 
						|
log._format = function (msg, style) { | 
						|
  if (!stream) return | 
						|
 | 
						|
  var output = '' | 
						|
  if (this.useColor()) { | 
						|
    style = style || {} | 
						|
    var settings = [] | 
						|
    if (style.fg) settings.push(style.fg) | 
						|
    if (style.bg) settings.push('bg' + style.bg[0].toUpperCase() + style.bg.slice(1)) | 
						|
    if (style.bold) settings.push('bold') | 
						|
    if (style.underline) settings.push('underline') | 
						|
    if (style.inverse) settings.push('inverse') | 
						|
    if (settings.length) output += consoleControl.color(settings) | 
						|
    if (style.beep) output += consoleControl.beep() | 
						|
  } | 
						|
  output += msg | 
						|
  if (this.useColor()) { | 
						|
    output += consoleControl.color('reset') | 
						|
  } | 
						|
  return output | 
						|
} | 
						|
 | 
						|
log.write = function (msg, style) { | 
						|
  if (!stream) return | 
						|
 | 
						|
  stream.write(this._format(msg, style)) | 
						|
} | 
						|
 | 
						|
log.addLevel = function (lvl, n, style, disp) { | 
						|
  // If 'disp' is null or undefined, use the lvl as a default | 
						|
  if (disp == null) disp = lvl | 
						|
  this.levels[lvl] = n | 
						|
  this.style[lvl] = style | 
						|
  if (!this[lvl]) { | 
						|
    this[lvl] = function () { | 
						|
      var a = new Array(arguments.length + 1) | 
						|
      a[0] = lvl | 
						|
      for (var i = 0; i < arguments.length; i++) { | 
						|
        a[i + 1] = arguments[i] | 
						|
      } | 
						|
      return this.log.apply(this, a) | 
						|
    }.bind(this) | 
						|
  } | 
						|
  this.disp[lvl] = disp | 
						|
} | 
						|
 | 
						|
log.prefixStyle = { fg: 'magenta' } | 
						|
log.headingStyle = { fg: 'white', bg: 'black' } | 
						|
 | 
						|
log.style = {} | 
						|
log.levels = {} | 
						|
log.disp = {} | 
						|
log.addLevel('silly', -Infinity, { inverse: true }, 'sill') | 
						|
log.addLevel('verbose', 1000, { fg: 'blue', bg: 'black' }, 'verb') | 
						|
log.addLevel('info', 2000, { fg: 'green' }) | 
						|
log.addLevel('timing', 2500, { fg: 'green', bg: 'black' }) | 
						|
log.addLevel('http', 3000, { fg: 'green', bg: 'black' }) | 
						|
log.addLevel('notice', 3500, { fg: 'blue', bg: 'black' }) | 
						|
log.addLevel('warn', 4000, { fg: 'black', bg: 'yellow' }, 'WARN') | 
						|
log.addLevel('error', 5000, { fg: 'red', bg: 'black' }, 'ERR!') | 
						|
log.addLevel('silent', Infinity) | 
						|
 | 
						|
// allow 'error' prefix | 
						|
log.on('error', function () {})
 | 
						|
 |