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

Add support for TCP connections (as introduced in etsy/[email protected]) #67

Open
wants to merge 4 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
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
language: node_js

node_js:
- "0.6"
- "0.8"
- "0.10"
- "0.11"
- "0.12"
- "4"
- "5"
- "6"
- "7"

install:
- npm install
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A node.js client for [Etsy](http://etsy.com)'s [StatsD](https://github.com/etsy/

This client will let you fire stats at your StatsD server from a node.js application.

node-statsd Runs and is tested on Node 0.6+ on all *nix platforms and 0.8+ on all platforms including Windows.
node-statsd Runs and is tested on Node 0.10+ on all platforms including Windows.

[![Build Status](https://secure.travis-ci.org/sivy/node-statsd.png?branch=master)](http://travis-ci.org/sivy/node-statsd)

Expand All @@ -27,6 +27,7 @@ Parameters (specified as an options hash):
* `cacheDns`: Cache the initial dns lookup to *host* `default: false`
* `mock`: Create a mock StatsD instance, sending no stats to the server? `default: false`
* `global_tags`: Optional tags that will be added to every metric `default: []`
* `tcp`: Optional boolean indicating if the Client should use a TCP connection `default: false`

All StatsD methods have the same API:
* `name`: Stat name `required`
Expand Down
42 changes: 37 additions & 5 deletions lib/statsd.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var dgram = require('dgram'),
net = require('net'),
dns = require('dns');

/**
Expand All @@ -12,9 +13,10 @@ var dgram = require('dgram'),
* @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.
* @option global_tags {Array=} Optional tags that will be added to every metric
* @option tcp {boolean} An optional boolean indicating if the Client should use a TCP connection
* @constructor
*/
var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock, global_tags) {
var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock, global_tags, tcp) {
var options = host || {},
self = this;

Expand All @@ -27,17 +29,19 @@ var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock, gl
globalize : globalize,
cacheDns : cacheDns,
mock : mock === true,
global_tags : global_tags
global_tags : global_tags,
tcp : tcp
};
}

this.host = options.host || 'localhost';
this.port = options.port || 8125;
this.prefix = options.prefix || '';
this.suffix = options.suffix || '';
this.socket = dgram.createSocket('udp4');
this.socket = options.tcp ? net.connect(this.port, this.host) : dgram.createSocket('udp4');
this.mock = options.mock;
this.global_tags = options.global_tags || [];
this.tcp = options.tcp;

if(options.cacheDns === true){
dns.lookup(options.host, function(err, address, family){
Expand All @@ -50,6 +54,13 @@ var Client = function (host, port, prefix, suffix, globalize, cacheDns, mock, gl
if(options.globalize){
global.statsd = this;
}

if(options.tcp === true) {
// Catch global TCP connection errors
// We don't have a way to get them to the consumer, so just discard them
this.socket.on('error', function() {});
this.socket.setKeepAlive(true);
}
};

/**
Expand Down Expand Up @@ -167,7 +178,10 @@ Client.prototype.sendAll = function(stat, value, type, sampleRate, tags, callbac
return callback(error);
}

sentBytes += bytes;
if(bytes) {
sentBytes += bytes;
}

if(completed === stat.length){
callback(null, sentBytes);
}
Expand Down Expand Up @@ -215,10 +229,28 @@ Client.prototype.send = function (stat, value, type, sampleRate, tags, callback)
message += '|#' + merged_tags.join(',');
}

if(this.tcp) {
message += '\n';
}

this.sendRaw(message, callback);
}

/**
* Sends a stat across the wire
* @param message {String} The fully qualified stat to send [prefix]stat[suffix]:value|type[|@sampleRate][|#tags]
* @param callback {Function=} Callback when message is done being delivered. Optional.
*/
Client.prototype.sendRaw = function (message, callback) {

// Only send this stat if we're not a mock Client.
if(!this.mock) {
buf = new Buffer(message);
this.socket.send(buf, 0, buf.length, this.port, this.host, callback);
if(this.tcp) {
this.socket.write(buf, 'ascii', callback);
} else {
this.socket.send(buf, 0, buf.length, this.port, this.host, callback);
}
} else {
if(typeof callback === 'function'){
callback(null, 0);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
}
, "bugs" : { "url" : "https://github.com/sivy/node-statsd/issues" }
, "directories" : { "lib" : "./lib/" }
, "engines" : { "node" : ">=0.1.97" }
, "engines" : { "node" : ">=0.10" }
, "scripts": {
"test": "mocha -R spec"
}
Expand Down
Loading