From 4cf3d242a503e6e4d6427f22c32b39f138b1ab6f Mon Sep 17 00:00:00 2001 From: Simo Kinnunen Date: Thu, 30 Jan 2014 00:06:03 +0900 Subject: [PATCH] Add HipChat notifier role. --- lib/cli.js | 39 ++++++++++++++++++ lib/roles/device.js | 2 +- lib/roles/notify/hipchat.js | 81 +++++++++++++++++++++++++++++++++++++ lib/roles/processor.js | 1 + lib/util/logger.js | 9 +++++ lib/util/wireutil.js | 2 + lib/wire/wire.proto | 1 + 7 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 lib/roles/notify/hipchat.js diff --git a/lib/cli.js b/lib/cli.js index 096a175a..5726c30c 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -237,6 +237,45 @@ program }) }) +program + .command('notify-hipchat') + .description('start HipChat notifier') + .option('-t, --token ' + , 'HipChat v2 API token (or $HIPCHAT_TOKEN)' + , String + , process.env.HIPCHAT_TOKEN) + .option('-r, --room ' + , 'HipChat room (or $HIPCHAT_ROOM)' + , String + , process.env.HIPCHAT_ROOM) + .option('-p, --priority ' + , 'minimum log level' + , Number + , logger.Level.WARNING) + .option('-s, --connect-sub ' + , 'sub endpoint' + , cliutil.list) + .action(function(options) { + if (!options.token) { + this.missingArgument('--token') + } + if (!options.room) { + this.missingArgument('--room') + } + if (!options.connectSub) { + this.missingArgument('--connect-sub') + } + + require('./roles/notify/hipchat')({ + token: options.token + , room: options.room + , priority: options.priority + , endpoints: { + sub: options.connectSub + } + }) + }) + program .command('app') .description('start app') diff --git a/lib/roles/device.js b/lib/roles/device.js index b6d2f3cf..1bcaab49 100644 --- a/lib/roles/device.js +++ b/lib/roles/device.js @@ -51,7 +51,7 @@ module.exports = function(options) { // Forward all logs logger.on('entry', function(entry) { - push.send([wireutil.global, + push.send([wireutil.log, wireutil.makeDeviceLogMessage(options.serial, entry)]) }) diff --git a/lib/roles/notify/hipchat.js b/lib/roles/notify/hipchat.js new file mode 100644 index 00000000..b5728c35 --- /dev/null +++ b/lib/roles/notify/hipchat.js @@ -0,0 +1,81 @@ +var util = require('util') + +var Hipchatter = require('hipchatter') +var Promise = require('bluebird') +var zmq = require('zmq') + +var logger = require('../../util/logger') +var wire = require('../../wire') +var wireutil = require('../../util/wireutil')(wire) + +module.exports = function(options) { + var log = logger.createLogger('notify-hipchat') + var client = Promise.promisifyAll(new Hipchatter(options.token)) + var buffer = [] + , timer + + // Input + var sub = zmq.socket('sub') + options.endpoints.sub.forEach(function(endpoint) { + log.info('Receiving input from %s', endpoint) + sub.connect(endpoint) + }) + + // Establish always-on channels + ;[wireutil.log].forEach(function(channel) { + log.info('Subscribing to permanent channel "%s"', channel) + sub.subscribe(channel) + }) + + sub.on('message', function(channel, data) { + var wrapper = wire.Envelope.decode(data) + switch (wrapper.type) { + case wire.MessageType.DEVICE_LOG: + var message = wire.DeviceLogMessage.decode(wrapper.message) + if (message.priority >= options.priority) { + buffer.push(message) + clearTimeout(timer) + timer = setTimeout(push, 1000) + } + break + } + }) + + function push() { + var messages = buffer.splice(0).map(function(entry) { + return util.format( + '%s/%s %d [%s] %s' + , logger.LevelLabel[entry.priority] + , entry.tag + , entry.pid + , entry.identifier + , entry.message + ) + }) + + log.info('Sending %d message(s)', messages.length) + + return client.notifyAsync(process.env.HIPCHAT_ROOM, { + message: messages.join('
') + , color: 'purple' + , notify: true + , message_format: 'html' + , token: process.env.HIPCHAT_TOKEN + }) + } + + function gracefullyExit() { + process.exit(0) + } + + process.on('SIGINT', function() { + gracefullyExit() + }) + + process.on('SIGTERM', function() { + gracefullyExit() + }) + + log.info('Listening for %s (or higher) level log messages', + logger.LevelLabel[options.priority]) +} diff --git a/lib/roles/processor.js b/lib/roles/processor.js index 8eec760c..04037089 100644 --- a/lib/roles/processor.js +++ b/lib/roles/processor.js @@ -44,6 +44,7 @@ module.exports = function(options) { case wire.MessageType.DEVICE_LOG: var message = wire.DeviceLogMessage.decode(wrapper.message) dbapi.saveDeviceLog(message.serial, message) + appDealer.send([channel, data]) break case wire.MessageType.DEVICE_POKE: var message = wire.DevicePokeMessage.decode(wrapper.message) diff --git a/lib/util/logger.js b/lib/util/logger.js index f2c46ea7..b96dd72f 100644 --- a/lib/util/logger.js +++ b/lib/util/logger.js @@ -106,6 +106,15 @@ Logger.Level = { , FATAL: 6 } +Logger.LevelLabel = { + 1: 'DBG' +, 2: 'VRB' +, 3: 'INF' +, 4: 'WRN' +, 5: 'ERR' +, 6: 'FTL' +} + Logger.globalIdentifier = '*' Logger.createLogger = function(tag) { diff --git a/lib/util/wireutil.js b/lib/util/wireutil.js index c13a1c4c..f52046b1 100644 --- a/lib/util/wireutil.js +++ b/lib/util/wireutil.js @@ -5,6 +5,7 @@ var uuid = require('node-uuid') module.exports = function(wire) { var wireutil = { global: '*ALL' + , log: '*LOG' , makePrivateChannel: function() { return uuid.v4(null, new Buffer(16)).toString('base64') } @@ -63,6 +64,7 @@ module.exports = function(wire) { , entry.tag , entry.pid , entry.message + , entry.identifier ) return wireutil.envelope(wire.MessageType.DEVICE_LOG, message) diff --git a/lib/wire/wire.proto b/lib/wire/wire.proto index ac171f05..fa1dc865 100644 --- a/lib/wire/wire.proto +++ b/lib/wire/wire.proto @@ -31,6 +31,7 @@ message DeviceLogMessage { required string tag = 4; required uint32 pid = 5; required string message = 6; + required string identifier = 7; } // Introductions