Skip to content

Commit

Permalink
Merge pull request #4 from appscot/debug_colors
Browse files Browse the repository at this point in the history
v0.4.0
  • Loading branch information
dmarcelino committed Mar 11, 2015
2 parents 542c33b + 652b4c4 commit 44e87e5
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 63 deletions.
44 changes: 22 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A thin wrapper for visionmedia/debug logger, adding levels and colored output.

## Overview
[visionmedia/debug](https://github.com/visionmedia/debug) is a ubitiquous logging library with 1000+ dependants. Given how widespread it is and the convenience of namespaces it is a great logger for library modules.
`debug-logger` is a convenience wrapper around `debug` that adds level based coloured output. Each instance of `debug-logger` will lazily instantiate 3 instances of `debug`, one for general purpose logging using `namespace`, another for debug (`namespace:debug`) and another for trace (`namespace:trace`). All this in configurable fashion. `debug-logger` has no dependencies besides `debug`.
`debug-logger` is a convenience wrapper around `debug` that adds level based coloured output. Each instance of `debug-logger` will lazily instantiate several instances of `debug` such as `namespace:info`, `namespace:warn`, `namespace:error`, etc. All these are configurable. `debug-logger` has no dependencies besides `debug`.

At AppsCot we use `debug-logger` in [waterline-orientdb](https://github.com/appscot/waterline-orientdb).

Expand All @@ -20,7 +20,9 @@ npm install debug-logger -S
```javascript
var log = require('debug-logger')('myapp');

log.trace("I'm a trace output");
log.debug("I'm a debug output");
log.log("I'm a log output");
log.info("I'm an info output");
log.warn("I'm a warn output");
log.error("I'm an error output");
Expand All @@ -46,8 +48,9 @@ log.info("let's inspect 'obj'", obj);

### Original `debug` instances and enabled property
```javascript
log.info.logger()("the default instance of debug, using 'myapp' namespace");
log.debug.logger()("the debug instance of debug, using 'myapp:debug' namespace");
var debug = debugLogger.debug('myapp:visionmedia');
debug('Nothing tastes better than the original!');

if (log.debug.enabled()) {
// This only runs if environment variable DEBUG includes "myapp:debug" namespace
Expand All @@ -74,19 +77,18 @@ log.info('By enabling colors we get this nice colored example:', {

### Customize available log levels
```javascript
debugLogger.levels.error.color = debugLogger.getForeColor('magenta');
debugLogger.levels.debug.color = debugLogger.getBackColor('cyan') + debugLogger.getForeColor('white');
debugLogger.levels.error.color = debugLogger.colors.magenta;
debugLogger.levels.error.prefix = 'ERROR ';

var customColorLog = debugLogger('myapp');
customColorLog.error("I'm a 'magenta' error output");
customColorLog.debug("I'm a 'cyan'/'white' debug output");
```
![customize log](https://raw.githubusercontent.com/wiki/appscot/debug-logger/customize_log.png)

### Add log levels
```javascript
debugLogger.levels.silly = {
color : debugLogger.getForeColor('magenta'),
color : debugLogger.colors.magenta,
prefix : 'SILLY ',
namespaceSuffix : ':silly'
};
Expand All @@ -96,13 +98,20 @@ sillyLog.silly("I'm a silly output");
```
![add log levels](https://raw.githubusercontent.com/wiki/appscot/debug-logger/silly.png)

### Filter log level (instead of namespace)
### Multiple arguments / util.format style
```javascript
log.log("Multiple", "arguments", "including", "objects:", { obj: 'obj'}, "makes life easier");
log.warn("util.format style string: %s, number: %d and json: %j.", "foo", 13, { obj: 'json'});
```
![multiple arguments](https://raw.githubusercontent.com/wiki/appscot/debug-logger/arguments.png)

### Filter by log level (instead of namespace)
```sh
export DEBUG_LEVEL=info
```
Only info level and above logs will be outputted.

More examples in the [examples folder](https://github.com/appscot/debug-logger/blob/master/examples/index.js).
More examples in the [examples folder](https://github.com/appscot/debug-logger/blob/master/examples).

## Reference

Expand All @@ -116,10 +125,10 @@ Assuming log is an instance of debug-logger (`var log = require('debug-logger')(
#### `log.info([data][, ...])`
#### `log.warn([data][, ...])`
#### `log.error([data][, ...])`
Prints the data prepended by log level. If the terminal supports colors, the level will be one of: blue, green, yellow, red. If an Error is provided, the toString() and call stack will be outputted. If an Object is provided the toString() and util.inspect() will be outputted. Example:
Prints the data prepended by log level. If the terminal supports colors, each level will have a specific color. If an Error is provided, the toString() and call stack will be outputted. If an Object is provided the toString() and util.inspect() will be outputted. Example:
```
myapp:debug DEBUG I'm a debug output +0ms
myapp INFO I'm an info output +1ms
myapp:debug I'm a debug output +0ms
myapp:info I'm an info output +1ms
```
This function can take multiple arguments in a printf()-like way, if formatting elements are not found in the first string then util.inspect is used on each argument.

Expand All @@ -131,17 +140,8 @@ Boolean indicating if `level`'s logger is enabled.

### Module

#### `.getForeColor(color)`
Returns an ANSI foreground color code string. `color` is one of `black, red, green, yellow, blue, magenta, cyan, white`
Example:
``` javascript
debugLogger.getForeColor('cyan')
// returns '\x1b[36m'
```

#### `.getBackColor(color)`
Returns an ANSI background color code string.

#### `.config(obj)`
Configures debug-logger. Returns `debug-logger` to allow chaining operations.

#### `.debug`
Returns visionmedia/debug module.
83 changes: 55 additions & 28 deletions debug-logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ var util = require('util'),
vmDebug = require('debug'),
streamSpy = require('./stream-spy');


exports = module.exports = debugLogger;
exports.getForeColor = getForeColor;
exports.getBackColor = getBackColor;
exports.debug = vmDebug;

exports.config = function config(options){
Expand All @@ -18,6 +15,9 @@ exports.config = function config(options){
if(options.inspectOptions){
exports.inspectOptions = options.inspectOptions;
}
if(options.levels){
merge(exports.levels, options.levels);
}
return debugLogger;
};

Expand All @@ -37,35 +37,39 @@ exports.colorReset = '\x1b[0m';

exports.levels = {
trace : {
color : getForeColor('cyan'),
prefix : 'TRACE ',
color : exports.colors.cyan,
prefix : '',
namespaceSuffix : ':trace',
level : 0
},
debug : {
color : getForeColor('blue'),
prefix : 'DEBUG ',
color : exports.colors.blue,
prefix : '',
namespaceSuffix : ':debug',
level : 1
},
log : {
color : '',
prefix : ' LOG ',
prefix : ' ',
namespaceSuffix : ':log',
level : 2
},
info : {
color : getForeColor('green'),
prefix : ' INFO ',
color : exports.colors.green,
prefix : ' ',
namespaceSuffix : ':info',
level : 3
},
warn : {
color : getForeColor('yellow'),
prefix : ' WARN ',
color : exports.colors.yellow,
prefix : ' ',
namespaceSuffix : ':warn',
level : 4
},
error : {
color : getForeColor('red'),
prefix : ' ERROR ',
color : exports.colors.red,
prefix : '',
namespaceSuffix : ':error',
level : 5
}
};
Expand All @@ -84,6 +88,20 @@ function ensureNewline(){
return debugLogger;
}

function merge(object, source){
Object.keys(source).forEach(function(key){
var val = source[key];

if(!object[key] || !isObject(val)){
object[key] = val;
return;
}
Object.keys(val).forEach(function(idx){
object[key][idx] = val[idx];
});
});
}

function getLogLevel(namespace) {
if(!process.env.DEBUG_LEVEL) {
return 0;
Expand Down Expand Up @@ -131,6 +149,10 @@ function isString(str){
return typeof str === 'string' || str instanceof String;
}

function isObject(obj){
return typeof obj === 'object' || obj instanceof Object;
}

function hasFormattingElements(str){
if(!str) { return false; }
var res = false;
Expand All @@ -143,7 +165,7 @@ function hasFormattingElements(str){
}

function getErrorMessage(e) {
var errorStrings = [' ' + e];
var errorStrings = ['' + e];

if (typeof e === 'undefined') {
return errorStrings;
Expand All @@ -155,21 +177,21 @@ function getErrorMessage(e) {
return errorStrings;
}
if (e instanceof Error) {
errorStrings[0] = ' ' + e.toString();
errorStrings[0] = e.toString();
if (e.stack) {
errorStrings[1] = 'Stack trace';
errorStrings[2] = e.stack;
}
return errorStrings;
}
if (typeof e === 'object' || e instanceof Object) {
if (isObject(e)) {
var inspection = util.inspect(e, exports.inspectOptions);
if(inspection.length < 55){
errorStrings[0] = ' ' + inspection;
errorStrings[0] = inspection;
return errorStrings;
}
if (typeof e.toString !== 'undefined') {
errorStrings[0] = ' ' + e.toString();
errorStrings[0] = e.toString();
}
errorStrings[1] = 'Inspected object';
errorStrings[2] = inspection;
Expand All @@ -179,17 +201,22 @@ function getErrorMessage(e) {
}

function getForeColor(color){
return '\x1b[' + (30 + exports.colors[color]) + 'm';
}

function getBackColor(color){
return '\x1b[' + (40 + exports.colors[color]) + 'm';
if(!isNaN(color)){
return '\x1b[3' + color + 'm';
}
else if(exports.colors[color]){
return '\x1b[3' + exports.colors[color] + 'm';
}
return color;
}

var debugInstances = {};
function getDebugInstance(namespace){
function getDebugInstance(namespace, color){
if(!debugInstances[namespace]){
debugInstances[namespace] = vmDebug(namespace);
if(!isNaN(color)){
debugInstances[namespace].color = color;
}
}
return debugInstances[namespace];
}
Expand All @@ -205,10 +232,10 @@ function debugLogger(namespace) {
Object.keys(levels).forEach(function(levelName) {
var loggerNamespaceSuffix = levels[levelName].namespaceSuffix ? levels[levelName].namespaceSuffix : 'default';
if(!debugLoggers[loggerNamespaceSuffix]){
debugLoggers[loggerNamespaceSuffix] = getDebugInstance.bind(this, namespace + loggerNamespaceSuffix);
debugLoggers[loggerNamespaceSuffix] = getDebugInstance.bind(this, namespace + loggerNamespaceSuffix, levels[levelName].color);
}
var levelLogger = debugLoggers[loggerNamespaceSuffix];
var color = vmDebug.useColors ? levels[levelName].color : '';
var color = vmDebug.useColors ? getForeColor(levels[levelName].color) : '';
var reset = vmDebug.useColors ? exports.colorReset : '';
var inspectionHighlight = vmDebug.useColors ? exports.styles.underline : '';

Expand All @@ -234,7 +261,7 @@ function debugLogger(namespace) {
var n = 1;
for(i=0; i<errorStrings.length; i++){
param = errorStrings[i];
message += param[0];
message += i === 0 ? param[0] : ' ' + param[0];
if (param.length > 1) {
var highlightStack = param[1].indexOf('Stack') >= 0 ? color : '';
inspections += '\n' +
Expand Down
22 changes: 10 additions & 12 deletions examples/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var log = require('..')('myapp');

// The below only shows up if environment variable DEBUG includes "myapp" namespace
// The below only shows up if environment variable DEBUG includes "myapp:*" namespace
log.trace("I'm a trace output");
log.debug("I'm a debug output");
log.log("I'm a log output");
Expand All @@ -12,7 +12,7 @@ log.error("I'm an error output");
console.log();
var debugLogger = require('..');
if (log.debug.enabled()) {
// This only runs if environment variable DEBUG includes "myapp:debug" namespace
// This only runs if environment variable DEBUG includes "myapp:debug" or "myapp:*" namespace
log.debug("Debug is enabled, let's inspect 'debugLogger.levels':", debugLogger.levels);
} else {
console.log("Debug is disabled, please add 'myapp:debug' namespace to DEBUG environment variable");
Expand All @@ -37,18 +37,16 @@ log.warn("util.format style string: %s, number: %d and json: %j.", "foo", 13, {


console.log();
log.info.logger()("the default instance of debug, using 'myapp' namespace");
log.debug.logger()("the debug instance of debug, using 'myapp:debug' namespace");
var debug = debugLogger.debug('myapp:visionmedia');
debug('Nothing tastes better than the original!');


console.log();
debugLogger.levels.error.color = debugLogger.getForeColor('magenta');
debugLogger.levels.debug.color = debugLogger.getBackColor('cyan') + debugLogger.getForeColor('white');
debugLogger.levels.error.color = debugLogger.colors.magenta;
debugLogger.levels.error.prefix = 'ERROR ';
var customColorLog = debugLogger('myapp');
customColorLog.error("I'm a 'magenta' error output");
customColorLog.debug("I'm a 'cyan'/'white' debug output");


console.log();
Expand All @@ -66,8 +64,8 @@ log.info('By enabling colors we get this nice colored example:', {

console.log();
debugLogger.levels.silly = {
color : debugLogger.getForeColor('magenta'),
prefix : 'SILLY ',
color : debugLogger.colors.magenta,
prefix : 'SILLY ',
namespaceSuffix : ':silly',
level : 0
};
Expand All @@ -87,10 +85,10 @@ alwaysPrintAtStartOfLineLog.warn('from the start');


if (!log.error.enabled()) {
// This only runs if environment variable DEBUG includes "myapp" namespace
console.log("You probably haven't seen much because the default logger is disabled");
console.log("Please add 'myapp' namespace to DEBUG environment variable and try again");
console.log("e.g.: export DEBUG=$DEBUG,myapp");
// This only runs if environment variable DEBUG includes "myapp:*" namespace
console.log("\nYou probably haven't seen much because some loggers are disabled");
console.log("Please add 'myapp:*' namespace to DEBUG environment variable and try again");
console.log("e.g.: export DEBUG=$DEBUG,myapp:*");
} else if(log.log.enabled()) {
console.log("\nNow set DEBUG_LEVEL environment variable to warn and run this example again");
console.log("e.g.: export DEBUG_LEVEL=warn");
Expand Down
Loading

0 comments on commit 44e87e5

Please sign in to comment.