Skip to content
This repository

Useful change for multiple data centers. #25

Closed
wants to merge 1 commit into from

3 participants

joethecodhr avleen Daniel Schauenberg
joethecodhr

Hello Etsy!

Dealnews ran into an issue where our VPN could not handle the amount of traffic that was being sent to StatsD from other data centers. As an alternative to sampling, we came up with the simple idea that StatsD could flush to itself.

Your feedback is welcomed!

joethecodhr

avleen
Owner
avleen commented July 16, 2011

So you have multiple statsd collectors, which then flush to a central statsd?
Was the problem you were having at the VPN caused by the packet/sec rate being too high?

joethecodhr

Correct. Our specific issue is a constraint that limits the number of open connections across our VPN.

Daniel Schauenberg
Owner
mrtazz commented June 18, 2012

Hey there is now a backend which allows StatsD to flush to itself (https://github.com/dynmeth/statsd-backend). Which I take to be more or less the same behaviour?

Daniel Schauenberg
Owner

I think the now existing Statsd backend and repeater support supersedes this pull request. Sorry that it didn't make it in :(.

Daniel Schauenberg mrtazz closed this November 03, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Jul 05, 2011
Adding support to allow StatsD to flush to StatsD. eeb9637
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 142 additions and 85 deletions. Show diff stats Hide diff stats

  1. 227  stats.js
227  stats.js
@@ -23,36 +23,47 @@ config.configFile(process.argv[2], function (config, oldConfig) {
23 23
   if (server === undefined) {
24 24
     server = dgram.createSocket('udp4', function (msg, rinfo) {
25 25
       if (config.dumpMessages) { sys.log(msg.toString()); }
26  
-      var bits = msg.toString().split(':');
27  
-      var key = bits.shift()
28  
-                    .replace(/\s+/g, '_')
29  
-                    .replace(/\//g, '-')
30  
-                    .replace(/[^a-zA-Z_\-0-9\.]/g, '');
31  
-
32  
-      if (bits.length == 0) {
33  
-        bits.push("1");
  26
+
  27
+      var messages = [];
  28
+
  29
+      if (msg.toString().indexOf(",") != -1) {
  30
+        messages = msg.toString().split(',');
  31
+      } else {
  32
+        messages.push(msg.toString());
34 33
       }
35 34
 
36  
-      for (var i = 0; i < bits.length; i++) {
37  
-        var sampleRate = 1;
38  
-        var fields = bits[i].split("|");
39  
-        if (fields[1] === undefined) {
  35
+      for (var j = 0; j < messages.length; j++) {
  36
+        var bits = messages[j].split(':');
  37
+        var key = bits.shift()
  38
+                      .replace(/\s+/g, '_')
  39
+                      .replace(/\//g, '-')
  40
+                      .replace(/[^a-zA-Z_\-0-9\.]/g, '');
  41
+
  42
+        if (bits.length == 0) {
  43
+          bits.push("1");
  44
+        }
  45
+
  46
+        for (var i = 0; i < bits.length; i++) {
  47
+          var sampleRate = 1;
  48
+          var fields = bits[i].split("|");
  49
+          if (fields[1] === undefined) {
40 50
             sys.log('Bad line: ' + fields);
41 51
             continue;
42  
-        }
43  
-        if (fields[1].trim() == "ms") {
44  
-          if (! timers[key]) {
45  
-            timers[key] = [];
46 52
           }
47  
-          timers[key].push(Number(fields[0] || 0));
48  
-        } else {
49  
-          if (fields[2] && fields[2].match(/^@([\d\.]+)/)) {
50  
-            sampleRate = Number(fields[2].match(/^@([\d\.]+)/)[1]);
51  
-          }
52  
-          if (! counters[key]) {
53  
-            counters[key] = 0;
  53
+          if (fields[1].trim() == "ms") {
  54
+            if (! timers[key]) {
  55
+              timers[key] = [];
  56
+            }
  57
+            timers[key].push(Number(fields[0] || 0));
  58
+          } else {
  59
+            if (fields[2] && fields[2].match(/^@([\d\.]+)/)) {
  60
+              sampleRate = Number(fields[2].match(/^@([\d\.]+)/)[1]);
  61
+            }
  62
+            if (! counters[key]) {
  63
+              counters[key] = 0;
  64
+            }
  65
+            counters[key] += Number(fields[0] || 1) * (1 / sampleRate);
54 66
           }
55  
-          counters[key] += Number(fields[0] || 1) * (1 / sampleRate);
56 67
         }
57 68
       }
58 69
     });
@@ -61,82 +72,128 @@ config.configFile(process.argv[2], function (config, oldConfig) {
61 72
 
62 73
     var flushInterval = Number(config.flushInterval || 10000);
63 74
 
64  
-    flushInt = setInterval(function () {
65  
-      var statString = '';
66  
-      var ts = Math.round(new Date().getTime() / 1000);
67  
-      var numStats = 0;
68  
-      var key;
  75
+    if (config.flushToStatsD) {
  76
+      flushInt = setInterval(function() {
  77
+        var statString = '';
  78
+        var messages = [];
69 79
 
70  
-      for (key in counters) {
71  
-        var value = counters[key] / (flushInterval / 1000);
72  
-        var message = 'stats.' + key + ' ' + value + ' ' + ts + "\n";
73  
-        message += 'stats_counts.' + key + ' ' + counters[key] + ' ' + ts + "\n";
74  
-        statString += message;
75  
-        counters[key] = 0;
  80
+        for (key in counters) {
  81
+          var value = counters[key];
76 82
 
77  
-        numStats += 1;
78  
-      }
  83
+          if (value == 0) {
  84
+            continue;
  85
+          }
  86
+
  87
+          messages.push(key + ':' + value + "|c");
  88
+          counters[key] = 0;
  89
+        }
  90
+            
  91
+        for (key in timers) {
  92
+          if (timers[key].length > 0) {
  93
+            for (var k = 0; k < timers[key].length; k++) {
  94
+              var value = timers[key][k];
  95
+
  96
+              if (value == 0) {
  97
+                continue;
  98
+              }
79 99
 
80  
-      for (key in timers) {
81  
-        if (timers[key].length > 0) {
82  
-          var pctThreshold = config.percentThreshold || 90;
83  
-          var values = timers[key].sort(function (a,b) { return a-b; });
84  
-          var count = values.length;
85  
-          var min = values[0];
86  
-          var max = values[count - 1];
87  
-
88  
-          var mean = min;
89  
-          var maxAtThreshold = max;
90  
-
91  
-          if (count > 1) {
92  
-            var thresholdIndex = Math.round(((100 - pctThreshold) / 100) * count);
93  
-            var numInThreshold = count - thresholdIndex;
94  
-            values = values.slice(0, numInThreshold);
95  
-            maxAtThreshold = values[numInThreshold - 1];
96  
-
97  
-            // average the remaining timings
98  
-            var sum = 0;
99  
-            for (var i = 0; i < numInThreshold; i++) {
100  
-              sum += values[i];
  100
+              messages.push(key + ':' + value + "|ms");
101 101
             }
102 102
 
103  
-            mean = sum / numInThreshold;
104  
-          }
  103
+            timers[key] = [];
  104
+	  }
  105
+	}
105 106
 
106  
-          timers[key] = [];
  107
+        statString = messages.join(",");
107 108
 
108  
-          var message = "";
109  
-          message += 'stats.timers.' + key + '.mean ' + mean + ' ' + ts + "\n";
110  
-          message += 'stats.timers.' + key + '.upper ' + max + ' ' + ts + "\n";
111  
-          message += 'stats.timers.' + key + '.upper_' + pctThreshold + ' ' + maxAtThreshold + ' ' + ts + "\n";
112  
-          message += 'stats.timers.' + key + '.lower ' + min + ' ' + ts + "\n";
113  
-          message += 'stats.timers.' + key + '.count ' + count + ' ' + ts + "\n";
  109
+        try {
  110
+          var socket = dgram.createSocket('udp4');
  111
+          var buf = new Buffer(statString);
  112
+          socket.send(buf, 0, buf.length, config.statsdPort, config.statsdHost);
  113
+          socket.close();
  114
+        } catch(e) {
  115
+          if (config.debug) {
  116
+            sys.log(e);
  117
+          }
  118
+        }
  119
+      }, flushInterval);
  120
+    } else {
  121
+      flushInt = setInterval(function () {
  122
+        var statString = '';
  123
+        var ts = Math.round(new Date().getTime() / 1000);
  124
+        var numStats = 0;
  125
+        var key;
  126
+
  127
+        for (key in counters) {
  128
+          var value = counters[key] / (flushInterval / 1000);
  129
+          var message = 'stats.' + key + ' ' + value + ' ' + ts + "\n";
  130
+          message += 'stats_counts.' + key + ' ' + counters[key] + ' ' + ts + "\n";
114 131
           statString += message;
  132
+          counters[key] = 0;
115 133
 
116 134
           numStats += 1;
117 135
         }
118  
-      }
119 136
 
120  
-      statString += 'statsd.numStats ' + numStats + ' ' + ts + "\n";
121  
-      
122  
-      try {
123  
-        var graphite = net.createConnection(config.graphitePort, config.graphiteHost);
124  
-        graphite.addListener('error', function(connectionException){
125  
-          if (config.debug) {
126  
-            sys.log(connectionException);
  137
+        for (key in timers) {
  138
+          if (timers[key].length > 0) {
  139
+            var pctThreshold = config.percentThreshold || 90;
  140
+            var values = timers[key].sort(function (a,b) { return a-b; });
  141
+            var count = values.length;
  142
+            var min = values[0];
  143
+            var max = values[count - 1];
  144
+
  145
+            var mean = min;
  146
+            var maxAtThreshold = max;
  147
+
  148
+            if (count > 1) {
  149
+              var thresholdIndex = Math.round(((100 - pctThreshold) / 100) * count);
  150
+              var numInThreshold = count - thresholdIndex;
  151
+              values = values.slice(0, numInThreshold);
  152
+              maxAtThreshold = values[numInThreshold - 1];
  153
+
  154
+              // average the remaining timings
  155
+              var sum = 0;
  156
+              for (var i = 0; i < numInThreshold; i++) {
  157
+                sum += values[i];
  158
+              }
  159
+
  160
+              mean = sum / numInThreshold;
  161
+            }
  162
+
  163
+            timers[key] = [];
  164
+
  165
+            var message = "";
  166
+            message += 'stats.timers.' + key + '.mean ' + mean + ' ' + ts + "\n";
  167
+            message += 'stats.timers.' + key + '.upper ' + max + ' ' + ts + "\n";
  168
+            message += 'stats.timers.' + key + '.upper_' + pctThreshold + ' ' + maxAtThreshold + ' ' + ts + "\n";
  169
+            message += 'stats.timers.' + key + '.lower ' + min + ' ' + ts + "\n";
  170
+            message += 'stats.timers.' + key + '.count ' + count + ' ' + ts + "\n";
  171
+            statString += message;
  172
+
  173
+            numStats += 1;
127 174
           }
128  
-        });
129  
-        graphite.on('connect', function() {
130  
-          this.write(statString);
131  
-          this.end();
132  
-        });
133  
-      } catch(e){
134  
-        if (config.debug) {
135  
-          sys.log(e);
136 175
         }
137  
-      }
138 176
 
139  
-    }, flushInterval);
  177
+        statString += 'statsd.numStats ' + numStats + ' ' + ts + "\n";
  178
+          
  179
+        try {
  180
+          var graphite = net.createConnection(config.graphitePort, config.graphiteHost);
  181
+          graphite.addListener('error', function(connectionException){
  182
+            if (config.debug) {
  183
+              sys.log(connectionException);
  184
+            }
  185
+          });
  186
+          graphite.on('connect', function() {
  187
+            this.write(statString);
  188
+            this.end();
  189
+          });
  190
+        } catch(e){
  191
+          if (config.debug) {
  192
+            sys.log(e);
  193
+          }
  194
+        }
  195
+      }, flushInterval);
  196
+    }
140 197
   }
141 198
 
142 199
 });
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.