| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 | 'use strict'var Progress = require('are-we-there-yet')var Gauge = require('gauge')var EE = require('events').EventEmittervar 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.stderrObject.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 colorEnabledlog.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 levellog.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 unicodeEnabledlog.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 objecttrackerConstructors.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 droplog.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 = 0log.record = []log.maxRecordSize = 10000log.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' prefixlog.on('error', function () {})
 |