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.

155 lines
3.9 KiB

var EE = require('events').EventEmitter
var log = exports = module.exports = new EE
var util = require('util')
var ansi = require('ansi')
log.cursor = ansi(process.stderr)
log.stream = process.stderr
// by default, let ansi decide based on tty-ness.
var colorEnabled = undefined
log.enableColor = function () {
colorEnabled = true
this.cursor.enabled = true
}
log.disableColor = function () {
colorEnabled = false
this.cursor.enabled = false
}
// default level
log.level = 'info'
// temporarily stop emitting, but don't drop
log.pause = function () {
this._paused = true
}
log.resume = function () {
if (!this._paused) return
this._paused = false
var b = this._buffer
this._buffer = []
b.forEach(function (m) {
this.emitLog(m)
}, this)
}
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) {
arg.stack = stack = arg.stack + ''
}
}
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
}
var l = this.levels[m.level]
if (l === undefined) return
if (l < this.levels[this.level]) return
if (l > 0 && !isFinite(l)) return
var style = log.style[m.level]
var disp = log.disp[m.level] || m.level
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)
}
log.write = function (msg, style) {
if (!this.cursor) return
if (this.stream !== this.cursor.stream) {
this.cursor = ansi(this.stream, { enabled: colorEnabled })
}
style = style || {}
if (style.fg) this.cursor.fg[style.fg]()
if (style.bg) this.cursor.bg[style.bg]()
if (style.bold) this.cursor.bold()
if (style.underline) this.cursor.underline()
if (style.inverse) this.cursor.inverse()
if (style.beep) this.cursor.beep()
this.cursor.write(msg).reset()
}
log.addLevel = function (lvl, n, style, disp) {
if (!disp) 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('http', 3000, { fg: 'green', bg: 'black' })
log.addLevel('warn', 4000, { fg: 'black', bg: 'yellow' }, 'WARN')
log.addLevel('error', 5000, { fg: 'red', bg: 'black' }, 'ERR!')
log.addLevel('silent', Infinity)