138 lines
4.1 KiB
JavaScript
138 lines
4.1 KiB
JavaScript
var zlib = require('zlib')
|
|
var dgram = require('dgram')
|
|
var crypto = require('crypto')
|
|
|
|
// From https://github.com/Graylog2/graylog2-docs/wiki/GELF
|
|
// and https://github.com/Graylog2/gelf-php/blob/master/GELFMessage.php
|
|
var GELF_ID = [0x1e, 0x0f]
|
|
var GELF_KEYS = ['version', 'host', 'short_message', 'full_message', 'timestamp', 'level', 'facility', 'line', 'file']
|
|
var ILLEGAL_KEYS = ['_id']
|
|
|
|
function Gelfling(host, port, options) {
|
|
this.host = host != null ? host : 'localhost'
|
|
this.port = port != null ? port : 12201
|
|
if (options == null) options = {}
|
|
|
|
this.maxChunkSize = this.getMaxChunkSize(options.maxChunkSize)
|
|
this.defaults = options.defaults || {}
|
|
this.errHandler = options.errHandler || console.error
|
|
this.keepAlive = options.keepAlive
|
|
this.compress = options.compress == null ? true : options.compress
|
|
}
|
|
|
|
Gelfling.prototype.send = function(data, callback) {
|
|
if (callback == null) callback = function() {}
|
|
if (Buffer.isBuffer(data)) data = [data]
|
|
var udpClient, remaining, i, self = this, cbDone = false
|
|
|
|
if (!Array.isArray(data))
|
|
return this.encode(this.convert(data), function(err, chunks) {
|
|
if (err) return callback(err)
|
|
self.send(chunks, callback)
|
|
})
|
|
|
|
if (!this.keepAlive || !this.udpClient) {
|
|
udpClient = dgram.createSocket('udp4')
|
|
udpClient.on('error', this.errHandler)
|
|
if (this.keepAlive) this.udpClient = udpClient
|
|
} else {
|
|
udpClient = this.udpClient
|
|
}
|
|
remaining = data.length
|
|
function checkDone(err) {
|
|
if (err || --remaining === 0) {
|
|
if (!self.keepAlive) udpClient.close()
|
|
if (!cbDone) {
|
|
cbDone = true;
|
|
callback(err)
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < data.length; i++)
|
|
udpClient.send(data[i], 0, data[i].length, this.port, this.host, checkDone)
|
|
}
|
|
|
|
Gelfling.prototype.close = function() {
|
|
if (this.udpClient) this.udpClient.close()
|
|
}
|
|
|
|
Gelfling.prototype.encode = function(msg, callback) {
|
|
if (callback == null) callback = function() {}
|
|
var self = this
|
|
var buffer = new Buffer(JSON.stringify(msg))
|
|
|
|
if (!this.compress) return callback(null, this.split(buffer))
|
|
|
|
zlib.gzip(buffer, function(err, compressed) {
|
|
if (err) return callback(err)
|
|
callback(null, self.split(compressed))
|
|
})
|
|
}
|
|
|
|
Gelfling.prototype.split = function(data, chunkSize) {
|
|
if (chunkSize == null) chunkSize = this.maxChunkSize
|
|
if (data.length <= chunkSize) return [data]
|
|
|
|
var msgId = [].slice.call(crypto.randomBytes(8)),
|
|
numChunks = Math.ceil(data.length / chunkSize),
|
|
chunks = new Array(numChunks), chunkIx, dataSlice, dataStart
|
|
|
|
for (chunkIx = 0; chunkIx < numChunks; chunkIx++) {
|
|
dataStart = chunkIx * chunkSize
|
|
dataSlice = [].slice.call(data, dataStart, dataStart + chunkSize)
|
|
chunks[chunkIx] = new Buffer(GELF_ID.concat(msgId, chunkIx, numChunks, dataSlice))
|
|
}
|
|
|
|
return chunks
|
|
}
|
|
|
|
Gelfling.prototype.convert = function(msg) {
|
|
if (typeof msg !== 'object') msg = {short_message: msg}
|
|
|
|
var gelfMsg = {}, defaults = this.defaults, key, val
|
|
|
|
for (key in defaults) {
|
|
if (!defaults.hasOwnProperty(key)) continue
|
|
val = defaults[key]
|
|
gelfMsg[key] = typeof val === 'function' ? val(msg) : val
|
|
}
|
|
|
|
for (key in msg) {
|
|
if (!msg.hasOwnProperty(key)) continue
|
|
val = msg[key]
|
|
if (GELF_KEYS.indexOf(key) < 0) key = '_' + key
|
|
if (ILLEGAL_KEYS.indexOf(key) >= 0) key = '_' + key
|
|
gelfMsg[key] = val
|
|
}
|
|
|
|
if (gelfMsg.version == null) gelfMsg.version = '1.0'
|
|
if (gelfMsg.host == null) gelfMsg.host = require('os').hostname()
|
|
if (gelfMsg.timestamp == null) gelfMsg.timestamp = +(new Date) / 1000
|
|
if (gelfMsg.short_message == null) gelfMsg.short_message = JSON.stringify(msg)
|
|
|
|
return gelfMsg
|
|
}
|
|
|
|
Gelfling.prototype.getMaxChunkSize = function(size) {
|
|
if (size == null) size = 'wan'
|
|
switch (size.toLowerCase()) {
|
|
case 'wan': return 1420
|
|
case 'lan': return 8154
|
|
default: return parseInt(size, 10)
|
|
}
|
|
}
|
|
|
|
var gelfling = module.exports = function(host, port, options) {
|
|
return new Gelfling(host, port, options)
|
|
}
|
|
gelfling.Gelfling = Gelfling
|
|
|
|
gelfling.EMERGENCY = 0
|
|
gelfling.ALERT = 1
|
|
gelfling.CRITICAL = 2
|
|
gelfling.ERROR = 3
|
|
gelfling.WARNING = 4
|
|
gelfling.NOTICE = 5
|
|
gelfling.INFO = 6
|
|
gelfling.DEBUG = 7
|