Skip to content

Commit

Permalink
refactoring to new features of es6 and new interface of good. Closes #63
Browse files Browse the repository at this point in the history
 Closes #64 Closes #65
  • Loading branch information
thebergamo committed Mar 21, 2016
1 parent 46c6676 commit d7e3e52
Show file tree
Hide file tree
Showing 6 changed files with 417 additions and 861 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ sudo: false
language: node_js

node_js:
- 0.10
- 4
- "4"
- "node"
27 changes: 8 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,24 @@ Lead Maintainer: [Adam Bretz](https://github.com/arb)

## Usage

`good-console` is a [good](https://github.com/hapijs/good) reporter implementation to write [hapi](http://hapijs.com/) server events to the console.
`good-console` is a [good](https://github.com/hapijs/good) reporter implementation to transform streams of [hapi](http://hapijs.com/) server events into formatted strings.

## `GoodConsole(events, [config])`
## `GoodConsole([config])`
Creates a new GoodConsole object with the following arguments:

- `events` - an object of key value pairs.
- `key` - one of the supported [good events](https://github.com/hapijs/good) indicating the hapi event to subscribe to
- `value` - a single string or an array of strings to filter incoming events. "\*" indicates no filtering. `null` and `undefined` are assumed to be "\*"
- `[config]` - optional configuration object with the following available keys
- `format` - [MomentJS](http://momentjs.com/docs/#/displaying/format/) format string. Defaults to 'YYMMDD/HHmmss.SSS'.
- `utc` - boolean controlling Moment using [utc mode](http://momentjs.com/docs/#/parsing/utc/) or not. Defaults to `true`.
- `color` - a boolean specifying whether to output in color. Defaults to `true`.

## Good Console Methods
### `goodconsole.init(stream, emitter, callback)`
Initializes the reporter with the following arguments:

- `stream` - a Node readable stream that will be the source of data for this reporter. It is assumed that `stream` is in `objectMode`.
- `emitter` - an event emitter object.
- `callback` - a callback to execute when the start function has complete all the necessary set up steps and is ready to receive data.
The example above we use the module `good-squeeze` for filtering our events and pipe that to `GoodConsole` and finally to `stdout` as the `Good` API suggest.

## Output Formats

Below are example outputs for the designated event type:

- "ops" - 141225/093015.900, [ops, `event.tags`], memory: 10Mb, uptime (seconds): 1000, load: [ 1.650390625, 1.6162109375, 1.65234375 ]
- "error" - 141225/093015.900, [error, `event.tags`], message: there was an error, stack: `eventData.stack`
- "request" - 141225/093015.900, [request, `event.tags`], data: {"message":"you made a request to a resource"}
- "log" - 141225/093015.900, [log, `event.tags`], data: you logged a message
- "response" - 141223/164207.694, [response], localhost: post /data {"name":"adam"} 200 (150ms) response payload: {"foo":"bar","value":1}
- "wreck" - 141223/164207.694, [wreck], get: http://hapijs.com/test 200 OK (29ms)
- "wreck" (with error) - 151105/084704.603, [wreck], get: http://hapijs.com/test (7ms) error: some error stack: some stack trace
- "ops" - 160318/013330.957, [ops] memory: 29Mb, uptime (seconds): 6, load: [1.650390625,1.6162109375,1.65234375]
- "error" - 160318/013330.957, [error,`event.tags`] message: Just a simple error stack: `event.error.stack`
- "request" - 160318/013330.957, [request,`event.tags`] data: you made a request
- "log" - 160318/013330.957, [log,`event.tags`] data: you made a default
- "response" - 160318/013330.957, [response, `event.tags`] http://localhost:61253: post /data {"name":"adam"} 200 (150ms)
266 changes: 138 additions & 128 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,172 +1,182 @@
'use strict';

const Squeeze = require('good-squeeze').Squeeze;
// Load Modules

const Hoek = require('hoek');
const Moment = require('moment');
const Stream = require('stream');
const SafeStringify = require('json-stringify-safe');
const Stream = require('stream').Transform;

const internals = {
defaults: {
format: 'YYMMDD/HHmmss.SSS',
utc: true,
color: true
}
defaults: {
format: 'YYMMDD/HHmmss.SSS',
utc: true,
color: true
}
};

class GoodConsole extends Stream {
constructor (config) {

super({objectMode: true});

this.settings = {
format: 'YYMMDD/HHmmss.SSS',
utc: true,
color: true
};
this._filter = new Squeeze(config);
}

_transform (data, enc, next) {

let eventName = data.event;
// let tags = [];
//
// if (Array.isArray(data.tags)) {
// tags = adta.tags.concat([]);
// } else if (data.tags != null) {
// tags = [data.tags];
// }
//
// tags.unshift(eventName);

if (eventName === 'error') {
return next(null, this._formatError(data));
}
internals.utility = {
formatOutput(event, settings) {

if (eventName === 'ops') {
return next(null, this._formatOps(data));
}
let timestamp = Moment(parseInt(event.timestamp, 10));

if (eventName === 'response') {
return next(null, this._formatResponse(data));
}
if (settings.utc) {
timestamp = timestamp.utc();
}

if (!data.data) {
data.data = '(none)';
}
timestamp = timestamp.format(settings.format);

return next(null, this.formatDefault(data));
}
event.tags = event.tags.toString();
const tags = ` [${event.tags}] `;

_formatOutput (event) {
const output = `${timestamp},${tags}${event.data}`;

let timestamp = Moment(parseInt(event.timestamp, 10)).format(this.settings.format);
return output;
},

if (!this.settings.utc) {
timestamp.local();
}
formatMethod(method, settings) {

const output = `${timestamp}, ${event.data}`;
const methodColors = {
get: 32,
delete: 31,
put: 36,
post: 33
};

return output;
}
let formattedMethod = method.toLowerCase();
if (settings.color) {
const color = methodColors[method.toLowerCase()] || 34;
formattedMethod = `\x1b[1;${color}m${formattedMethod}\x1b[0m`;
}

_formatMethod (method) {
return formattedMethod;
},

const methodColors = {
get: 32,
delete: 31,
put: 36,
post: 33
};
formatStatusCode(statusCode, settings) {

let color;
let formattedMethod = method.toLowerCase();
if (this.settings.color) {
color = methodColors[method.toLowerCase()] || 34;
formattedMethod = `\x1b[1;${color}m${formattedMethod}\x1b[0m`;
}
let color;
if (statusCode && settings.color) {
color = 32;
if (statusCode >= 500) {
color = 31;
}
else if (statusCode >= 400) {
color = 33;
}
else if (statusCode >= 300) {
color = 36;
}

return formattedMethod;
}

_formatStatusCode (statusCode) {

let color;
if (statusCode && this.settings.color) {
color = 32;
if (statusCode >= 500) {
color = 31;
} else if (statusCode >= 400) {
color = 33;
} else if (statusCode >= 300) {
color = 36;
}

return `\x1b[${color}m${statusCode}\x1b[0m`;
}
return `\x1b[${color}m${statusCode}\x1b[0m`;
}

return statusCode;
},

return statusCode;
}
formatResponse(event, tags, settings) {

_formatResponse (event) {
const query = event.query ? JSON.stringify(event.query) : '';
const method = internals.utility.formatMethod(event.method, settings);
const statusCode = internals.utility.formatStatusCode(event.statusCode, settings) || '';

const query = event.query ? JSON.stringify(event.query) : '';
const method = this._formatMethod(event.method);
const statusCode = this._formatStatusCode(event.statusCode) || '';
// event, timestamp, id, instance, labels, method, path, query, responseTime,
// statusCode, pid, httpVersion, source, remoteAddress, userAgent, referer, log
// method, pid, error
const output = `${event.instance}: ${method} ${event.path} ${query} ${statusCode} (${event.responseTime}ms)`;

// event, timestamp, id, instance, labels, method, path, query, responseTime,
// statusCode, pid, httpVersion, source, remoteAddress, userAgent, referer, log
// method, pid, error
const output = `${event.instance}: ${method} ${event.path} ${query} ${statusCode} (${event.responseTime}ms)`;
const response = {
timestamp: event.timestamp,
tags,
data: output
};

const response = {
timestamp: event.timestamp,
data: output
};
return internals.utility.formatOutput(response, settings);
},

return this._formatOutput(response);
}
formatOps(event, tags, settings) {

_formatOps (event) {
const memory = Math.round(event.proc.mem.rss / (1024 * 1024));
const output = `memory: ${memory}Mb, uptime (seconds): ${event.proc.uptime}, load: [${event.os.load}]`;

const memory = Math.round(event.proc.mem.rss / (1024 * 1024));
const output = `memory: ${memory}Mb, uptime (seconds): ${event.proc.uptime}, load: ${event.os.load}`
const ops = {
timestamp: event.timestamp,
tags,
data: output
};

const ops = {
timestamp: event.timestamp,
data: output
};
return internals.utility.formatOutput(ops, settings);
},

return this._formatOutput(ops);
}
formatError(event, tags, settings) {

_formatError (event) {
const output = `message: ${event.error.message} stack: ${event.error.stack}`;

const output = `message: ${event.error.message} stack: ${data.error.stack}`;
const error = {
timestamp: event.timestamp,
tags,
data: output
};

const error = {
timestamp: event.timestamp,
data: output
};
return internals.utility.formatOutput(error, settings);
},

return this._formatOutput(error);
}
formatDefault(event, tags, settings) {

_formatDefault (event) {
const data = typeof event.data === 'object' ? SafeStringify(event.data) : event.data;
const output = `data: ${data}`;

const data = typeof event.data === 'object' ? SafeStringify(event.data) : event.data;
const output = `data: ${data}`;
const defaults = {
timestamp: event.timestamp,
tags,
data: output
};

return internals.utility.formatOutput(defaults, settings);
}
};

const defaults = {
timestamp: event.timestamp || Moment().unix(),
data: output
};
class GoodConsole extends Stream.Transform {
constructor(config) {

return this._formatOutput(defaults);
}
super({ objectMode: true });

config = config || {};
this._settings = Hoek.applyToDefaults(internals.defaults, config);
}

_transform(data, enc, next) {

const eventName = data.event;
let tags = [];

if (Array.isArray(data.tags)) {
tags = data.tags.concat([]);
}
else if (data.tags) {
tags = [data.tags];
}

tags.unshift(eventName);

if (eventName === 'error') {
return next(null, internals.utility.formatError(data, tags, this._settings));
}

if (eventName === 'ops') {
return next(null, internals.utility.formatOps(data, tags, this._settings));
}

if (eventName === 'response') {
return next(null, internals.utility.formatResponse(data, tags, this._settings));
}

if (!data.data) {
data.data = '(none)';
}

return next(null, internals.utility.formatDefault(data, tags, this._settings));
}
}

module.exports = GoodConsole;

20 changes: 7 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,20 @@
"description": "Console broadcasting for Good process monitor",
"main": "lib/index.js",
"scripts": {
"test": "lab -t 100 -vLa code",
"test-cov-html": "lab -r html -o coverage.html -La code"
"test": "lab -t 100 -vLa code"
},
"dependencies": {
"good-squeeze": "2.x.x",
"hoek": "2.x.x",
"hoek": "3.x.x",
"joi": "8.0.x",
"json-stringify-safe": "5.0.x",
"moment": "2.11.x",
"through2": "0.6.x"
},
"peerDependencies": {
"good": ">= 6.x.x"
"moment": "2.12.x"
},
"devDependencies": {
"code": "1.x.x",
"lab": "6.x.x",
"stand-in": "3.0.x"
"code": "2.x.x",
"lab": "10.x.x"
},
"engines": {
"node": ">=0.10.x"
"node": ">=4.x.x"
},
"license": "BSD-3-Clause"
}
Loading

0 comments on commit d7e3e52

Please sign in to comment.