Current File : //home/tradevaly/www/node_modules/consola/src/consola.js |
import Types from './types.js'
import { isLogObj } from './utils/index.js'
let paused = false
const queue = []
class Consola {
constructor (options = {}) {
this._reporters = options.reporters || []
this._types = options.types || Types
this.level = options.level !== undefined ? options.level : 3
this._defaults = options.defaults || {}
this._async = options.async !== undefined ? options.async : undefined
this._stdout = options.stdout
this._stderr = options.stderr
this._mockFn = options.mockFn
this._throttle = options.throttle || 1000
this._throttleMin = options.throttleMin || 5
// Create logger functions for current instance
for (const type in this._types) {
const defaults = {
type,
...this._types[type],
...this._defaults
}
this[type] = this._wrapLogFn(defaults)
this[type].raw = this._wrapLogFn(defaults, true)
}
// Use _mockFn if is set
if (this._mockFn) {
this.mockTypes()
}
// Keep serialized version of last log
this._lastLogSerialized = undefined
this._lastLog = undefined
this._lastLogTime = undefined
this._lastLogCount = 0
this._throttleTimeout = undefined
}
get stdout () {
return this._stdout || console._stdout // eslint-disable-line no-console
}
get stderr () {
return this._stderr || console._stderr // eslint-disable-line no-console
}
create (options) {
return new Consola(Object.assign({
reporters: this._reporters,
level: this.level,
types: this._types,
defaults: this._defaults,
stdout: this._stdout,
stderr: this._stderr,
mockFn: this._mockFn
}, options))
}
withDefaults (defaults) {
return this.create({
defaults: Object.assign({}, this._defaults, defaults)
})
}
withTag (tag) {
return this.withDefaults({
tag: this._defaults.tag ? (this._defaults.tag + ':' + tag) : tag
})
}
addReporter (reporter) {
this._reporters.push(reporter)
return this
}
removeReporter (reporter) {
if (reporter) {
const i = this._reporters.indexOf(reporter)
if (i >= 0) {
return this._reporters.splice(i, 1)
}
} else {
this._reporters.splice(0)
}
return this
}
setReporters (reporters) {
this._reporters = Array.isArray(reporters)
? reporters
: [reporters]
return this
}
wrapAll () {
this.wrapConsole()
this.wrapStd()
}
restoreAll () {
this.restoreConsole()
this.restoreStd()
}
wrapConsole () {
for (const type in this._types) {
// Backup original value
if (!console['__' + type]) { // eslint-disable-line no-console
console['__' + type] = console[type] // eslint-disable-line no-console
}
// Override
console[type] = this[type].raw // eslint-disable-line no-console
}
}
restoreConsole () {
for (const type in this._types) {
// Restore if backup is available
if (console['__' + type]) { // eslint-disable-line no-console
console[type] = console['__' + type] // eslint-disable-line no-console
delete console['__' + type] // eslint-disable-line no-console
}
}
}
wrapStd () {
this._wrapStream(this.stdout, 'log')
this._wrapStream(this.stderr, 'log')
}
_wrapStream (stream, type) {
if (!stream) {
return
}
// Backup original value
if (!stream.__write) {
stream.__write = stream.write
}
// Override
stream.write = (data) => {
this[type].raw(String(data).trim())
}
}
restoreStd () {
this._restoreStream(this.stdout)
this._restoreStream(this.stderr)
}
_restoreStream (stream) {
if (!stream) {
return
}
if (stream.__write) {
stream.write = stream.__write
delete stream.__write
}
}
pauseLogs () {
paused = true
}
resumeLogs () {
paused = false
// Process queue
const _queue = queue.splice(0)
for (const item of _queue) {
item[0]._logFn(item[1], item[2])
}
}
mockTypes (mockFn) {
this._mockFn = mockFn || this._mockFn
if (typeof this._mockFn !== 'function') {
return
}
for (const type in this._types) {
this[type] = this._mockFn(type, this._types[type]) || this[type]
this[type].raw = this[type]
}
}
_wrapLogFn (defaults, isRaw) {
return (...args) => {
if (paused) {
queue.push([this, defaults, args, isRaw])
return
}
return this._logFn(defaults, args, isRaw)
}
}
_logFn (defaults, args, isRaw) {
if (defaults.level > this.level) {
return this._async ? Promise.resolve(false) : false
}
// Construct a new log object
const logObj = Object.assign({
date: new Date(),
args: []
}, defaults)
// Consume arguments
if (!isRaw && args.length === 1 && isLogObj(args[0])) {
Object.assign(logObj, args[0])
} else {
logObj.args = Array.from(args)
}
// Aliases
if (logObj.message) {
logObj.args.unshift(logObj.message)
delete logObj.message
}
if (logObj.additional) {
if (!Array.isArray(logObj.additional)) {
logObj.additional = logObj.additional.split('\n')
}
logObj.args.push('\n' + logObj.additional.join('\n'))
delete logObj.additional
}
// Normalize type and tag to lowercase
logObj.type = typeof logObj.type === 'string' ? logObj.type.toLowerCase() : ''
logObj.tag = typeof logObj.tag === 'string' ? logObj.tag.toLowerCase() : ''
// Resolve log
/**
* @param newLog false if the throttle expired and
* we don't want to log a duplicate
*/
const resolveLog = (newLog = false) => {
const repeated = this._lastLogCount - this._throttleMin
if (this._lastLog && repeated > 0) {
const args = [...this._lastLog.args]
if (repeated > 1) {
args.push(`(repeated ${repeated} times)`)
}
this._log({ ...this._lastLog, args })
this._lastLogCount = 1
}
// Log
if (newLog) {
this._lastLog = logObj
if (this._async) {
return this._logAsync(logObj)
} else {
this._log(logObj)
}
}
}
// Throttle
clearTimeout(this._throttleTimeout)
const diffTime = this._lastLogTime ? logObj.date - this._lastLogTime : 0
this._lastLogTime = logObj.date
if (diffTime < this._throttle) {
try {
const serializedLog = JSON.stringify([logObj.type, logObj.tag, logObj.args])
const isSameLog = this._lastLogSerialized === serializedLog
this._lastLogSerialized = serializedLog
if (isSameLog) {
this._lastLogCount++
if (this._lastLogCount > this._throttleMin) {
// Auto-resolve when throttle is timed out
this._throttleTimeout = setTimeout(resolveLog, this._throttle)
return // SPAM!
}
}
} catch (_) {
// Circular References
}
}
resolveLog(true)
}
_log (logObj) {
for (const reporter of this._reporters) {
reporter.log(logObj, {
async: false,
stdout: this.stdout,
stderr: this.stderr
})
}
}
_logAsync (logObj) {
return Promise.all(
this._reporters.map(reporter => reporter.log(logObj, {
async: true,
stdout: this.stdout,
stderr: this.stderr
}))
)
}
}
// Legacy support
Consola.prototype.add = Consola.prototype.addReporter
Consola.prototype.remove = Consola.prototype.removeReporter
Consola.prototype.clear = Consola.prototype.removeReporter
Consola.prototype.withScope = Consola.prototype.withTag
Consola.prototype.mock = Consola.prototype.mockTypes
Consola.prototype.pause = Consola.prototype.pauseLogs
Consola.prototype.resume = Consola.prototype.resumeLogs
// Export class
export default Consola