Skip to content

Commit

Permalink
Human reporter as Bunyan stream (#36)
Browse files Browse the repository at this point in the history
* Human readable log is being made from bunyan log entries

* Minor code formatting

* Inline function to test

* Minor refactoring

* Return pid in log

* Return spaces to some curves

* Blacklist params rather than delete them

* Fix blacklisting for node4
  • Loading branch information
artmnv authored and ai committed Jun 27, 2017
1 parent 8e614d8 commit 0e0bbbf
Show file tree
Hide file tree
Showing 12 changed files with 360 additions and 297 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"jest": "^20.0.4",
"jsdoc": "^3.4.3",
"lint-staged": "^4.0.0",
"memory-stream": "^0.0.3",
"pre-commit": "^1.2.2",
"rimraf": "^2.6.1",
"yaspeller-ci": "^0.4.0"
Expand Down
38 changes: 22 additions & 16 deletions reporters/bunyan/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,25 @@ function clientParams (client) {
const reporters = {

listen (app) {
let msg
const details = {
loguxServer: pkg.version,
nodeId: app.nodeId,
environment: app.env,
subprotocol: app.options.subprotocol,
supports: app.options.supports,
listen: reportersCommon.getAppUrl(app)
}
if (app.env === 'development') {
msg = 'Logux server is listening in non-secure development mode'
} else {
msg = 'Logux server is listening'
details.note = [
'Server was started in non-secure development mode',
'Press Ctrl-C to shutdown server'
]
}

return {
level: 'info',
msg,
details: {
loguxServer: pkg.version,
nodeId: app.nodeId,
environment: app.env,
subprotocol: app.options.subprotocol,
supports: app.options.supports,
listen: reportersCommon.getAppUrl(app)
}
msg: 'Logux server is listening',
details
}
},

Expand Down Expand Up @@ -97,13 +98,18 @@ const reporters = {
},

runtimeError (app, err, action, meta) {
const details = {}
let prefix = `${ err.name }: ${ err.message }`
if (err.name === 'Error') prefix = err.message

const details = {
stacktrace: err.stack
}
if (meta) {
details['actionID'] = meta.id
details['actionId'] = meta.id
}
return {
level: 'error',
msg: err,
msg: prefix,
details
}
},
Expand Down
110 changes: 110 additions & 0 deletions reporters/human/format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use strict'

const stream = require('stream')
const helpers = require('../human/helpers')

// Levels
const TRACE = 10
const DEBUG = 20
const INFO = 30
const WARN = 40
const ERROR = 50
const FATAL = 60

/**
* Writable stream that formats bunyan records written to human readable.
*/
class BunyanFormatWritable extends stream.Writable {
/**
* @param {Server} app application object
* @param {Stream} out (process.stdout) writable stream to write
*/
constructor (app, out) {
super()
this.out = out || process.stdout
this.app = app

const levelFromName = {
trace: TRACE,
debug: DEBUG,
info: INFO,
warn: WARN,
error: ERROR,
fatal: FATAL
}
this.nameFromLevel = {}
Object.keys(levelFromName).forEach(name => {
const lvl = levelFromName[name]
this.nameFromLevel[lvl] = name
})
}

write (chunk, encoding, cb) {
let rec
const callback = cb || (() => {})
try {
rec = JSON.parse(chunk)
this.out.write(this.formatRecord(rec, this.app))
} catch (e) {
this.out.write(chunk)
}
callback()
}

formatRecord (rec, app) {
let message = []
const c = helpers.color(app)

message.push(helpers[this.nameFromLevel[rec.level]](c, rec.msg))

if (rec.hint) {
message = message.concat(helpers.hint(c, rec.hint))
}

if (rec.stacktrace) {
message = message.concat(
helpers.prettyStackTrace(c, rec.stacktrace, app.options.root)
)
}

let note = []
if (rec.note) {
note = helpers.note(c, rec.note)
}

const params = []
if (rec.listen) {
params.push(['PID', rec.pid])
}

const blacklist = ['v', 'name', 'component', 'hostname', 'time', 'msg',
'level', 'hint', 'stacktrace', 'note', 'pid']
const leftover = Object.keys(rec)
for (let i = 0; i < leftover.length; i++) {
const key = leftover[i]
if (blacklist.indexOf(key) === -1) {
const value = rec[key]
const name = key
.replace(/([A-Z])/g, ' $1')
.toLowerCase()
.split(' ')
.map(elem => {
if (elem === 'id') return 'ID'
if (elem === 'ip') return 'IP'

return elem
})
.join(' ')
.replace(/^./, str => str.toUpperCase())
params.push([name, value])
}
}

message = message.concat(helpers.params(c, params))
message = message.concat(note)

return helpers.message(message)
}
}

module.exports = BunyanFormatWritable
11 changes: 4 additions & 7 deletions reporters/human/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ module.exports = {
}
return fields.map(field => {
const name = field[0]
let value = field[1]
const value = field[1]

const start = PADDING + rightPag(`${ name }: `, max)
if (value instanceof Date) {
value = yyyymmdd.withTime(value)
}

if (name === 'Node ID') {
const pos = value.indexOf(':')
Expand Down Expand Up @@ -87,13 +84,13 @@ module.exports = {
},

note (c, str) {
return PADDING + c.grey(str)
return str.map(i => PADDING + c.grey(i)).join(NEXT_LINE)
},

prettyStackTrace (c, err, root) {
prettyStackTrace (c, stacktrace, root) {
if (root.slice(-1) !== path.sep) root += path.sep

return err.stack.split('\n').slice(1).map(i => {
return stacktrace.split('\n').slice(1).map(i => {
i = i.replace(/^\s*/, PADDING)
const match = i.match(/(\s+at [^(]+ \()([^)]+)\)/)
if (!match || match[2].indexOf(root) !== 0) {
Expand Down
Loading

0 comments on commit 0e0bbbf

Please sign in to comment.