cedar
Version:
User-friendly logger.
175 lines (146 loc) • 4.33 kB
JavaScript
var doNothing = function () {}
/**
* The `Base` log defines methods that transports will share.
*/
var Base = module.exports = function (config, defaults) {
var cedar = require('../../cedar')
// A log is a shorthand for `log.log`, among other things.
var log = function () {
log.log.apply(log, arguments)
}
// Don't run `setMethods` until all config properties are set.
var setMethods = doNothing
// Define properties that trigger `setMethods`.
Base.resetters.forEach(function (property) {
var value
Object.defineProperty(log, property, {
get: function () {
return value
},
set: function (newValue) {
value = newValue
setMethods.apply(log)
}
})
})
// Copy `config` properties to the `log`.
Base.decorate(log, config, true)
// Apply default properties.
Base.decorate(log, defaults || Base.defaults)
// Set up logging methods.
Base.setMethods.apply(log)
// Re-run `setMethods` if `resetters` change.
setMethods = Base.setMethods
// Return the fully-decorated log function.
return log
}
/**
* Some properties will reset methods if changed.
*/
Base.resetters = ['level', 'prefixes', 'format', 'showTrace']
/**
* Cedar supports 7 levels of logging.
*/
Base.levels = ['trace', 'debug', 'log', 'info', 'warn', 'error', 'fatal']
/**
* Share defaults between log objects.
*/
Base.defaults = {
// Show all log messages by default.
level: 'trace',
// Stream to `stdout` (using `write`).
stream: process.stdout,
// Don't add any space to JSON.
space: '',
// Stringify with `JSON.stringify`.
stringify: JSON.stringify,
// Join arguments together as an array.
join: function (args) {
var list = []
for (var index = 0, length = args.length; index < length; index++) {
var arg = args[index]
if (arg instanceof Error) {
arg = '"' + (arg.stack || arg.toString()).replace(/\n/, '\\n') + '"'
} else {
arg = JSON.stringify(arg, null, this.space)
}
list.push(arg)
}
return '[' + list.join(',') + ']'
},
// Start messages with a prefix for each log method.
prefixes: {
trace: 'TRACE ',
debug: 'DEBUG ',
log: 'LOG ',
info: 'INFO ',
warn: 'WARN ',
error: 'ERROR ',
fatal: 'FATAL '
},
// Format a log message.
format: function (message, type, prefix) {
return prefix + message + '\n'
}
}
/**
* Decorate an object with the properties of another.
*/
Base.decorate = function (object, defaults, shouldOverwrite) {
object = object || {}
for (var key in defaults) {
if (shouldOverwrite || (typeof object[key] === 'undefined')) {
object[key] = defaults[key]
}
}
return object
}
/**
* Create logging methods based on the configured `level`.
*/
Base.setMethods = function () {
var self = this
var found = false
if ((Base.levels.indexOf(self.level) < 0) && self.level !== 'nothing') {
self.error('Unknown log level: "' + self.level + '".')
} else {
Base.levels.forEach(function (methodName, index) {
if (methodName === self.level) {
found = true
}
var prefix = self.prefixes[methodName] || ''
var format = self.format
// If this log is an Emitter, we can catch and emit errors.
if (self.emit) {
self[methodName] = found ? function () {
var message = self.join(arguments)
message = format.call(self, message, methodName, prefix)
try {
self.stream.write(message)
} catch (e) {
self.emit('error', e)
}
} : doNothing
// Otherwise, they'll just throw.
} else {
self[methodName] = found ? function () {
var message = self.join(arguments)
message = format.call(self, message, methodName, prefix)
self.stream.write(message)
} : doNothing
}
})
// Wrap the trace method with a stack tracer.
if (self.trace !== doNothing) {
var traceMethod = self.trace
self.trace = function () {
var e = new Error('')
Error.captureStackTrace(e, self.trace)
var l = arguments.length
arguments[l] = e.stack.split('\n').splice(2).join('\n')
arguments.length = ++l
traceMethod.apply(self, arguments)
}
}
}
}