Faidon Liambotis has submitted this change and it was merged.
Change subject: Replace Gmetric implementation
......................................................................
Replace Gmetric implementation
I didn't like gmetric.js's quality and I thought it might gain something by way
of concision if it were re-written. I did so (and tested) and it works.
Change-Id: I0c3198d122511aa856906e9bd7b8233a4dbda332
---
M modules/statsd/files/backends/ganglia.js
D modules/statsd/files/backends/gmetric.js
M modules/statsd/manifests/init.pp
3 files changed, 65 insertions(+), 540 deletions(-)
Approvals:
Faidon Liambotis: Looks good to me, approved
jenkins-bot: Verified
diff --git a/modules/statsd/files/backends/ganglia.js
b/modules/statsd/files/backends/ganglia.js
index d2d58f1..7f6e36b 100644
--- a/modules/statsd/files/backends/ganglia.js
+++ b/modules/statsd/files/backends/ganglia.js
@@ -23,6 +23,64 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+function Xdr( bufSize ) {
+ this.b = new Buffer( bufSize );
+ this.b.fill( 0 );
+ this.ptr = 0;
+}
+
+Xdr.prototype.pack = function ( type, value ) {
+ switch ( type ) {
+ case 'int':
+ this.b.writeInt32BE( value, this.ptr );
+ this.ptr += 4;
+ break;
+ case 'string':
+ this.pack( 'int', value.length );
+ this.b.write( value, this.ptr );
+ this.ptr += ( ( Buffer.byteLength( value ) + 3 ) & ~0x03 );
+ break;
+ case 'boolean':
+ this.pack( 'int', value ? 1 : 0 );
+ break;
+ }
+};
+
+Xdr.prototype.getBytes = function () {
+ return this.b.slice( 0, this.ptr );
+};
+
+Xdr.meta = function ( metric ) {
+ var xdr = new Xdr( 1024 );
+
+ xdr.pack( 'int', 128 );
+ xdr.pack( 'string', metric.hostname );
+ xdr.pack( 'string', metric.name );
+ xdr.pack( 'boolean', metric.spoof );
+ xdr.pack( 'string', metric.type );
+ xdr.pack( 'string', metric.name );
+ xdr.pack( 'string', metric.units );
+ xdr.pack( 'int', metric.slope );
+ xdr.pack( 'int', metric.tmax );
+ xdr.pack( 'int', metric.dmax );
+ xdr.pack( 'int', 1 );
+ xdr.pack( 'string', 'GROUP' );
+ xdr.pack( 'string', metric.group );
+ return xdr.getBytes();
+};
+
+Xdr.data = function ( metric ) {
+ var xdr = new Xdr( 512 );
+
+ xdr.pack( 'int', 133 );
+ xdr.pack( 'string', metric.hostname );
+ xdr.pack( 'string', metric.name );
+ xdr.pack( 'boolean', metric.spoof );
+ xdr.pack( 'string', '%s' );
+ xdr.pack( 'string', metric.value.toString() );
+ return xdr.getBytes();
+};
+
function logSocketError( err, bytes ) {
if ( err ) console.log( err );
}
@@ -72,13 +130,11 @@
}
}
-
var os = require( 'os' );
var util = require( 'util' );
var dgram = require( 'dgram' );
-var Gmetric = require( './gmetric' );
-var gmetric = new Gmetric();
+var slopes = [ 'zero', 'positive', 'negative', 'both', 'unspecified' ];
var blankGroup = {
count : 0,
@@ -137,7 +193,7 @@
name : args.join('_'),
} );
if ( typeof opts.slope === 'string' ) {
- opts.slope = Gmetric.slope[opts.slope.toLowerCase()];
+ opts.slope = slopes.indexOf( opts.slope );
}
ganglia.items.push( opts );
},
@@ -173,15 +229,16 @@
ganglia.dispatch();
},
dispatch : function () {
- var packed, metric;
+ var metric, meta, data;
ganglia.flushed = Math.floor( new Date() / 1000 );
while ( ( metric = ganglia.items.shift() ) !== undefined ) {
- packed = gmetric.pack(metric);
- socket.send( packed.meta, 0, packed.meta.length,
+ meta = Xdr.meta( metric );
+ socket.send( meta, 0, meta.length,
backendConfig.gangliaPort, backendConfig.gangliaHost,
logSocketError );
- socket.send( packed.data, 0, packed.data.length,
+ data = Xdr.data( metric );
+ socket.send( data, 0, data.length,
backendConfig.gangliaPort, backendConfig.gangliaHost,
logSocketError );
ganglia.sent++;
diff --git a/modules/statsd/files/backends/gmetric.js
b/modules/statsd/files/backends/gmetric.js
deleted file mode 100644
index c9a4bd4..0000000
--- a/modules/statsd/files/backends/gmetric.js
+++ /dev/null
@@ -1,527 +0,0 @@
-/**
- * Gmetric.js
- * Gmetric packet submission for node.js
- * https://github.com/jbuchbinder/node-gmetric
- *
- * Copyright (C) 2013 Jeff Buchbinder, and other contributors.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-(function() {
- /**
- * Module dependencies.
- */
-
- var dgram = require('dgram'),
- socket = require('dgram').createSocket('udp4');
-
- /**
- * The Gmetric class.
- */
-
- var Gmetric = (function(){
- function Gmetric(){}
-
- /**
- * Packs an integer as a big endian unsigned long.
- * refs: http://code.google.com/p/embeddedgmetric/wiki/GmetricProtocol
- * refs: http://www.ietf.org/rfc/rfc4506.txt
- * @param {Buffer} (target) The target Buffer to pack onto
- * @param {Integer} (i) The integer to pack
- * @param {Integer} (pos) The position to begin the pack
- * @return {Integer} The current position in the buffer
- */
-
- Gmetric.prototype.pack_int = function(target, i, pos){
- if (i === undefined || i === null){
- i = 0;
- }
- i = parseInt(i, 10);
- target.writeInt32BE(i, pos);
- return pos + 4;
- };
-
- /**
- * Packs a boolean as a big endian unsigned long.
- * refs: http://code.google.com/p/embeddedgmetric/wiki/GmetricProtocol
- * refs: http://www.ietf.org/rfc/rfc4506.txt
- * @param {Buffer} (target) The target Buffer to pack onto
- * @param {Integer} (b) The boolean to pack
- * @param {Integer} (pos) The position to begin the pack
- * @return {Integer} The current position in the buffer
- */
-
- Gmetric.prototype.pack_bool = function(target, b, pos){
- return this.pack_int(target, (b ? 1 : 0), pos);
- };
-
- /**
- * Packs a string matching the xdr format.
- * refs: http://code.google.com/p/embeddedgmetric/wiki/GmetricProtocol
- * refs: http://www.ietf.org/rfc/rfc4506.txt
- * @param {Buffer} (target) The target Buffer to pack onto
- * @param {String} (data) The string to pack
- * @param {Integer} (pos) The position to begin the pack
- * @return {Integer} The current position in the buffer
- */
-
- Gmetric.prototype.pack_string = function(target, data, pos){
- if (data === null || data === undefined){
- data = "";
- }
- data = data.toString();
- pos = this.pack_int(target, data.length, pos);
-
- var fill_length = this.string_fill_length(data);
- pos += target.write(data, pos, 'ascii');
- target.fill(0, pos, (pos + fill_length));
- return pos + fill_length;
- };
-
- /**
- * Returns the xdr fill length for a given string.
- * @param {String} (str) The string to retrieve the fill length for
- * @return {Integer} The xdr fill length for the given string
- */
-
- Gmetric.prototype.string_fill_length = function(str){
- var len = str.length;
- len = Math.floor((len + 3) / 4) * 4;
- return (len - str.length);
- };
-
- /**
- * Unpacks an xdr string.
- * @param {Buffer} (buffer) The buffer to read from
- * @param {Integer} (pos) The current buffer position
- * @return {Object} The unpacked string and buffer position
- */
-
- Gmetric.prototype.unpack_string = function(buffer, pos){
- var unpack, strlen, unpacked_string;
-
- // Parse the string length
- unpack = this.unpack_int(buffer, pos);
- pos = unpack.pos;
- strlen = unpack.integer;
-
- // Parse the string and update the position
- unpacked_string = buffer.toString('ascii', pos, pos+strlen);
- pos += strlen;
-
- // Add the fill length onto the position
- pos += this.string_fill_length(unpacked_string);
- return { string: unpacked_string, pos: pos };
- };
-
- /**
- * Unpacks an xdr integer.
- * @param {Buffer} (buffer) The buffer to read from
- * @param {Integer} (pos) The current buffer position
- * @return {Object} The unpacked integer and buffer position
- */
-
- Gmetric.prototype.unpack_int = function(buffer, pos){
- var unpacked = null;
- try{
- unpacked = buffer.readInt32BE(pos);
- pos += 4;
- } catch (err){}
- return { integer: unpacked, pos: pos };
- };
-
- /**
- * Unpacks an xdr boolean.
- * @param {Buffer} (buffer) The buffer to read from
- * @param {Integer} (pos) The current buffer position
- * @return {Object} The unpacked boolean and buffer position
- */
-
- Gmetric.prototype.unpack_bool = function(buffer, pos){
- var unpacked = this.unpack_int(buffer, pos);
- unpacked.bool = (unpacked.integer === 1);
- delete unpacked.integer;
- return unpacked;
- };
-
- /**
- * Returns the list of metric elements considered extras.
- * @param {Object} (metric) The gmetric metric hash
- * @return {Array} The list of gmetric objects considered to be extras
- */
-
- Gmetric.prototype.extra_elements = function(metric){
- var keys = Object.keys(metric);
- var extra_elems = [];
-
- for(var i = 0; i < keys.length; i++){
- if (module.exports.natural_metrics.hasOwnProperty(keys[i]) !== true){
- extra_elems.push(keys[i]);
- }
- }
- return extra_elems;
- };
-
- /**
- * Creates the metadata buffer for the gmetric packet.
- * refs: http://code.google.com/p/embeddedgmetric/wiki/GmetricProtocol
- * refs: http://www.ietf.org/rfc/rfc4506.txt
- * @param {Object} (metric) The gmetric metric hash
- * @return {Buffer} The meta buffer
- */
-
- Gmetric.prototype.create_meta = function(metric){
- var buffer = new Buffer(1024), pos = 0, extra_elems = [];
- pos = this.pack_int(buffer, 128, pos); // gmetadata_full
- pos = this.pack_string(buffer, metric.hostname, pos); // hostname
- pos = this.pack_string(buffer, metric.name, pos); // metric name
- pos = this.pack_bool(buffer, metric.spoof, pos); // spoof flag
-
- pos = this.pack_string(buffer, metric.type, pos); // metric type
- pos = this.pack_string(buffer, metric.name, pos); // metric name
- pos = this.pack_string(buffer, metric.units, pos); // metric units
- pos = this.pack_int(buffer,
- module.exports.slope[metric.slope], pos); // slope derivative
- pos = this.pack_int(buffer, metric.tmax, pos); // max between
- pos = this.pack_int(buffer, metric.dmax, pos); // lifetime
-
- // Magic Number: The number of extra data elements
- extra_elems = this.extra_elements(metric);
- pos = this.pack_int(buffer, extra_elems.length, pos);
-
- // Metadata Extra Data: key/value functionality
- for(var i = 0; i < extra_elems.length; i++){
- pos = this.pack_string(buffer, extra_elems[i].toUpperCase(), pos);
- pos = this.pack_string(buffer, metric[extra_elems[i]], pos);
- }
- return buffer.slice(0, pos);
- };
-
- /**
- * Creates the data buffer for the gmetric packet.
- * refs: http://code.google.com/p/embeddedgmetric/wiki/GmetricProtocol
- * refs: http://www.ietf.org/rfc/rfc4506.txt
- * @param {Object} (metric) The gmetric metric hash
- * @return {Buffer} The data buffer
- */
-
- Gmetric.prototype.create_data = function(metric){
- var buffer = new Buffer(512), pos = 0, value = metric.value.toString();
- pos = this.pack_int(buffer, 128+5, pos); // string message
- pos = this.pack_string(buffer, metric.hostname, pos); // hostname
- pos = this.pack_string(buffer, metric.name, pos); // metric name
- pos = this.pack_bool(buffer, metric.spoof, pos); // spoof flag
- pos = this.pack_string(buffer, "%s", pos); //
- pos = this.pack_string(buffer, value, pos); // metric value
- return buffer.slice(0, pos);
- };
-
- /**
- * Create the final package from a metric to send to the gmond target.
- * @param {Object} (metric) The metric packet to merge and pack
- * @return {Object} The gmetric meta and data packets
- */
-
- Gmetric.prototype.pack = function(opts){
- var metric = {
- hostname: '',
- group: '',
- spoof: 0,
- units: '',
- slope: 'both',
- tmax: 60,
- dmax: 0
- };
-
- for ( var key in opts ) {
- metric[key] = opts[key];
- }
-
- // Convert bools to ints
- if (metric.spoof === true){
- metric.spoof = 1;
- } else if(metric.spoof === false){
- metric.spoof = 0;
- }
-
- if ("name" in metric !== true ||
- "value" in metric !== true ||
- "type" in metric !== true){
- throw new Error("Missing name, value, type");
- }
-
- if (metric.type in module.exports.supported_types !== true){
- throw new Error("Invalid metric type");
- }
-
- var meta = this.create_meta(metric);
- var data = this.create_data(metric);
- return { meta: meta, data: data };
- };
-
- /**
- * Unpacks a gmetric meta packet.
- * @param {Buffer} (meta_packet) The meta packet buffer to unpack
- * @return {Object} The parsed meta packet
- */
-
- Gmetric.prototype.parse_meta = function(meta_packet){
- var meta = {}, unpack = null;
- if (meta_packet.readInt32BE(0) !== 128){
- throw new Error("Invalid meta packet");
- }
- var pos = 4;
-
- // Parse hostname
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- meta.hostname = unpack.string;
-
- // Parse metric name
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- meta.name = unpack.string;
-
- // Parse spoof flag
- unpack = this.unpack_bool(meta_packet, pos);
- pos = unpack.pos;
- meta.spoof = unpack.bool;
-
- // Parse metric type
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- meta.type = unpack.string;
-
- // Parse metric name
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- meta.name = unpack.string;
-
- // Parse metric units
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- meta.units = unpack.string;
-
- // Parse slope derivative
- unpack = this.unpack_int(meta_packet, pos);
- pos = unpack.pos;
- meta.slope = module.exports.slope2str[unpack.integer];
-
- // Parse tmax
- unpack = this.unpack_int(meta_packet, pos);
- pos = unpack.pos;
- meta.tmax = unpack.integer;
-
- // Parse dmax
- unpack = this.unpack_int(meta_packet, pos);
- pos = unpack.pos;
- meta.dmax = unpack.integer;
-
- // Parse number of extra data elements
- unpack = this.unpack_int(meta_packet, pos);
- pos = unpack.pos;
- var extra_elems = unpack.integer;
-
- // Parse each metadata key/value pair and add it into extras
- for(var i = 0; i < extra_elems; i++) {
- var extra_key, extra_value;
-
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- extra_key = unpack.string.toLowerCase();
- unpack = this.unpack_string(meta_packet, pos);
- pos = unpack.pos;
- extra_value = unpack.string;
- meta[extra_key] = extra_value;
- }
-
- return meta;
- };
-
- /**
- * Unpacks a gmetric data packet.
- * @param {Buffer} (data_packet) The data packet buffer to unpack
- * @return {Object} The parsed data packet
- */
-
- Gmetric.prototype.parse_data = function(data_packet){
- var data = {}, unpack = null;
- if (data_packet.readInt32BE(0) !== 133){
- throw new Error("Invalid data packet");
- }
- var pos = 4;
-
- // Parse hostname
- unpack = this.unpack_string(data_packet, pos);
- pos = unpack.pos;
- data.hostname = unpack.string;
-
- // Parse metric name
- unpack = this.unpack_string(data_packet, pos);
- pos = unpack.pos;
- data.name = unpack.string;
-
- // Parse spoof flag
- unpack = this.unpack_bool(data_packet, pos);
- pos = unpack.pos;
- data.spoof = unpack.bool;
-
- // Parse metric value
- unpack = this.unpack_string(data_packet, pos);
- pos = unpack.pos;
- unpack = this.unpack_string(data_packet, pos);
- pos = unpack.pos;
- data.value = unpack.string;
-
- return data;
- };
-
- /**
- * Unpacks a gmetric packet.
- * @param {Buffer} (packet) The packet to unpack
- * @return {Object} The parsed data or metadata packet
- */
-
- Gmetric.prototype.unpack = function(packet){
- if (packet.readInt32BE(0) === 128) {
- return this.parse_meta(packet);
- } else if (packet.readInt32BE(0) === 133) {
- return this.parse_data(packet);
- }
- };
-
- /**
- * Sends a packet buffer over UDP.
- * @param {String} (host) The target host
- * @param {Integer} (port) The target port
- * @param {Buffer} (packet) The packet buffer to send
- */
-
- Gmetric.prototype.send_packet = function(host, port, packet){
- socket.send(packet, 0, packet.length, port, host, function (err, bytes){
- if (err){
- console.log(err);
- }
- });
- };
-
- /**
- * Sends a metric packet over UDP.
- * @param {String} (host) The target host
- * @param {Integer} (port) The target port
- * @param {Object} (metric) The metric to send
- */
-
- Gmetric.prototype.send = function(host, port, metric){
- var packet = this.pack(metric);
- this.send_packet(host, port, packet.meta);
- this.send_packet(host, port, packet.data);
- };
-
- /**
- * Sends a metric packet over UDP broadcast
- * @param {String} (host) The target host
- * @param {Integer} (port) The target port
- * @param {Object} (metric) The metric to send
- */
-
- Gmetric.prototype.send_broadcast = function(host, port, metric){
- var packet = this.pack(metric);
- socket.setBroadcast(true);
- socket.setMulticastTTL(128);
- socket.addMembership(host);
- this.send_packet(host, port, packet.meta);
- this.send_packet(host, port, packet.data);
- };
-
- /**
- * Closes the udp socket.
- */
-
- Gmetric.prototype.close = function() {
- socket.close();
- };
-
- return Gmetric;
-
- })();
-
- /**
- * Expose `createGmetric()`.
- */
-
- module.exports = Gmetric;
-
- /**
- * Expose slope.
- */
-
- module.exports.slope = {
- zero: 0,
- positive: 1,
- negative: 2,
- both: 3,
- unspecified: 4
- };
-
- /**
- * Expose slope2str.
- */
-
- module.exports.slope2str = {
- 0: 'zero',
- 1: 'positive',
- 2: 'negative',
- 3: 'both',
- 4: 'unspecified'
- };
-
- /**
- * Expose supported_types.
- */
-
- module.exports.supported_types = {
- string: true,
- int8: true,
- uint8: true,
- int16: true,
- uint16: true,
- int32: true,
- uint32: true,
- float: true,
- double: true
- };
-
- /**
- * Expose natural_metrics.
- */
-
- module.exports.natural_metrics = {
- hostname: true,
- spoof: true,
- units: true,
- slope: true,
- name: true,
- value: true,
- type: true,
- tmax: true,
- dmax: true
- };
-
-}).call(this);
diff --git a/modules/statsd/manifests/init.pp b/modules/statsd/manifests/init.pp
index 54f599a..7873af4 100644
--- a/modules/statsd/manifests/init.pp
+++ b/modules/statsd/manifests/init.pp
@@ -50,11 +50,6 @@
notify => Service['statsd'],
}
- file { '/usr/share/statsd/backends/gmetric.js':
- source => 'puppet:///modules/statsd/backends/gmetric.js',
- require => Package['statsd'],
- }
-
file { '/usr/share/statsd/backends/ganglia.js':
source => 'puppet:///modules/statsd/backends/ganglia.js',
require => Package['statsd'],
--
To view, visit https://gerrit.wikimedia.org/r/82805
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I0c3198d122511aa856906e9bd7b8233a4dbda332
Gerrit-PatchSet: 1
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Ori.livneh <[email protected]>
Gerrit-Reviewer: Faidon Liambotis <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits