Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeal committed Dec 14, 2011
0 parents commit 9d98643
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
68 changes: 68 additions & 0 deletions README.md
@@ -0,0 +1,68 @@
# Logging

This is a considerable departure from the traditional logger.

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.

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.

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.

## Spec

A logging library should be a single function that returns logger functions.

```javascript
var logging = require('logging')
, log = logging('mymodulename')
;
```

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.

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.

**server.js**
```javascript
process.logging = require('logging')
var request = require('request')
```

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.

Using the logger is quite easy within a module.

```javascript
if (process.logging) var log = process.logging('mymodule')
else var log = function () {}

...
module.exports = fancy (options) {
log('new fancy %method for %url', options)
}
...
fancy({method:'GET', url:'http://www.google.com'})
```

The final piece of this spec is visible in the last example.

Log functions take two arguments, a message and a context.

Named string interpolation from the context **should** be supported. This prevents many errors related to using the + operator in building the message string.

## logging API

The rest of this documentation covers features which should not be considered part of the specification.

Enabling stdout or stderr printing of logs.

```
require('logging').stdout()
```

```
require('logging').stderr()
```

All will print `[mymodule] new fancy GET for http://www.google.com`.

63 changes: 63 additions & 0 deletions main.js
@@ -0,0 +1,63 @@
var events = require('events')
, util = require('util')
, global = new events.EventEmitter()
;

function formatter (msg, ctx) {
while (msg.indexOf('%') !== -1) {
var start = msg.indexOf('%')
, end = msg.indexOf(' ', start)
;
if (end === -1) end = msg.length
msg = msg.slice(0, start) + ctx[msg.slice(start+1, end)] + msg.slice(end)
}
return msg
}
global.formatter = formatter

function Logger (name) {
var self = this
self.name = name
self.on('log', function (msg, ctx) {
if (self.listeners('msg').length) {
msg = (self.formatter || global.formatter) (msg, ctx)
self.emit('msg', msg, ctx)
}
})
}
util.inherits(Logger, events.EventEmitter)

module.exports = function (name) {
var logger = new Logger(name)
function log (msg, ctx) {
if (!msg) throw new Error('msg is a required argument.')
if (!ctx) ctx = {}
logger.emit('log', msg, ctx)
}
log.error = function (e) {
logger.emit('error', e)
}
logger.log = log
log.logger = logger
global.emit('logger', logger)
return log
}

module.exports.stderr = function () {
global.on('logger', function (logger) {
logger.on('msg', function (msg, ctx) {
console.error('['+logger.name+'] '+msg)
})
})
}
module.exports.stdout = function () {
global.on('logger', function (logger) {
logger.on('msg', function (msg, ctx) {
console.log('['+logger.name+'] '+msg)
})
})
}
module.exports.formatter = function (f) {
if (f) global.formatter = f
return global.formatter
}
13 changes: 13 additions & 0 deletions package.json
@@ -0,0 +1,13 @@
{
"author": "Mikeal Rogers <mikeal.rogers@gmail.com>",
"name": "logging",
"description": "Simple and extensible logging.",
"version": "0.0.0",
"repository": {
"url": ""
},
"scripts": {"test":"node test.js"},
"main": "main.js",
"dependencies": {},
"devDependencies": {}
}
19 changes: 19 additions & 0 deletions test.js
@@ -0,0 +1,19 @@
var logging = require('./main')
, assert = require('assert')
, f = logging.formatter()
;

assert.equal(f('%start with', {start:'starts'}), 'starts with')
assert.equal(f('in %the middle', {the:'the'}), 'in the middle')
assert.equal(f('at %end', {end:'end'}), 'at end')
assert.equal(f('%has %many %reps', {has:'has',many:'many',reps:'reps'}), 'has many reps')


process.logging = logging
logging.stdout()

process.stdout.write = function (chunk) {
assert.equal(chunk.toString(), '[test] a test line\n')
}
var log = logging('test')
log('a test line')

0 comments on commit 9d98643

Please sign in to comment.