From 8f5d1c9fdc99d3934c83be293db1a5b4de04b175 Mon Sep 17 00:00:00 2001 From: James McNally Date: Wed, 27 May 2015 19:41:14 +0100 Subject: [PATCH 1/4] Created basic event support and priority support. --- lib/statsd.js | 26 ++++++++++++++++ package.json | 50 +++++++++++++++++-------------- test/dogstatsd_events.spec.js | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 22 deletions(-) create mode 100644 test/dogstatsd_events.spec.js diff --git a/lib/statsd.js b/lib/statsd.js index dbaffaf..36747cb 100644 --- a/lib/statsd.js +++ b/lib/statsd.js @@ -85,6 +85,26 @@ Client.prototype.update_stats = function(stats, delta, sampleRate, tags) { self.send(data, sampleRate, tags); }; +Client.prototype.event = function(title, text, options, tags) { + + var self = this; + + var titleLength = title.length; + var textLength = text.length; + + var eventString = '_e{' + titleLength + ',' + textLength + '}:'; + eventString += title + '|' + text; + + //Start of optional parameters + if(options) { + if (options.priority) { + eventString += '|p:' + options.priority; + } + } + + self.send_data(eventString); +}; + // An internal function update the last time the socket was // used. This function is called when the socket is used // and causes demand allocated ephemeral sockets to be closed @@ -182,3 +202,9 @@ Client.prototype.close = function() { }; exports.StatsD = Client; + +//Enum types to support events generation +exports.priority = { + NORMAL: 'normal', + LOW: 'low' +}; diff --git a/package.json b/package.json index 1549542..a0902c5 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,30 @@ { - "name" : "node-dogstatsd", - "description" : "node client for extended StatsD server of Datadog", - "version" : "0.0.6", - "author" : "Young Han Lee", - "repository" : { - "type" : "git", - "url" : "git://github.com/joybro/node-dogstatsd.git" - }, - "bugs" : { - "url" : "https://github.com/joybro/node-dogstatsd/issues" - }, - "directories" : { - "lib" : "./lib/" - }, - "main" : "./lib/statsd", - "engines" : { "node" : ">=0.1.97" }, - "licenses" : [ - { - "type" : "MIT", - "url" : "http://github.com/joybro/node-dogstatsd/raw/master/LICENSE" - } - ] + "name": "node-dogstatsd", + "description": "node client for extended StatsD server of Datadog", + "version": "0.0.6", + "author": "Young Han Lee", + "repository": { + "type": "git", + "url": "git://github.com/joybro/node-dogstatsd.git" + }, + "bugs": { + "url": "https://github.com/joybro/node-dogstatsd/issues" + }, + "directories": { + "lib": "./lib/" + }, + "main": "./lib/statsd", + "engines": { + "node": ">=0.1.97" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/joybro/node-dogstatsd/raw/master/LICENSE" + } + ], + "devDependencies": { + "mocha": "^2.2.5", + "sinon": "^1.14.1" + } } diff --git a/test/dogstatsd_events.spec.js b/test/dogstatsd_events.spec.js new file mode 100644 index 0000000..d76760b --- /dev/null +++ b/test/dogstatsd_events.spec.js @@ -0,0 +1,56 @@ +/** + * Created by James McNally on 27/05/2015. + */ + +var assert = require('assert'); +var sinon = require('sinon'); +var dogstatsd = require('../lib/statsd.js'); + + +describe('Dogstatsd Events Functionality', function() { + + + describe('Dogstatd Event Calls', function() { + + var client, sendSpy; + + before(function() { + client = new dogstatsd.StatsD('localhost',8125); + //replace send with spy to test without udp. + sendSpy = sinon.spy(); + client.send_data = sendSpy; + }); + + afterEach(function() { + sendSpy.reset(); + }); + + after(function() { + client.close(); + }); + + it('should send the basic string based on core options', function() { + client.event('TestTitle', 'TestText'); + assert(sendSpy.calledWith('_e{9,8}:TestTitle|TestText')); + }); + + it('should include a priority if included in the options', function() { + + client.event('TestTitle', 'TestText', {priority: dogstatsd.priority.NORMAL}); + var spyBuffer = sendSpy.args[0][0]; + assert(/\|p:normal/.test(spyBuffer)); + }); + }); + + describe('Event Enums', function() { + + it('should translate enumerated types to correct strings for event priorities', function() { + assert.equal(dogstatsd.priority.NORMAL, 'normal'); + assert.equal(dogstatsd.priority.LOW, 'low'); + }); + + it('should translate enumerated types to correct strings for event types', function() { + + }); + }); +}); \ No newline at end of file From 8d39b3360a0364609b10cff3ac7b4db960cb7678 Mon Sep 17 00:00:00 2001 From: James McNally Date: Thu, 28 May 2015 10:20:23 +0100 Subject: [PATCH 2/4] Added support for generating events to datadog through dogstatsd. --- README.md | 19 +++++++++++ lib/statsd.js | 61 +++++++++++++++++++++++++--------- package.json | 1 + test/dogstatsd_events.spec.js | 30 ++++++++++++++++- test/dogstatsd_metrics.spec.js | 46 +++++++++++++++++++++++++ 5 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 test/dogstatsd_metrics.spec.js diff --git a/README.md b/README.md index d19731c..5c5b626 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,25 @@ The name of the package is changed because this isn't really statsd client and s > c.histogram('node_test.some_service.data', 100) // works only with datadog' StatsD > c.increment('node_test.int', 1, ['tag:one']) // works only with datadog' StatsD +### Event Support + +This library supports raising events to a dogstatsd server as well. The convention is: + + client.event(title, description, options, tags) + +Options is an object that contains one of three optional parameters that can be set on the event: + +eventType - There is an enum called eventType that wraps the four options (error, info, success, warning). Default is info. +priority - String that sets priority. There is an enum called priority that wraps the two options (low, normal). Default is normal. +aggKey - String that allows the event viewer to aggregate similar requests. + +#### Example Call + + var dogstatd = require('../lib/statsd.js'); + var client = new dogstatd.StatsD('localhost',8125); + + client.event('Error Detected','error description',{eventType: dogstatd.eventType.ERROR, priority: dogstatd.priority.NORMAL, aggKey: 'Error'},['nodeApp']); + ## License node-statsd is licensed under the MIT license. diff --git a/lib/statsd.js b/lib/statsd.js index 36747cb..a310692 100644 --- a/lib/statsd.js +++ b/lib/statsd.js @@ -100,9 +100,18 @@ Client.prototype.event = function(title, text, options, tags) { if (options.priority) { eventString += '|p:' + options.priority; } + if (options.eventType) { + eventString += '|t:' + options.eventType; + } + if (options.aggKey) { + eventString += '|k:' + options.aggKey; + } + if (tags && tags.length !== 0) { + eventString += generateTagString(this.global_tags, tags); + } } - self.send_data(eventString); + self.send_data(new Buffer(eventString)); }; // An internal function update the last time the socket was @@ -140,7 +149,7 @@ Client.prototype.send_data = function (buf) { this._update_last_used(); - socket.send(buf, 0, buf.length, this.port, this.host); + socket.send(buf, 0, buf.length, this.port, this.host, function() {console.log('Sent buffer: ' + buf)}); }; Client.prototype.send = function(data, sample_rate, tags) { @@ -165,29 +174,44 @@ Client.prototype.send = function(data, sample_rate, tags) { else sampled_data = data; - if (this.global_tags || tags) { - var merged_tags = []; - - if (Array.isArray(this.global_tags)) - merged_tags = merged_tags.concat(this.global_tags); - + var tagString = generateTagString(this.global_tags, tags); + console.log(tagString); + for (stat in sampled_data) { - if (Array.isArray(tags)) - merged_tags = merged_tags.concat(tags); + sampled_data[stat] = sampled_data[stat] + tagString; - if (merged_tags.length > 0) { - var merged_tags_str = merged_tags.join(','); - for (stat in sampled_data) - sampled_data[stat] = sampled_data[stat] + "|#" + merged_tags_str; - } } + for (var stat in sampled_data) { var send_data = stat + ":" + sampled_data[stat]; this.send_data(new Buffer(send_data)); } }; +function generateTagString(globalTags, tags) { + + if (globalTags || tags) { + var merged_tags = []; + + if (Array.isArray(globalTags)) + merged_tags = merged_tags.concat(globalTags); + + + if (Array.isArray(tags)) + merged_tags = merged_tags.concat(tags); + + if (merged_tags.length > 0) { + return '|#' + merged_tags.join(','); + } + else { + return ''; + } + } + //catch all cases where nothing is returned. + return ''; +} + Client.prototype.close = function() { if (this.socket) this.socket.close(); @@ -208,3 +232,10 @@ exports.priority = { NORMAL: 'normal', LOW: 'low' }; + +exports.eventType = { + ERROR: 'error', + WARNING: 'warning', + INFO: 'info', + SUCCESS: 'success' +}; diff --git a/package.json b/package.json index a0902c5..25bfd5f 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "engines": { "node": ">=0.1.97" }, + "scripts": {"test": "mocha"}, "licenses": [ { "type": "MIT", diff --git a/test/dogstatsd_events.spec.js b/test/dogstatsd_events.spec.js index d76760b..343ce4c 100644 --- a/test/dogstatsd_events.spec.js +++ b/test/dogstatsd_events.spec.js @@ -31,7 +31,8 @@ describe('Dogstatsd Events Functionality', function() { it('should send the basic string based on core options', function() { client.event('TestTitle', 'TestText'); - assert(sendSpy.calledWith('_e{9,8}:TestTitle|TestText')); + var spyBuffer = sendSpy.args[0][0]; + assert('_e{9,8}:TestTitle|TestText' === spyBuffer.toString()); }); it('should include a priority if included in the options', function() { @@ -40,6 +41,28 @@ describe('Dogstatsd Events Functionality', function() { var spyBuffer = sendSpy.args[0][0]; assert(/\|p:normal/.test(spyBuffer)); }); + + it('should include an event type if included in the options', function() { + + client.event('TestTitle', 'TestText', {eventType: dogstatsd.eventType.SUCCESS}); + var spyBuffer = sendSpy.args[0][0]; + assert(/\|t:success/.test(spyBuffer)); + }); + + it('should include an aggregation key if included in the options', function() { + + client.event('TestTitle', 'TestText', {aggKey: 'testkey'}); + var spyBuffer = sendSpy.args[0][0]; + assert(/\|k:testkey/.test(spyBuffer)); + }); + + it('should include tags seperated by commas after a |#', function() { + + client.event('TestTitle', 'TestText', {aggKey: 'testkey'},['tag1:test','tag2:test2','tag3']); + var packet = sendSpy.args[0][0]; + assert(/\|#tag1:test,tag2:test2,tag3/.test(packet)); + + }); }); describe('Event Enums', function() { @@ -51,6 +74,11 @@ describe('Dogstatsd Events Functionality', function() { it('should translate enumerated types to correct strings for event types', function() { + assert.equal(dogstatsd.eventType.ERROR,'error'); + assert.equal(dogstatsd.eventType.WARNING,'warning'); + assert.equal(dogstatsd.eventType.INFO,'info'); + assert.equal(dogstatsd.eventType.SUCCESS,'success'); + }); }); }); \ No newline at end of file diff --git a/test/dogstatsd_metrics.spec.js b/test/dogstatsd_metrics.spec.js new file mode 100644 index 0000000..a736fdd --- /dev/null +++ b/test/dogstatsd_metrics.spec.js @@ -0,0 +1,46 @@ +/** + * Created by James on 28/05/2015. + */ + +var assert = require('assert'); +var sinon = require('sinon'); +var dogstatsd = require('../lib/statsd.js'); + +describe('dogstatsd Metrics Functionality: ', function() { + + describe('Tags Functionality', function() { + + var client, sendSpy; + + before(function() { + client = new dogstatsd.StatsD('localhost',8125); + //replace send with spy to test without udp. + sendSpy = sinon.spy(); + client.send_data = sendSpy; + }); + + afterEach(function() { + sendSpy.reset(); + }); + + after(function() { + client.close(); + }); + + it('should include tags separated by commas after a |#', function() { + + client.increment('node_test.int',1,['tag1:test','tag2:test2','tag3']); + var packet = sendSpy.args[0][0]; + assert(/\|#tag1:test,tag2:test2,tag3/.test(packet)); + + }); + + it('should not include the tags section if no tags are specified', function() { + client.increment('node_test.int',1); + var packet = sendSpy.args[0][0]; + console.log(packet.toString()); + assert.equal(packet.toString(),'node_test.int:1|c'); + + }) + }) +}) \ No newline at end of file From 88c45aab422a1f5cd66f4ba208878776b885191e Mon Sep 17 00:00:00 2001 From: James McNally Date: Thu, 28 May 2015 10:25:30 +0100 Subject: [PATCH 3/4] Updated README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5c5b626..629cadc 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ This library supports raising events to a dogstatsd server as well. The conventi Options is an object that contains one of three optional parameters that can be set on the event: -eventType - There is an enum called eventType that wraps the four options (error, info, success, warning). Default is info. -priority - String that sets priority. There is an enum called priority that wraps the two options (low, normal). Default is normal. -aggKey - String that allows the event viewer to aggregate similar requests. +* *eventType* - There is an enum called eventType that wraps the four options (error, info, success, warning). Default is info. +* *priority* - String that sets priority. There is an enum called priority that wraps the two options (low, normal). Default is normal. +* *aggKey* - String that allows the event viewer to aggregate similar requests. #### Example Call From 0b70dcd5f645224378572d9889133e0f47e907fe Mon Sep 17 00:00:00 2001 From: James McNally Date: Mon, 14 Dec 2015 17:01:57 +0000 Subject: [PATCH 4/4] Removed console.log from the socket send. --- lib/statsd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/statsd.js b/lib/statsd.js index a310692..96fbd87 100644 --- a/lib/statsd.js +++ b/lib/statsd.js @@ -149,7 +149,7 @@ Client.prototype.send_data = function (buf) { this._update_last_used(); - socket.send(buf, 0, buf.length, this.port, this.host, function() {console.log('Sent buffer: ' + buf)}); + socket.send(buf, 0, buf.length, this.port, this.host); }; Client.prototype.send = function(data, sample_rate, tags) {