├── README.md ├── main.js ├── package.json └── test.js /README.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | 3 | This is a considerable departure from the traditional logger. 4 | 5 | This logger is meant for use in third party modules and packages. It's so that modules can have a very simple way to offer optional visibility in to the modules inner workings. 6 | 7 | To this end, it does not have log levels like *info*, *warn*, etc. It simply allows the creation of a logger for your module (with a name) and offer a single function to take messages and a context for those messages. 8 | 9 | This module is both an implementation and a light specification. Loggers can be quite opinionated and the creators of modules are unlikely to solidify around a single implementation of anything. 10 | 11 | ## Spec 12 | 13 | A logging library should be a single function that returns logger functions. 14 | 15 | ```javascript 16 | var logging = require('logging') 17 | , log = logging('mymodulename') 18 | ; 19 | ``` 20 | 21 | When running an application in a production environment, logging is the one of the few things you need to be global that is outside of node core. 22 | 23 | Users of this specification should require **the user** to set the process.logging to the desired module. A library **must never** set this property automatically as it will override any other logger the user may want to use. 24 | 25 | **server.js** 26 | ```javascript 27 | process.logging = require('logging') 28 | var request = require('request') 29 | ``` 30 | 31 | Notice that this line comes **before** loading **any** other module. This is important, modules will likely check for process.logging as soon as they are required. 32 | 33 | Using the logger is quite easy within a module. 34 | 35 | ```javascript 36 | if (process.logging) var log = process.logging('mymodule') 37 | else var log = function () {} 38 | 39 | ... 40 | module.exports = fancy (options) { 41 | log('new fancy %method for %url', options) 42 | } 43 | ... 44 | fancy({method:'GET', url:'http://www.google.com'}) 45 | ``` 46 | 47 | The final piece of this spec is visible in the last example. 48 | 49 | Log functions take two arguments, a message and a context. 50 | 51 | Named string interpolation from the context **should** be supported. This prevents many errors related to using the + operator in building the message string. 52 | 53 | ## logging API 54 | 55 | The rest of this documentation covers features which should not be considered part of the specification. 56 | 57 | Enabling stdout or stderr printing of logs. 58 | 59 | ``` 60 | require('logging').stdout() 61 | ``` 62 | 63 | ``` 64 | require('logging').stderr() 65 | ``` 66 | 67 | All will print `[mymodule] new fancy GET for http://www.google.com`. 68 | 69 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | var events = require('events') 2 | , util = require('util') 3 | , global = new events.EventEmitter() 4 | ; 5 | 6 | function formatter (msg, ctx) { 7 | while (msg.indexOf('%') !== -1) { 8 | var start = msg.indexOf('%') 9 | , end = msg.indexOf(' ', start) 10 | ; 11 | if (end === -1) end = msg.length 12 | msg = msg.slice(0, start) + ctx[msg.slice(start+1, end)] + msg.slice(end) 13 | } 14 | return msg 15 | } 16 | global.formatter = formatter 17 | 18 | function Logger (name) { 19 | var self = this 20 | self.name = name 21 | self.on('log', function (msg, ctx) { 22 | if (self.listeners('msg').length) { 23 | msg = (self.formatter || global.formatter) (msg, ctx) 24 | self.emit('msg', msg, ctx) 25 | } 26 | }) 27 | } 28 | util.inherits(Logger, events.EventEmitter) 29 | 30 | module.exports = function (name) { 31 | var logger = new Logger(name) 32 | function log (msg, ctx) { 33 | if (!msg) throw new Error('msg is a required argument.') 34 | if (!ctx) ctx = {} 35 | logger.emit('log', msg, ctx) 36 | } 37 | log.error = function (e) { 38 | logger.emit('error', e) 39 | } 40 | logger.log = log 41 | log.logger = logger 42 | global.emit('logger', logger) 43 | return log 44 | } 45 | 46 | module.exports.stderr = function () { 47 | global.on('logger', function (logger) { 48 | logger.on('msg', function (msg, ctx) { 49 | console.error('['+logger.name+'] '+msg) 50 | }) 51 | }) 52 | } 53 | module.exports.stdout = function () { 54 | global.on('logger', function (logger) { 55 | logger.on('msg', function (msg, ctx) { 56 | console.log('['+logger.name+'] '+msg) 57 | }) 58 | }) 59 | } 60 | module.exports.formatter = function (f) { 61 | if (f) global.formatter = f 62 | return global.formatter 63 | } 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Mikeal Rogers ", 3 | "name": "logging", 4 | "description": "Simple and extensible logging.", 5 | "version": "0.0.0", 6 | "repository": "git://github.com/mikeal/logref", 7 | "scripts": {"test":"node test.js"}, 8 | "main": "main.js", 9 | "dependencies": {}, 10 | "devDependencies": {} 11 | } 12 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var logging = require('./main') 2 | , assert = require('assert') 3 | , f = logging.formatter() 4 | ; 5 | 6 | assert.equal(f('%start with', {start:'starts'}), 'starts with') 7 | assert.equal(f('in %the middle', {the:'the'}), 'in the middle') 8 | assert.equal(f('at %end', {end:'end'}), 'at end') 9 | assert.equal(f('%has %many %reps', {has:'has',many:'many',reps:'reps'}), 'has many reps') 10 | 11 | 12 | process.logging = logging 13 | logging.stdout() 14 | 15 | process.stdout.write = function (chunk) { 16 | assert.equal(chunk.toString(), '[test] a test line\n') 17 | } 18 | var log = logging('test') 19 | log('a test line') --------------------------------------------------------------------------------