Skip to content

Commit

Permalink
Merge pull request #1 from turbonetix/implementation
Browse files Browse the repository at this point in the history
READY: Implementation
  • Loading branch information
NathanGRomano committed Jun 28, 2014
2 parents 081e874 + 1c4c1b9 commit 252fd03
Show file tree
Hide file tree
Showing 5 changed files with 325 additions and 14 deletions.
86 changes: 83 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,91 @@
[![NPM version](https://badge.fury.io/js/socket.io-logger.svg)](http://badge.fury.io/js/socket.io-logger)
[![David DM](https://david-dm.org/turbonetix/socket.io-logger.png)](https://david-dm.org/turbonetix/socket.io-logger.png)

![Bus.IO](https://raw.github.com/turbonetix/bus.io/master/logo.png)
Simple logger middleware for [socket.io](https://github.com/Automattic/socket.io "socket.io").

WIP
`$ npm install socket.io-logger`

A socket.io-logger will log all of your `events`.
```javascript
var fs = require('fs');
var io = require('socket.io')(3000);
var options = {stream: fs.createWriteStream('/var/log/events.log',{flags:'a'}) };
var logger = require('socket.io-logger')(options);
io.use(logger);
```

# Features

* Data is flattened with [flat](https://www.npmjs.org/package/flat "flat").
* Customized formatting support.
* Plugable interface to use with your favorite logger packages.

# API

## Logger

```javascript
var Logger = require('socket.io-logger')();
```

### Logger#

```javascript
io.use(Logger());
```

By default the logger middleware will write to `stdout`.

### Logger#(options:Object)

```javascript
var options = {
stream: fs.createWriteStream('/var/log/events.log', {flags:'a'})
format: function (sock, args) { return { sock:sock.id, args: args}; }
};
io.use(Logger(options));
```

You can use anything as long as the `stream` has a `write` method.

```javascript
var options = {
stream: {
write: function (data) {
console.log(data);
}
}
};
io.use(Logger(options));
```

### Logger#stream (stream:Object)

The `stream` must have a `write` method.

```javascript
var stream = fs.createWriteStream('/var/log/events.log', {flags:'a'});
var logger = Logger();
logger.stream(stream);
io.use(logger);
```

### Logger#format (format:Function)

Set a customized function to manipulate the data that will be serialized.

```javascript
var format = function (sock, args) {
return {
sock: sock.id,
name: args.shift(),
data: args
};
};

var logger = Logger();
logger.format(format);
io.use(logger);
```

# Installation and Environment Setup

Expand Down
21 changes: 21 additions & 0 deletions examples/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
var io = require('socket.io')(3000);
var Logger = require('./..');
var options = { format: Logger.defaultFormat, stream: { write: function (line) { process.stdout.write(line); } } };
var logger = Logger(options);
io.use(logger);
io.on('connection', function (sock) {
sock.emit('done');
});

setTimeout(function () {
var sock = require('socket.io-client').connect('ws://localhost:3000');
sock.on('connect', function () {
sock.emit('this');
sock.emit('is');
sock.emit('a');
sock.emit('test');
setTimeout(function () {
process.exit(0);
}, 1000);
});
},1000);
138 changes: 133 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,143 @@
var debug = require('debug')('logger');
var pkg = require('./../package.json');
var flat = require('flat');
var Router = require('socket.io-events');

exports = module.exports = Logger;
exports.version = require('./../package.json').version;
exports.version = pkg.version;

function Logger () {
if (!(this instanceof Logger)) return new Logger();
function logger () {
/**
* A very simple middleware for socket.io that will record the events and log
* them to a stream.
*
* @return Logger
*/

function Logger (options) {
if (!(this instanceof Logger)) return new Logger(options);

options = options || {};

debug('new logger v%s', pkg.version);

var router = Router();
router.on(function (sock, args, cb) {
debug('logger args.length %s', arguments.length);
try {
// "this" is the "socket"
logger.stream().write(logger.format(sock, args) + "\n");
cb();
}
catch (e) {
debug('caught an error %s', e);
console.trace(e);
cb(e);
}
});

function logger (sock, cb) {
debug('logger sock', sock, cb.toString());
router(sock, cb);
}

logger.__proto__ = Logger.prototype;

if (options.stream) {
logger.stream(options.stream);
}

if (options.format) {
logger.format(options.format);
}

return logger;
}

Logger.prototype = {}
/**
* The default formating function for Logger
*
* @param {Object} sock
* @param {args} args
*/

Logger.defaultFormat = function (sock, args) {
debug('defaultFormat', sock, args);
args = args || [];
var name = args.shift() || 'unkown';
var data;
switch(args.length) {
case 0:
data = {};
break;
case 1:
data = args.shift();
break;
default:
data = args;
break;
};
return {
socket: {
id: sock.id
},
event: {
name: name,
data: data
}
};
};

/**
* Either sets / gets the format function, or invokes the format
* function given the sock, and args.
*
* @api public
* @param mixed
* @return String
*/

Logger.prototype.format = function () {
var args = Array.prototype.slice.call(arguments);
debug('format args', args);

switch(arguments.length) {
case 0:
debug('get format');
if (!this._format) {
debug('no format');
this.format(Logger.defaultFormat);
}
return this._format;
break;
case 1:
debug('setting format')
if ('function' === typeof args[0] && args[0].length >= 2) {
this._format = args[0];
}
return this;
break;
default:
return JSON.stringify(flat.flatten(this.format().apply(this, args)));
break;
}

};

/**
* set / get the stream instance
*
* @api public
* @param {Object} stream
* @return Logger;
*/

Logger.prototype.stream = function (stream) {
if ('undefined' !== typeof stream && 'function' === typeof stream.write) {
this._stream = stream;
return this;
}
if (!this._stream || 'function' !== typeof this._stream.write) {
this.stream(process.stdout);
}
return this._stream;
};
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "socket.io-logger",
"version": "0.0.0-alpha1",
"description": "A socket.io-logger will log all of your events.",
"version": "0.0.0",
"description": "Simple logger middleware for socket.io.",
"main": "index.js",
"scripts": {
"test": "grunt"
Expand All @@ -26,9 +26,13 @@
"coffee-script": "^1.7.1",
"grunt-jasmine-bundle": "^0.2.0",
"grunt-cli": "^0.1.13",
"grunt": "^0.4.5"
"grunt": "^0.4.5",
"socket.io": "^1.0.6",
"socket.io-client": "^1.0.6"
},
"dependencies": {
"debug": "^1.0.2"
"debug": "^1.0.2",
"flat": "^1.2.1",
"socket.io-events": "^0.3.2"
}
}
82 changes: 80 additions & 2 deletions spec/lib/index-spec.coffee
Original file line number Diff line number Diff line change
@@ -1,18 +1,96 @@
EventEmitter = require('events').EventEmitter
Flat = require 'flat'

describe 'lib', ->

Given -> @sock = new EventEmitter
Given -> @sock.id = 1
Given -> @args = ['some event', {some: 'data'}]
Given -> @cb = jasmine.createSpy 'cb'
Given -> @line = '{"socket.id":1,"event.name":"some event","event.data.some":"data"}'

Given -> @lib = requireSubject 'lib', {
Given -> @lib = requireSubject 'lib',
'./../package.json':
version: 1
}
flat: Flat

describe '.version', ->

When -> @version = @lib.version
Then -> expect(@version).toEqual 1

describe '#defaultFormat', ->

When -> @res = @lib.defaultFormat @sock, @args
Then -> expect(@res).toEqual
socket:
id: 1
event:
name: 'some event'
data:
some: 'data'

describe '#', ->

When -> @res = @lib()
Then -> expect(typeof @res).toBe 'function'
And -> expect(@res instanceof @lib).toBe true

describe '#(options:Object)', ->

Given -> @options = stream: write: ->
When -> @res = @lib @options
Then -> expect(typeof @res).toBe 'function'
And -> expect(@res instanceof @lib).toBe true
And -> expect(@res.stream()).toEqual @options.stream

describe 'prototype', ->

Given -> @logger = @lib()

describe.only '# (sock:Object, args:Array)', ->

Given -> @packet = data: @args
Given -> @stream = jasmine.createSpyObj 'stream', ['write']
Given -> @logger.stream @stream
Given -> @logger @sock, @cb
When -> @sock.onevent @packet
Then -> expect(@stream.write).toHaveBeenCalled()
And -> expect(@stream.write.argsForCall[0][0]).toEqual @line + '\n'

describe '#format', ->

When -> @format = @logger.format()
Then -> expect(typeof @format).toBe 'function'
And -> expect(@format.length).toBe 2
And -> expect(@format).toEqual @lib.defaultFormat

describe '#format (format:Function)', ->

Given -> @format = (a, b) ->
When -> @logger.format @format
Then -> expect(@logger.format()).toEqual @format

describe '#format (sock:Object, args:Array)', ->

When -> @res = @logger.format @sock, @args
And -> expect(@res).toEqual @line

describe '#stream', ->

When -> @stream = @logger.stream()
Then -> expect(typeof @stream).toBe 'object'
And -> expect(typeof @stream.write).toBe 'function'

describe '#stream (stream:Object)', ->

Given -> @stream = write: ->
When -> @logger.stream @stream
Then -> expect(@logger.stream()).toEqual @stream

describe '#stream (stream:mixed)', ->

Given -> @stream = 'crap'
Given -> @existing = @logger.stream()
When -> @logger.stream @stream
Then -> expect(@logger.stream()).toEqual @existing

0 comments on commit 252fd03

Please sign in to comment.