Skip to content
This repository was archived by the owner on Sep 19, 2024. It is now read-only.

Add pull request template #78

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Description

Please include a summary of the change and which issues are fixed. Please also include relevant motivation and context.

Fixes:
- Link to Clubhouse story

## Type of change

Please delete options that are not relevant.

- Frontend only. Little-to-no backend code was modified.
- Backend only. Does not require any frontend code changes.
- Affects the pipeline, (ETLs, Workers, Periodic).
- Requires a DB migration to be run.
- Affects signup/login/onboarding.
- Affects billing/pricing.
- Has required changes in other repos, (LIST THEM HERE).
- Other (styles, tests, build, etc).

---

[PR Guidelines](https://github.com/rollbar/internal/blob/master/code-style/GUIDELINES.md)
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ If an array is specified as the `name` parameter each item in that array will be
client.histogram('my_histogram', 42, 0.25, next);
client.histogram('my_histogram', 42, ['tag'], next);
client.histogram('my_histogram', 42, 0.25, ['tag'], next);

// Send multiple metrics
var multi = client.multi();
multi.set('my_unique', 'foobar');
multi.increment(['these', 'are', 'different', 'stats']);
multi.gauge('my_gauge', 123.45);
// callback is optional
multi.send(next);
```

## Errors
Expand Down
226 changes: 162 additions & 64 deletions lib/statsd.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,7 @@
var dgram = require('dgram'),
dns = require('dns');

/**
* The UDP Client for StatsD
* @param options
* @option host {String} The host to connect to default: localhost
* @option port {String|Integer} The port to connect to default: 8125
* @option prefix {String} An optional prefix to assign to each stat name sent
* @option suffix {String} An optional suffix to assign to each stat name sent
* @option globalize {boolean} An optional boolean to add "statsd" as an object in the global namespace
* @option cacheDns {boolean} An optional option to only lookup the hostname -> ip address once
* @option mock {boolean} An optional boolean indicating this Client is a mock object, no stats are sent.
* @constructor
*/
var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock) {
var options = host || {},
self = this;

if(arguments.length > 1 || typeof(host) === 'string'){
options = {
host : host,
port : port,
prefix : prefix,
suffix : suffix,
globalize : globalize,
cacheDns : cacheDns,
mock : mock === true
};
}

this.host = options.host || 'localhost';
this.port = options.port || 8125;
this.prefix = options.prefix || '';
this.suffix = options.suffix || '';
this.socket = dgram.createSocket('udp4');
this.mock = options.mock;

if(options.cacheDns === true){
dns.lookup(options.host, function(err, address, family){
if(err == null){
self.host = address;
}
});
}

if(options.globalize){
global.statsd = this;
}
};
var functions = {};

/**
* Represents the timing stat
Expand All @@ -57,8 +11,10 @@ var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock) {
* @param tags {Array=} The Array of tags to add to metrics. Optional.
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.timing = function (stat, time, sampleRate, tags, callback) {
this.sendAll(stat, time, 'ms', sampleRate, tags, callback);
functions.timing = function (method) {
return function (stat, time, sampleRate, tags, callback) {
return this[method](stat, time, 'ms', sampleRate, tags, callback);
};
};

/**
Expand All @@ -69,8 +25,10 @@ Client.prototype.timing = function (stat, time, sampleRate, tags, callback) {
* @param tags {Array=} The Array of tags to add to metrics. Optional.
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.increment = function (stat, value, sampleRate, tags, callback) {
this.sendAll(stat, value || 1, 'c', sampleRate, tags, callback);
functions.increment = function (method) {
return function (stat, value, sampleRate, tags, callback) {
return this[method](stat, value || 1, 'c', sampleRate, tags, callback);
};
};

/**
Expand All @@ -81,8 +39,10 @@ Client.prototype.increment = function (stat, value, sampleRate, tags, callback)
* @param tags {Array=} The Array of tags to add to metrics. Optional.
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.decrement = function (stat, value, sampleRate, tags, callback) {
this.sendAll(stat, -value || -1, 'c', sampleRate, tags, callback);
functions.decrement = function (method) {
return function (stat, value, sampleRate, tags, callback) {
return this[method](stat, -value || -1, 'c', sampleRate, tags, callback);
};
};

/**
Expand All @@ -93,8 +53,10 @@ Client.prototype.decrement = function (stat, value, sampleRate, tags, callback)
* @param tags {Array=} The Array of tags to add to metrics. Optional.
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.histogram = function (stat, value, sampleRate, tags, callback) {
this.sendAll(stat, value, 'h', sampleRate, tags, callback);
functions.histogram = function (method) {
return function (stat, value, sampleRate, tags, callback) {
return this[method](stat, value, 'h', sampleRate, tags, callback);
};
};


Expand All @@ -106,8 +68,10 @@ Client.prototype.histogram = function (stat, value, sampleRate, tags, callback)
* @param tags {Array=} The Array of tags to add to metrics. Optional.
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.gauge = function (stat, value, sampleRate, tags, callback) {
this.sendAll(stat, value, 'g', sampleRate, tags, callback);
functions.gauge = function (method) {
return function (stat, value, sampleRate, tags, callback) {
return this[method](stat, value, 'g', sampleRate, tags, callback);
};
};

/**
Expand All @@ -118,11 +82,65 @@ Client.prototype.gauge = function (stat, value, sampleRate, tags, callback) {
* @param tags {Array=} The Array of tags to add to metrics. Optional.
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.unique =
Client.prototype.set = function (stat, value, sampleRate, tags, callback) {
this.sendAll(stat, value, 's', sampleRate, tags, callback);
functions.unique =
functions.set = function (method) {
return function (stat, value, sampleRate, tags, callback) {
return this[method](stat, value, 's', sampleRate, tags, callback);
}
};

/**
* The UDP Client for StatsD
* @param options
* @option host {String} The host to connect to default: localhost
* @option port {String|Integer} The port to connect to default: 8125
* @option prefix {String} An optional prefix to assign to each stat name sent
* @option suffix {String} An optional suffix to assign to each stat name sent
* @option globalize {boolean} An optional boolean to add "statsd" as an object in the global namespace
* @option cacheDns {boolean} An optional option to only lookup the hostname -> ip address once
* @option mock {boolean} An optional boolean indicating this Client is a mock object, no stats are sent.
* @constructor
*/
var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock) {
var options = host || {},
self = this;

if(arguments.length > 1 || typeof(host) === 'string'){
options = {
host : host,
port : port,
prefix : prefix,
suffix : suffix,
globalize : globalize,
cacheDns : cacheDns,
mock : mock === true
};
}

this.host = options.host || 'localhost';
this.port = options.port || 8125;
this.prefix = options.prefix || '';
this.suffix = options.suffix || '';
this.socket = dgram.createSocket('udp4');
this.mock = options.mock;

if(options.cacheDns === true){
dns.lookup(options.host, function(err, address, family){
if(err == null){
self.host = address;
}
});
}

if(options.globalize){
global.statsd = this;
}
};

Object.keys(functions).forEach(function(fn) {
Client.prototype[fn] = functions[fn]('sendAll');
});

/**
* Checks if stats is an array and sends all stats calling back once all have sent
* @param stat {String|Array} The stat(s) to send
Expand Down Expand Up @@ -181,30 +199,70 @@ Client.prototype.sendAll = function(stat, value, type, sampleRate, tags, callbac

/**
* Sends a stat across the wire
* @param stat {String|Array} The stat(s) to send
* @param stat {String} The stat to send
* @param value The value to send
* @param type {String} The type of message to send to statsd
* @param sampleRate {Number} The Number of times to sample (0 to 1)
* @param tags {Array} The Array of tags to add to metrics
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.send = function (stat, value, type, sampleRate, tags, callback) {
var message = this.prefix + stat + this.suffix + ':' + value + '|' + type,
buf;
var message = this.message(stat, value, type, sampleRate, tags);
this.sendMessage(message, callback);
};

/**
* Checks if stat is an array and returns an array of messages
* @param stat {String|Array} The stat(s) to send
* @param value The value to send
* @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional.
* @param tags {Array=} The Array of tags to add to metrics. Optional.
*/
Client.prototype.allMessages = function(stat, value, type, sampleRate, tags) {
var self = this;
var stats = Array.isArray(stat) ? stat : [stat];
return stats.map(function(item) {
return self.message(item, value, type, sampleRate, tags);
}).filter(function(item) {
return !!item;
});
};

/**
* Creates the message
* @param stat {String} The stat to send
* @param value The value to send
* @param type {String} The type of message to send to statsd
* @param sampleRate {Number} The Number of times to sample (0 to 1)
* @param tags {Array} The Array of tags to add to metrics
*/
Client.prototype.message = function(stat, value, type, sampleRate, tags) {
var message = this.prefix + stat + this.suffix + ':' + value + '|' + type;

if(sampleRate && sampleRate < 1){
if(Math.random() < sampleRate){
message += '|@' + sampleRate;
} else {
//don't want to send if we don't meet the sample ratio
return;
return null;
}
}

if(tags && Array.isArray(tags)){
message += '|#' + tags.join(',');
}

return message;
};

/**
* Sends a stat message across the wire
* @param message {String} the full StatsD message
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.sendMessage = function(message, callback) {
var buf;

// Only send this stat if we're not a mock Client.
if(!this.mock) {
buf = new Buffer(message);
Expand All @@ -216,6 +274,13 @@ Client.prototype.send = function (stat, value, type, sampleRate, tags, callback)
}
};

/**
* Returns a multi object that allows you to send multiple metrics at once
*/
Client.prototype.multi = function() {
return new Multi(this);
};

/**
* Close the underlying socket and stop listening for data on it.
*/
Expand All @@ -224,3 +289,36 @@ Client.prototype.close = function(){
}

exports.StatsD = Client;

/**
* The Multi class that allows you to send multiple metrics at once
*/
var Multi = function (client) {
this.client = client;
this.messages = [];
};

/**
* Send the multi-metric
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Multi.prototype.send = function(callback) {
if (!this.messages.length) {
if(typeof callback === 'function'){
callback(null, 0);
}
return;
}

var message = this.messages.join('\n');
this.messages = [];
this.client.sendMessage(message, callback);
};

Object.keys(functions).forEach(function(fn) {
Multi.prototype[fn] = function() {
var messages = functions[fn]('allMessages').apply(this.client, arguments);
this.messages = this.messages.concat(messages);
};
});

Loading