├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── example.js ├── gelf-stream.js ├── package.json └── test └── fast.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | 4 | .tern-port 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 Michael Hart (michael.hart.au@gmail.com) 2 | 3 | This project is free software released under the MIT license: 4 | http://www.opensource.org/licenses/mit-license.php 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gelf-stream 2 | ----------- 3 | 4 | [![Build Status](https://secure.travis-ci.org/mhart/gelf-stream.png?branch=master)](http://travis-ci.org/mhart/gelf-stream) 5 | 6 | A node.js stream to send JS objects to a 7 | [Graylog2](http://graylog2.org/) server (in 8 | [GELF](http://graylog2.org/resources/gelf) format). 9 | 10 | Also provides a stream that can be used directly in 11 | [Bunyan](https://github.com/trentm/node-bunyan) and provides 12 | a number of sane mappings. 13 | 14 | Example 15 | ------- 16 | 17 | ```javascript 18 | var split = require('split'), 19 | bunyan = require('bunyan'), 20 | gelfStream = require('gelf-stream') 21 | 22 | // gelf-stream comes with Bunyan support 23 | 24 | var stream = gelfStream.forBunyan('localhost') 25 | 26 | var log = bunyan.createLogger({name: 'foo', streams: [{type: 'raw', stream: stream}]}) 27 | 28 | log.info('Testing Bunyan') // will be sent to the Graylog2 server on localhost 29 | 30 | log.error(new Error('Oh noes!')) // will extract file/line numbers too 31 | 32 | stream.end() // Bunyan doesn't currently end the stream when the program has finished 33 | 34 | // Or you can use it to stream any sort of object/string 35 | 36 | process.stdin 37 | .pipe(split()) // split into lines 38 | .pipe(gelfStream.create('localhost', {defaults: {level: 6}})) 39 | 40 | process.stdin.resume() 41 | ``` 42 | 43 | API 44 | --- 45 | 46 | ### gelfStream.create([host], [port], [options]) 47 | 48 | ### gelfStream.forBunyan([host], [port], [options]) 49 | 50 | 51 | Installation 52 | ------------ 53 | 54 | With [npm](http://npmjs.org/) do: 55 | 56 | ``` 57 | npm install gelf-stream 58 | ``` 59 | 60 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var split = require('split'), 2 | bunyan = require('bunyan'), 3 | gelfStream = require('./') // require('gelf-stream') 4 | 5 | // gelf-stream comes with Bunyan support 6 | 7 | var stream = gelfStream.forBunyan('localhost') 8 | 9 | var log = bunyan.createLogger({name: 'foo', streams: [{type: 'raw', stream: stream}]}) 10 | 11 | log.info('Testing Bunyan') // will be sent to the Graylog2 server on localhost 12 | 13 | log.error(new Error('Oh noes!')) // will extract file/line numbers too 14 | 15 | stream.end() // Bunyan doesn't currently end the stream when the program has finished 16 | 17 | // Or you can use it to stream any sort of object/string 18 | 19 | process.stdin 20 | .pipe(split()) // split into lines 21 | .pipe(gelfStream.create('localhost', {defaults: {level: 6}})) 22 | 23 | process.stdin.resume() 24 | 25 | -------------------------------------------------------------------------------- /gelf-stream.js: -------------------------------------------------------------------------------- 1 | var gelfStream = exports 2 | var gelfling = require('gelfling') 3 | var util = require('util') 4 | var Writable = require('stream').Writable 5 | 6 | function GelfStream(host, port, options) { 7 | if (options == null && typeof port === 'object') { 8 | options = port 9 | port = null 10 | if (options == null && typeof host === 'object') { 11 | options = host 12 | host = null 13 | } 14 | } 15 | if (options == null) options = {} 16 | 17 | if (options.keepAlive == null) options.keepAlive = true 18 | 19 | Writable.call(this, {objectMode: true}) 20 | 21 | this._options = options 22 | this._client = gelfling(host, port, options) 23 | 24 | this.once('finish', this.destroy) 25 | } 26 | util.inherits(GelfStream, Writable) 27 | 28 | GelfStream.prototype._write = function(chunk, encoding, callback) { 29 | if (!this._options.filter || this._options.filter(chunk)) { 30 | this._client.send(this._options.map ? this._options.map(chunk) : chunk, callback) 31 | } else { 32 | callback() 33 | } 34 | } 35 | 36 | GelfStream.prototype.destroy = function(callback) { 37 | if (callback) this.once('close', callback) 38 | this._client.close() 39 | process.nextTick(function() { this.emit('close') }.bind(this)) 40 | } 41 | 42 | function create(host, port, options) { 43 | return new GelfStream(host, port, options) 44 | } 45 | 46 | // --------------------------- 47 | // Bunyan stuff 48 | // --------------------------- 49 | 50 | function mapGelfLevel(bunyanLevel) { 51 | switch (bunyanLevel) { 52 | case 10 /*bunyan.TRACE*/: return gelfling.DEBUG 53 | case 20 /*bunyan.DEBUG*/: return gelfling.DEBUG 54 | case 30 /*bunyan.INFO*/: return gelfling.INFO 55 | case 40 /*bunyan.WARN*/: return gelfling.WARNING 56 | case 50 /*bunyan.ERROR*/: return gelfling.ERROR 57 | case 60 /*bunyan.FATAL*/: return gelfling.EMERGENCY 58 | default: return gelfling.WARNING 59 | } 60 | } 61 | 62 | function flatten(obj, into, prefix, sep) { 63 | if (into == null) into = {} 64 | if (prefix == null) prefix = '' 65 | if (sep == null) sep = '.' 66 | var key, prop 67 | for (key in obj) { 68 | if (!Object.prototype.hasOwnProperty.call(obj, key)) continue 69 | prop = obj[key] 70 | if (typeof prop === 'object' && !(prop instanceof Date) && !(prop instanceof RegExp)) 71 | flatten(prop, into, prefix + key + sep, sep) 72 | else 73 | into[prefix + key] = prop 74 | } 75 | return into 76 | } 77 | 78 | function bunyanToGelf(log) { 79 | /*jshint camelcase:false */ 80 | var errFile, key, 81 | ignoreFields = ['hostname', 'time', 'msg', 'name', 'level', 'v'], 82 | flattenedLog = flatten(log), 83 | gelfMsg = { 84 | host: log.hostname, 85 | timestamp: +new Date(log.time) / 1000, 86 | short_message: log.msg, 87 | facility: log.name, 88 | level: mapGelfLevel(log.level), 89 | full_message: JSON.stringify(log, null, 2) 90 | } 91 | 92 | if (log.err && log.err.stack && 93 | (errFile = log.err.stack.match(/\n\s+at .+ \(([^:]+)\:([0-9]+)/)) != null) { 94 | if (errFile[1]) gelfMsg.file = errFile[1] 95 | if (errFile[2]) gelfMsg.line = errFile[2] 96 | } 97 | 98 | for (key in flattenedLog) { 99 | if (ignoreFields.indexOf(key) < 0 && gelfMsg[key] == null) 100 | gelfMsg[key] = flattenedLog[key] 101 | } 102 | 103 | return gelfMsg 104 | } 105 | 106 | function forBunyan(host, port, options) { 107 | if (options == null && typeof port === 'object') { 108 | options = port 109 | port = null 110 | if (options == null && typeof host === 'object') { 111 | options = host 112 | host = null 113 | } 114 | } 115 | if (options == null) options = {} 116 | 117 | options.map = bunyanToGelf 118 | 119 | return new GelfStream(host, port, options) 120 | } 121 | 122 | gelfStream.GelfStream = GelfStream 123 | gelfStream.create = create 124 | gelfStream.forBunyan = forBunyan 125 | gelfStream.bunyanToGelf = bunyanToGelf 126 | gelfStream.mapGelfLevel = mapGelfLevel 127 | gelfStream.flatten = flatten 128 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gelf-stream", 3 | "version": "1.1.1", 4 | "description": "A stream to send JS objects to a Graylog2 server (in GELF format)", 5 | "author": "Michael Hart (http://github.com/mhart)", 6 | "main": "gelf-stream.js", 7 | "keywords": [ 8 | "gelf", 9 | "stream", 10 | "graylog", 11 | "graylog2", 12 | "bunyan" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/mhart/gelf-stream.git" 17 | }, 18 | "license": "MIT", 19 | "dependencies": { 20 | "gelfling": "^0.3.0" 21 | }, 22 | "devDependencies": { 23 | "mocha": "^2.3.4", 24 | "should": "^8.1.1" 25 | }, 26 | "scripts": { 27 | "test": "mocha ./test/fast.js -b -t 100s -R list" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/fast.js: -------------------------------------------------------------------------------- 1 | var should = require('should'), 2 | gelfStream = require('../') 3 | 4 | describe('gelf-stream', function() { 5 | 6 | }) 7 | 8 | --------------------------------------------------------------------------------