├── .gitignore ├── README.md ├── debug-logger.js ├── examples ├── console.parity.js ├── file.js ├── index.js ├── legacy_0.3.X.js └── stdout_stderr.js ├── package.json └── stream-spy.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm version](https://badge.fury.io/js/debug-logger.svg)](http://badge.fury.io/js/debug-logger) 2 | 3 | debug-logger 4 | ============ 5 | 6 | A thin wrapper for visionmedia/debug logger, adding levels and colored output. 7 | 8 | ## Overview 9 | [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. 10 | `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`. 11 | 12 | `debug-logger` uses the same syntax as [node.js console](https://nodejs.org/api/console.html) so you can use it as drop in replacement. 13 | Check and run [examples/console.parity.js](https://github.com/appscot/debug-logger/blob/master/examples/console.parity.js) for more details. 14 | 15 | At AppsCot we use `debug-logger` in [sails-orientdb](https://github.com/appscot/sails-orientdb). 16 | 17 | ## Instalation 18 | ```javascript 19 | npm install debug-logger -S 20 | ``` 21 | 22 | ## Usage 23 | ```javascript 24 | var log = require('debug-logger')('myapp'); 25 | 26 | log.trace("I'm a trace output"); 27 | log.debug("I'm a debug output"); 28 | log.log("I'm a log output"); 29 | log.info("I'm an info output"); 30 | log.warn("I'm a warn output"); 31 | log.error("I'm an error output"); 32 | ``` 33 | ![screenshot](https://raw.githubusercontent.com/wiki/appscot/debug-logger/ScreenShot.png) 34 | 35 | ### Inspect error/object 36 | ```javascript 37 | var err = new Error('error message'); 38 | err.stack = 'the stack\nline2\nline3'; 39 | 40 | log.error('Something failed:', err); 41 | 42 | var obj = { 43 | anumber : 1234, 44 | astring : 'str', 45 | adate : new Date(), 46 | aboolean : true 47 | }; 48 | log.info("let's inspect 'obj'", obj); 49 | ``` 50 | ![inspect error/object](https://raw.githubusercontent.com/wiki/appscot/debug-logger/error_object.png) 51 | 52 | ### Original `debug` instances and enabled property 53 | ```javascript 54 | log.debug.logger()("the debug instance of debug, using 'myapp:debug' namespace"); 55 | var debug = debugLogger.debug('myapp:visionmedia'); 56 | debug('Nothing tastes better than the original!'); 57 | 58 | if (log.debug.enabled()) { 59 | // This only runs if environment variable DEBUG includes "myapp:debug" namespace 60 | log.debug("Debug is enabled"); 61 | } 62 | ``` 63 | ![enabled](https://raw.githubusercontent.com/wiki/appscot/debug-logger/enabled.png) 64 | 65 | ### util.inspect options 66 | Full `util.inspect` options available at [nodejs.org](http://nodejs.org/api/util.html#util_util_inspect_object_options). 67 | ```javascript 68 | var debugLogger = require('debug-logger'); 69 | debugLogger.inspectOptions = { 70 | colors : true 71 | }; 72 | log.info('By enabling colors we get this nice colored example:', { 73 | anumber : 1234, 74 | astring : 'str', 75 | adate : new Date(), 76 | aboolean : true 77 | }); 78 | ``` 79 | ![inspect](https://raw.githubusercontent.com/wiki/appscot/debug-logger/inspect.png) 80 | 81 | ### Customize available log levels 82 | ```javascript 83 | debugLogger.levels.error.color = debugLogger.colors.magenta; 84 | debugLogger.levels.error.prefix = 'ERROR '; 85 | 86 | var customColorLog = debugLogger('myapp'); 87 | customColorLog.error("I'm a 'magenta' error output"); 88 | ``` 89 | ![customize log](https://raw.githubusercontent.com/wiki/appscot/debug-logger/customize_log.png) 90 | 91 | ### Add log levels 92 | ```javascript 93 | debugLogger.levels.silly = { 94 | color : debugLogger.colors.magenta, 95 | prefix : 'SILLY ', 96 | namespaceSuffix : ':silly' 97 | }; 98 | 99 | var sillyLog = debugLogger('myapp'); 100 | sillyLog.silly("I'm a silly output"); 101 | ``` 102 | ![add log levels](https://raw.githubusercontent.com/wiki/appscot/debug-logger/silly.png) 103 | 104 | ### Multiple arguments / util.format style 105 | ```javascript 106 | log.log("Multiple", "arguments", "including", "objects:", { obj: 'obj'}, "makes life easier"); 107 | log.warn("util.format style string: %s, number: %d and json: %j.", "foo", 13, { obj: 'json'}); 108 | ``` 109 | ![multiple arguments](https://raw.githubusercontent.com/wiki/appscot/debug-logger/arguments.png) 110 | 111 | ### Measure code execution time 112 | ```javascript 113 | log.time('100-elements'); 114 | for (var i = 0; i < 100; i++) { 115 | ; 116 | } 117 | log.timeEnd('100-elements'); 118 | 119 | log.time('setTimeout'); 120 | setTimeout(function(){ 121 | var diff = log.timeEnd('setTimeout', 'debug'); 122 | log.trace('log.timeEnd returns diff so it can be reused:', diff); 123 | }, 262); 124 | ``` 125 | ![code time](https://raw.githubusercontent.com/wiki/appscot/debug-logger/time.png) 126 | 127 | ### Inspect object 128 | ```javascript 129 | log.dir({ foo: { bar: 1 } }); 130 | log.dir({ foo: { bar: 1 } }, { depth: 0 }, 'warn'); 131 | ``` 132 | ![dir inspect](https://raw.githubusercontent.com/wiki/appscot/debug-logger/dir.png) 133 | 134 | ### Assert condition 135 | ```javascript 136 | log.assert(1 == 0); 137 | 138 | // More elaborate example 139 | var log = require('..').config({ 140 | levels: { 141 | fatal: { 142 | color : 5, //magenta 143 | prefix : '', 144 | namespaceSuffix : ':fatal', 145 | level : 6 146 | } 147 | } 148 | })('myapp'); 149 | log.assert(1 == 0, 'testing %s %d', 'log.assert', 666, 'fatal'); 150 | ``` 151 | ![assert](https://raw.githubusercontent.com/wiki/appscot/debug-logger/assert.png) 152 | 153 | ### stderr vs stdout 154 | By default trace, debug, log and info output to stdout while warn and error output to stderr. 155 | This is configurable, [example](https://github.com/appscot/debug-logger/blob/master/examples/stdout_stderr.js): 156 | ```javascript 157 | var log = require('debug')('myapp'); 158 | log.trace("goes to stdout!"); 159 | log.debug("goes to stdout!"); 160 | log.log("goes to stdout!"); 161 | log.info("goes to stdout!"); 162 | log.warn("goes to stderr"); 163 | log.error("goes to stderr"); 164 | 165 | // outputting only to stdout 166 | var stdout = require('debug').config({ levels: { warn: { fd: 1 }, error: { fd: 1 } } })('stdoutapp'); 167 | stdout.warn("goes to stdout!"); 168 | stdout.error("goes to stdout!"); 169 | ``` 170 | 171 | ### Filter by log level (instead of namespace) 172 | ```sh 173 | export DEBUG_LEVEL=info 174 | ``` 175 | Only info level and above logs will be outputted. 176 | 177 | More examples in the [examples folder](https://github.com/appscot/debug-logger/blob/master/examples). 178 | 179 | ## Reference 180 | 181 | ### Instance Methods 182 | 183 | Assuming log is an instance of debug-logger (`var log = require('debug-logger')('myapp');`). 184 | 185 | #### `log.trace([data][, ...])` 186 | #### `log.debug([data][, ...])` 187 | #### `log.log([data][, ...])` 188 | #### `log.info([data][, ...])` 189 | #### `log.warn([data][, ...])` 190 | #### `log.error([data][, ...])` 191 | 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: 192 | ``` 193 | myapp:debug I'm a debug output +0ms 194 | myapp:info I'm an info output +1ms 195 | ``` 196 | 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. 197 | 198 | #### `log([message][, ...])` 199 | Outputs the message using the root/default `debug` instance, without the level suffix. Example: 200 | ``` 201 | myapp I'm a root/default debug instance output +0ms 202 | ``` 203 | 204 | #### `log[level].logger()` 205 | Returns the default `debug` instance used by `level`. 206 | 207 | #### `log[level].enabled()` 208 | Boolean indicating if `level`'s logger is enabled. 209 | 210 | #### `log.time(label)` 211 | Mark a time. 212 | 213 | #### `log.timeEnd(label[, level])` 214 | Finish timer, record output. `level` will determine the logger used to output the result (defaults to 'log'). 215 | Return duration in ms. 216 | 217 | #### `log.dir(obj[, options][, level])` 218 | Uses util.inspect on obj and prints resulting string to the appropriate logger. This function bypasses any custom inspect() function on obj. An optional [options object](https://nodejs.org/api/console.html#console_console_dir_obj_options) may be passed that alters certain aspects of the formatted string. 219 | `level` will determine the logger used to output the result (defaults to 'log'). 220 | 221 | #### `log.assert(value[, message][, ...][, level])` 222 | Similar to [console.assert()](https://nodejs.org/api/console.html#console_console_assert_value_message). 223 | Additionally it outputs the error using the appropriate logger set by `level` (defaults to 'error'). 224 | 225 | ### Module 226 | 227 | #### `.config(obj)` 228 | Configures debug-logger. Returns `debug-logger` to allow chaining operations. 229 | 230 | #### `.debug` 231 | Returns visionmedia/debug module. 232 | -------------------------------------------------------------------------------- /debug-logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'), 4 | vmDebug = require('debug'), 5 | streamSpy = require('./stream-spy'); 6 | 7 | exports = module.exports = debugLogger; 8 | exports.debug = vmDebug; 9 | var debugInstances = exports.debugInstances = {}; 10 | 11 | exports.config = function config(options){ 12 | options = options || {}; 13 | if(options.ensureNewline){ 14 | ensureNewline(); 15 | } 16 | if(options.inspectOptions){ 17 | exports.inspectOptions = options.inspectOptions; 18 | } 19 | if(options.levels){ 20 | merge(exports.levels, options.levels); 21 | } 22 | return debugLogger; 23 | }; 24 | 25 | exports.inspectOptions = {}; 26 | 27 | exports.colors = { 28 | black : 0, 29 | red : 1, 30 | green : 2, 31 | yellow : 3, 32 | blue : 4, 33 | magenta : 5, 34 | cyan : 6, 35 | white : 7 36 | }; 37 | exports.colorReset = '\x1b[0m'; 38 | 39 | exports.levels = { 40 | trace : { 41 | color : exports.colors.cyan, 42 | prefix : '', 43 | namespaceSuffix : ':trace', 44 | level : 0, 45 | fd : 1 // currently only 1 (stdout) is supported. stderr is debug's standard 46 | }, 47 | debug : { 48 | color : exports.colors.blue, 49 | prefix : '', 50 | namespaceSuffix : ':debug', 51 | level : 1, 52 | fd : 1 53 | }, 54 | log : { 55 | color : '', 56 | prefix : ' ', 57 | namespaceSuffix : ':log', 58 | level : 2, 59 | fd : 1 60 | }, 61 | info : { 62 | color : exports.colors.green, 63 | prefix : ' ', 64 | namespaceSuffix : ':info', 65 | level : 3, 66 | fd : 1 67 | }, 68 | warn : { 69 | color : exports.colors.yellow, 70 | prefix : ' ', 71 | namespaceSuffix : ':warn', 72 | level : 4 73 | }, 74 | error : { 75 | color : exports.colors.red, 76 | prefix : '', 77 | namespaceSuffix : ':error', 78 | level : 5 79 | } 80 | }; 81 | 82 | exports.styles = { 83 | underline : '\x1b[4m' 84 | }; 85 | 86 | 87 | function time(label){ 88 | this.timeLabels[label] = process.hrtime(); 89 | } 90 | 91 | function timeEnd(label, level){ 92 | level = level || 'log'; 93 | var diff = process.hrtime(this.timeLabels[label]); 94 | var diffMs = (diff[0] * 1e9 + diff[1]) / 1e6; 95 | this[level](label + ':', diffMs + 'ms'); 96 | return diffMs; 97 | } 98 | 99 | function dir(obj, options, level){ 100 | if(!level && this[options]){ 101 | level = options; 102 | options = undefined; 103 | } 104 | options = options || exports.inspectOptions; 105 | level = level || 'log'; 106 | this[level](util.inspect(obj, options)); 107 | } 108 | 109 | function assert(expression){ 110 | if (!expression) { 111 | var level = 'error'; 112 | var arr = Array.prototype.slice.call(arguments, 1); 113 | if(this[arr[arr.length-1]]){ 114 | level = arr[arr.length-1]; 115 | arr = arr.slice(0, -1); 116 | } 117 | var assrt = require('assert'); 118 | var err = new assrt.AssertionError({ 119 | message: util.format.apply(this, arr), 120 | actual: false, 121 | expected: true, 122 | operator: '==', 123 | stackStartFunction: assert 124 | }); 125 | this[level](err); 126 | throw err; 127 | } 128 | } 129 | 130 | 131 | var ensureNewlineEnabled = false; 132 | var fd = parseInt(process.env.DEBUG_FD, 10) || 2; 133 | function ensureNewline(){ 134 | if(fd !== 1 && fd !== 2){ return; } 135 | streamSpy.enable(); 136 | ensureNewlineEnabled = true; 137 | return debugLogger; 138 | } 139 | 140 | function merge(object, source){ 141 | Object.keys(source).forEach(function(key){ 142 | var val = source[key]; 143 | 144 | if(!object[key] || !isObject(val)){ 145 | object[key] = val; 146 | return; 147 | } 148 | Object.keys(val).forEach(function(idx){ 149 | object[key][idx] = val[idx]; 150 | }); 151 | }); 152 | } 153 | 154 | function getLogLevel(namespace) { 155 | if(!process.env.DEBUG_LEVEL) { 156 | return 0; 157 | } 158 | var debugLevel = process.env.DEBUG_LEVEL.toLowerCase(); 159 | if(debugLevel.indexOf('*:') === 0){ 160 | return hasLogLevel(debugLevel.slice(2)) || 0; 161 | } 162 | var hasLevel = hasLogLevel(debugLevel); 163 | if(hasLevel !== null){ 164 | return hasLevel; 165 | } 166 | if(!namespace) { 167 | return 0; 168 | } 169 | //currently we will only process the first part of namespace 170 | var appNamespace = namespace.split(':')[0].toLowerCase(); 171 | 172 | var debugLevelParts = debugLevel.split(','); 173 | 174 | var i; 175 | for(i = 0; i < debugLevelParts.length; i++){ 176 | var parts = debugLevelParts[i].split(':'); 177 | if(appNamespace === parts[0]){ 178 | return hasLogLevel(parts[parts.length-1]) || 0; 179 | } 180 | } 181 | return 0; 182 | } 183 | 184 | function hasLogLevel(level) { 185 | if(!level) { 186 | return null; 187 | } 188 | if (!isNaN(level)){ 189 | return level; 190 | } 191 | else if(isString(level) && exports.levels[level]){ 192 | return exports.levels[level].level || 0; 193 | } 194 | return null; 195 | } 196 | 197 | function isString(str){ 198 | return typeof str === 'string' || str instanceof String; 199 | } 200 | 201 | function isObject(obj){ 202 | return typeof obj === 'object' || obj instanceof Object; 203 | } 204 | 205 | function hasFormattingElements(str){ 206 | if(!str) { return false; } 207 | var res = false; 208 | ['%s', '%d', '%j', '%o'].forEach(function(elem){ 209 | if(str.indexOf(elem) >= 0) { 210 | res = true; 211 | } 212 | }); 213 | return res; 214 | } 215 | 216 | function getErrorMessage(e) { 217 | var errorStrings = ['' + e]; 218 | 219 | if (typeof e === 'undefined') { 220 | return errorStrings; 221 | } 222 | if (e === null) { 223 | return errorStrings; 224 | } 225 | if (e instanceof Date) { 226 | return errorStrings; 227 | } 228 | if (e instanceof Error) { 229 | errorStrings[0] = e.toString(); 230 | if (e.stack) { 231 | errorStrings[1] = 'Stack trace'; 232 | errorStrings[2] = e.stack; 233 | } 234 | return errorStrings; 235 | } 236 | if (isObject(e)) { 237 | var inspection = util.inspect(e, exports.inspectOptions); 238 | if(inspection.length < 55){ 239 | errorStrings[0] = inspection; 240 | return errorStrings; 241 | } 242 | if (typeof e.toString !== 'undefined') { 243 | errorStrings[0] = e.toString(); 244 | } 245 | errorStrings[1] = 'Inspected object'; 246 | errorStrings[2] = inspection; 247 | } 248 | 249 | return errorStrings; 250 | } 251 | 252 | function getForeColor(color){ 253 | if(!isNaN(color)){ 254 | return '\x1b[3' + color + 'm'; 255 | } 256 | else if(exports.colors[color]){ 257 | return '\x1b[3' + exports.colors[color] + 'm'; 258 | } 259 | return color; 260 | } 261 | 262 | function disableColors(loggerLevel, disable){ 263 | if(disable){ 264 | loggerLevel.color = ''; 265 | loggerLevel.reset = ''; 266 | loggerLevel.inspectionHighlight = ''; 267 | } 268 | } 269 | 270 | function getDebugInstance(namespace, color, fd){ 271 | if(!debugInstances[namespace]){ 272 | debugInstances[namespace] = vmDebug(namespace); 273 | if(fd === 1 && isNaN(parseInt(process.env.DEBUG_FD))){ 274 | debugInstances[namespace].log = console.log.bind(console); 275 | } 276 | if(!isNaN(color)){ 277 | debugInstances[namespace].color = color; 278 | } 279 | } 280 | return debugInstances[namespace]; 281 | } 282 | 283 | 284 | function debugLogger(namespace) { 285 | var levels = exports.levels; 286 | var debugLoggers = { 'default': getDebugInstance.bind(this, namespace, '') }; 287 | 288 | var logger = function(){ 289 | debugLoggers['default']().apply(this, arguments); 290 | }; 291 | logger.logLevel = getLogLevel(namespace); 292 | 293 | logger.timeLabels = {}; 294 | logger.time = time; 295 | logger.timeEnd = timeEnd; 296 | logger.dir = dir; 297 | logger.assert = assert; 298 | 299 | Object.keys(levels).forEach(function(levelName) { 300 | var loggerNamespaceSuffix = levels[levelName].namespaceSuffix ? levels[levelName].namespaceSuffix : 'default'; 301 | if(!debugLoggers[loggerNamespaceSuffix]){ 302 | debugLoggers[loggerNamespaceSuffix] = getDebugInstance.bind(this, namespace + loggerNamespaceSuffix, levels[levelName].color, levels[levelName].fd); 303 | } 304 | var levelLogger = debugLoggers[loggerNamespaceSuffix]; 305 | 306 | var initialized = false; 307 | 308 | function logFn() { 309 | if (logger.logLevel > logger[levelName].level) { return; } 310 | 311 | var levelLog = levelLogger(); 312 | if(!levelLog.enabled) { return; } 313 | 314 | if(!initialized){ 315 | initialized = true; 316 | disableColors(logger[levelName], !levelLog.useColors); 317 | } 318 | 319 | if (isString(arguments[0]) && hasFormattingElements(arguments[0])){ 320 | arguments[0] = logger[levelName].color + levels[levelName].prefix + logger[levelName].reset + arguments[0]; 321 | return levelLog.apply(this, arguments); 322 | } 323 | 324 | var selfArguments = arguments; 325 | var errorStrings = Object.keys(selfArguments).map(function(key){ 326 | return getErrorMessage(selfArguments[key]); 327 | }); 328 | var message = ""; 329 | var inspections = ""; 330 | 331 | var i, param; 332 | var n = 1; 333 | for(i=0; i 1) { 337 | var highlightStack = param[1].indexOf('Stack') >= 0 ? logger[levelName].color : ''; 338 | inspections += '\n' + 339 | logger[levelName].inspectionHighlight + '___' + param[1] + ' #' + n++ + '___' + logger[levelName].reset +'\n' + 340 | highlightStack + param[2] + logger[levelName].reset; 341 | } 342 | }; 343 | 344 | levelLog(logger[levelName].color + levels[levelName].prefix + logger[levelName].reset + message + inspections); 345 | }; 346 | 347 | function logNewlineFn() { 348 | if (streamSpy.lastCharacter !== '\n') { 349 | vmDebug.log(''); 350 | } 351 | logFn.apply(logFn, arguments); 352 | }; 353 | 354 | logger[levelName] = ensureNewlineEnabled ? logNewlineFn : logFn; 355 | logger[levelName].level = levels[levelName].level; 356 | logger[levelName].logger = function(){ return levelLogger(); }; 357 | logger[levelName].enabled = function(){ return logger.logLevel <= logger[levelName].level && levelLogger().enabled; }; 358 | logger[levelName].color = getForeColor(levels[levelName].color); 359 | logger[levelName].reset = exports.colorReset; 360 | logger[levelName].inspectionHighlight = exports.styles.underline; 361 | }); 362 | 363 | return logger; 364 | } 365 | -------------------------------------------------------------------------------- /examples/console.parity.js: -------------------------------------------------------------------------------- 1 | // The below only shows up if environment variable DEBUG includes "myapp:*" namespace 2 | // e.g.: export DEBUG=$DEBUG,myapp:* 3 | var log = require('..')('myapp'); 4 | 5 | var count = 5; 6 | console.log('count: %d', count); 7 | log.log('count: %d', count); 8 | 9 | br(); 10 | count++; 11 | console.info('count:', count, '...'); 12 | log.info('count:', count, '...'); 13 | 14 | br(); 15 | count++; 16 | console.error('count: %d', count); 17 | log.error('count: %d', count); 18 | 19 | br(); 20 | console.warn('plain message'); 21 | log.warn('plain message'); 22 | 23 | br(); 24 | console.dir({ foo: { bar: 1 } }, { depth: 0 }); 25 | log.dir({ foo: { bar: 1 } }, { depth: 0 }); 26 | 27 | br(); 28 | console.time('100-elements'); 29 | log.time('100-elements'); 30 | for (var i = 0; i < 100; i++) { 31 | ; 32 | } 33 | console.timeEnd('100-elements'); 34 | log.timeEnd('100-elements'); 35 | 36 | br(); 37 | count++; 38 | // log.trace accepts similar input as console.log but it behaves more like log4j's TRACE as it prints a finer level of events 39 | console.trace('count: %d', count); 40 | log.trace('count: %d', count); 41 | 42 | br(); 43 | try{ 44 | console.assert(1 == 0, 'Wrong value'); 45 | } catch(err){} 46 | try{ 47 | log.assert(1 == 0, 'Wrong value'); 48 | } catch(err){} 49 | 50 | 51 | 52 | br(); 53 | function br(){ 54 | console.log(); 55 | } 56 | -------------------------------------------------------------------------------- /examples/file.js: -------------------------------------------------------------------------------- 1 | // Write to a file 2 | // e.g.: node examples/file.js 3>debug.log 3 | process.env.DEBUG_FD=3; 4 | 5 | var log = require('..').config({ 6 | levels: { 7 | fatal: { 8 | color : 5, //magenta 9 | prefix : '', 10 | namespaceSuffix : ':fatal', 11 | level : 6 12 | } 13 | } 14 | })('myapp'); 15 | 16 | log.info("I'm an info output"); 17 | 18 | 19 | br(); 20 | log.dir({ foo: { bar: 1 } }); 21 | log.dir({ foo: { bar: 1 } }, { depth: 0 }, 'warn'); 22 | 23 | 24 | br(); 25 | log.time('100-elements'); 26 | for (var i = 0; i < 100; i++) { 27 | ; 28 | } 29 | log.timeEnd('100-elements'); 30 | 31 | 32 | log.time('setTimeout'); 33 | setTimeout(function(){ 34 | br(); 35 | var diff = log.timeEnd('setTimeout', 'debug'); 36 | log.trace('log.timeEnd returns diff so it can be reused:', diff); 37 | 38 | br(); 39 | log.assert(1 == 0, 'testing %s %d', 'log.assert', 666, 'fatal'); 40 | 41 | }, 262); 42 | 43 | function br(){ 44 | require('..').debug.log(''); 45 | } 46 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | var log = require('..')('myapp'); 2 | 3 | // The below only shows up if environment variable DEBUG includes "myapp:*" namespace 4 | log.trace("I'm a trace output"); 5 | log.debug("I'm a debug output"); 6 | log.log("I'm a log output"); 7 | log.info("I'm an info output"); 8 | log.warn("I'm a warn output"); 9 | log.error("I'm an error output"); 10 | 11 | 12 | console.log(); 13 | var debugLogger = require('..'); 14 | if (log.debug.enabled()) { 15 | // This only runs if environment variable DEBUG includes "myapp:debug" or "myapp:*" namespace 16 | log.debug("Debug is enabled, let's inspect 'debugLogger.levels':", debugLogger.levels); 17 | } else { 18 | console.log("Debug is disabled, please add 'myapp:debug' namespace to DEBUG environment variable"); 19 | console.log("e.g.: export DEBUG=$DEBUG,myapp:debug"); 20 | } 21 | 22 | 23 | console.log(); 24 | var err = new Error('error message'); 25 | err.stack = 'the stack\nline2\nline3'; 26 | log.error('Something failed:', err); 27 | 28 | 29 | console.log(); 30 | log.warn("You can use log.(err) and the stack trace is printed on the level's color"); 31 | log.warn(err); 32 | 33 | 34 | console.log(); 35 | log.log("Multiple", "arguments", "including", "objects:", { obj: 'obj'}, "makes life easier"); 36 | log.warn("util.format style string: %s, number: %d and json: %j.", "foo", 13, { obj: 'json'}); 37 | 38 | 39 | console.log(); 40 | log('the root/default debug instance'); 41 | log.info.logger()("the info instance of debug, using 'myapp:info' namespace"); 42 | // debugLogger.debug references the debug module, e.g.: debugLogger.debug == require('debug') 43 | var debug = debugLogger.debug('myapp:visionmedia'); 44 | debug('nothing tastes better than the original!'); 45 | 46 | 47 | console.log(); 48 | debugLogger.levels.error.color = debugLogger.colors.magenta; 49 | debugLogger.levels.error.prefix = 'ERROR '; 50 | var customColorLog = debugLogger('myapp'); 51 | customColorLog.error("I'm a 'magenta' error output"); 52 | 53 | 54 | console.log(); 55 | debugLogger.inspectOptions = { 56 | colors : true 57 | }; 58 | // Check http://nodejs.org/api/util.html#util_util_inspect_object_options 59 | log.info('By enabling colors we get this nice colored example:', { 60 | anumber : 1234, 61 | astring : 'str', 62 | adate : new Date(), 63 | aboolean : true 64 | }); 65 | 66 | 67 | console.log(); 68 | debugLogger.levels.silly = { 69 | color : debugLogger.colors.magenta, 70 | prefix : 'SILLY ', 71 | namespaceSuffix : ':silly', 72 | level : 0 73 | }; 74 | var sillyLog = debugLogger('myapp'); 75 | sillyLog.info("Is silly logger enabled? " + sillyLog.silly.enabled()); 76 | if(sillyLog.silly.enabled()){ 77 | sillyLog.silly("I'm a silly output"); 78 | } else { 79 | console.log("Silly is disabled, please add 'myapp:silly' namespace to DEBUG environment variable"); 80 | console.log("e.g.: export DEBUG=$DEBUG,myapp:silly"); 81 | } 82 | 83 | 84 | console.log(); 85 | var alwaysPrintAtStartOfLineLog = debugLogger.config({ ensureNewline: true })('myapp'); 86 | process.stdout.write('Some text without a line break'); 87 | alwaysPrintAtStartOfLineLog.warn('from the start'); 88 | 89 | 90 | if (!log.error.enabled()) { 91 | // This only runs if environment variable DEBUG includes "myapp:*" namespace 92 | console.log("\nYou probably haven't seen much because some loggers are disabled"); 93 | console.log("Please add 'myapp:*' namespace to DEBUG environment variable and try again"); 94 | console.log("e.g.: export DEBUG=$DEBUG,myapp:*"); 95 | } else if(log.log.enabled()) { 96 | console.log("\nNow set DEBUG_LEVEL environment variable to warn and run this example again"); 97 | console.log("e.g.: export DEBUG_LEVEL=warn"); 98 | } 99 | console.log(); 100 | 101 | -------------------------------------------------------------------------------- /examples/legacy_0.3.X.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Make debug-logger behave like it did in v0.3.X 3 | */ 4 | var debugLogger = require('..').config({ 5 | levels : { 6 | trace : { 7 | prefix : 'TRACE ' 8 | }, 9 | debug : { 10 | prefix : 'DEBUG ' 11 | }, 12 | log : { 13 | prefix : ' LOG ', 14 | namespaceSuffix : null 15 | }, 16 | info : { 17 | prefix : ' INFO ', 18 | namespaceSuffix : null 19 | }, 20 | warn : { 21 | prefix : ' WARN ', 22 | namespaceSuffix : null 23 | }, 24 | error : { 25 | prefix : ' ERROR ', 26 | namespaceSuffix : null 27 | } 28 | } 29 | }); 30 | 31 | var log = debugLogger('myapp'); 32 | 33 | 34 | // The below only shows up if environment variable DEBUG includes "myapp" namespace 35 | log.trace("I'm a trace output"); 36 | log.debug("I'm a debug output"); 37 | log.log("I'm a log output"); 38 | log.info("I'm an info output"); 39 | log.warn("I'm a warn output"); 40 | log.error("I'm an error output"); 41 | 42 | 43 | console.log(); 44 | debugLogger.levels.debug.color = '\x1b[4' + debugLogger.colors.cyan + 'm' + '\x1b[3' + debugLogger.colors.white + 'm'; 45 | var customColorLog = debugLogger('myapp'); 46 | customColorLog.debug("I'm a 'cyan'/'white' debug output"); 47 | 48 | console.log(); 49 | -------------------------------------------------------------------------------- /examples/stdout_stderr.js: -------------------------------------------------------------------------------- 1 | var log = require('..')('myapp'); 2 | 3 | log.trace("goes to stdout!"); 4 | log.debug("goes to stdout!"); 5 | log.log("goes to stdout!"); 6 | log.info("goes to stdout!"); 7 | log.warn("goes to stderr"); 8 | log.error("goes to stderr"); 9 | 10 | 11 | var stdout = require('..').config({ levels: { warn: { fd: 1 }, error: { fd: 1 } } })('stdoutapp'); 12 | 13 | stdout.warn("goes to stdout!"); 14 | stdout.error("goes to stdout!"); 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "debug-logger", 3 | "version": "0.4.1", 4 | "description": "A wrapper for visionmedia/debug logger, adding levels and colored output", 5 | "main": "debug-logger.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git@github.com:appscot/debug-logger.git" 9 | }, 10 | "keywords": [ 11 | "debug", 12 | "logger", 13 | "levels", 14 | "colors", 15 | "console", 16 | "log", 17 | "info", 18 | "warn", 19 | "error" 20 | ], 21 | "author": { 22 | "name": "Dario Marcelino", 23 | "email": "dario@appscot.com" 24 | }, 25 | "license": "MIT", 26 | "dependencies": { 27 | "debug": "^2.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /stream-spy.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * Hooking into Node.js stdout 5 | * Based on: https://gist.github.com/pguillory/729616 by @pguillory 6 | * 7 | * @param {Object} callback 8 | */ 9 | function hook_stream(stream, callback) { 10 | var old_write = stream.write; 11 | 12 | stream.write = (function(write) { 13 | return function(string, encoding, fd) { 14 | write.apply(stream, arguments); 15 | callback(string, encoding, fd); 16 | }; 17 | })(stream.write); 18 | 19 | return function() { 20 | stream.write = old_write; 21 | }; 22 | }; 23 | 24 | 25 | module.exports.lastCharacter = '\n'; 26 | function getLastCharacter(string, encoding, fd){ 27 | module.exports.lastCharacter = string.slice(-1); 28 | } 29 | 30 | var unhook; 31 | var unhookStderr; 32 | module.exports.enable = function enable(){ 33 | if(!unhook){ 34 | unhook = hook_stream(process.stdout, getLastCharacter); 35 | } 36 | if(!unhookStderr){ 37 | unhookStderr = hook_stream(process.stderr, getLastCharacter); 38 | } 39 | }; 40 | 41 | module.exports.disable = function disable(){ 42 | if(unhook){ 43 | unhook(); 44 | unhook = undefined; 45 | } 46 | if(unhookStderr){ 47 | unhookStderr(); 48 | unhookStderr = undefined; 49 | } 50 | }; 51 | --------------------------------------------------------------------------------