forked from iFixit/statsd-php-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
StatsD.php
214 lines (192 loc) · 6.27 KB
/
StatsD.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<?php
/**
* Sends statistics to an instance of the statsd daemon over UDP
*
* Make changes here: https://github.com/iFixit/statsd-php-client
* See: https://github.com/etsy/statsd
**/
class StatsD {
protected static $host = 'localhost';
protected static $port = '8125';
const MAX_PACKET_SIZE = 512;
/**
* If true, stats are added to a queue until a flush is triggered
* If false, stats are sent immediately, one UDP packet per call
*/
protected static $addStatsToQueue = false;
protected static $queuedStats = array();
protected static $queuedCounters = array();
/**
* Log timing information
*
* @param string $stats The metric to in log timing info for.
* @param float $time The ellapsed time (ms) to log
* @param float|1 $sampleRate the rate (0-1) for sampling.
**/
public static function timing($stat, $time, $sampleRate=1) {
static::queueStats(array($stat => self::num($time) . "|ms"), $sampleRate);
}
/**
* Report the current value of some gauged value.
*
* @param string|array $stat The metric to report ong
* @param integer $value The value for this gauge
*/
public static function gauge($stat, $value) {
static::queueStats(array($stat => self::num($value) . "|g"));
}
/**
* Increments one or more stats counters
*
* @param string|array $stats The metric(s) to increment.
* @param float|1 $sampleRate the rate (0-1) for sampling.
* @return boolean
**/
public static function increment($stats, $sampleRate=1) {
static::updateStat($stats, 1, $sampleRate);
}
/**
* Decrements one or more stats counters.
*
* @param string|array $stats The metric(s) to decrement.
* @param float|1 $sampleRate the rate (0-1) for sampling.
* @return boolean
**/
public static function decrement($stats, $sampleRate=1) {
static::updateStat($stats, -1, $sampleRate);
}
/**
* Pause and collect all reported stats until flushStatsOutput() is called.
*/
public static function pauseStatsOutput() {
static::$addStatsToQueue = true;
}
/**
* Send all stats generated AFTER a call to pauseStatsOutput()
* and resume immediate sending again.
*/
public static function flushStatsOutput() {
static::$addStatsToQueue = false;
static::sendAllStats();
}
/**
* Updates a counter by an arbitrary amount.
*
* @param string|array $stats The metric(s) to update. Should be either a string or array of metrics.
* @param int|1 $delta The amount to increment/decrement each metric by.
* @param float|1 $sampleRate the rate (0-1) for sampling.
* @return boolean
**/
public static function updateStat($stat, $delta=1, $sampleRate=1) {
$deltaStr = self::num($delta);
if ($sampleRate < 1) {
if ((mt_rand() / mt_getrandmax()) <= $sampleRate) {
static::$queuedStats[] = "$stat:$deltaStr|c|@". self::num($sampleRate);
}
} else {
if (!isset(static::$queuedCounters[$stat])) {
static::$queuedCounters[$stat] = 0;
}
static::$queuedCounters[$stat] += $delta;
}
if (!static::$addStatsToQueue) {
static::sendAllStats();
}
}
/**
* Deprecated, works, but will be removed in the future.
*/
public static function updateStats($stats, $delta=1, $sampleRate=1) {
if (!is_array($stats)) {
return self::updateStat($stats, $delta, $sampleRate);
}
foreach($stats as $stat) {
self::updateStat($stat, $delta, $sampleRate);
}
}
/**
* Add stats to the queue or send them immediately depending on
* self::$addStatsToQueue
*/
protected static function queueStats($data, $sampleRate=1) {
if ($sampleRate < 1) {
foreach ($data as $stat => $value) {
if ((mt_rand() / mt_getrandmax()) <= $sampleRate) {
static::$queuedStats[] = "$stat:$value|@". self::num($sampleRate);
}
}
} else {
foreach($data as $stat => $value) {
static::$queuedStats[] = "$stat:$value";
}
}
if (!static::$addStatsToQueue) {
static::sendAllStats();
}
}
/**
* Flush the queue and send all the stats we have.
*/
protected static function sendAllStats() {
if (empty(static::$queuedStats) && empty(static::$queuedCounters))
return;
foreach(static::$queuedCounters as $stat => $value) {
$line = "$stat:$value|c";
static::$queuedStats[] = $line;
}
self::sendLines(static::$queuedStats);
static::$queuedStats = array();
static::$queuedCounters = array();
}
/**
* Squirt the metrics over UDP
*/
protected static function sendAsUDP($data) {
// Wrap this in a try/catch -
// failures in any of this should be silently ignored
try {
$host = static::$host;
$port = static::$port;
$fp = fsockopen("udp://$host", $port, $errno, $errstr);
if (! $fp) { return; }
// Non-blocking I/O, please.
stream_set_blocking($fp, 0);
fwrite($fp, $data);
fclose($fp);
} catch (Exception $e) {
}
}
/**
* Send these lines via UDP in groups of self::MAX_PACKET_SIZE bytes
* Sending UDP packets bigger than ~500-1000 bytes will mean the packets
* get fragmented, and if ONE fragment doesn't make it, the whole datagram
* is thrown out.
*/
protected static function sendLines($lines) {
$out = array();
$chunkSize = 0;
$i = 0; $lineCount = count($lines);
while ($i < $lineCount) {
$line = $lines[$i];
$len = strlen($line) + 1;
$chunkSize += $len;
if ($chunkSize > self::MAX_PACKET_SIZE) {
static::sendAsUDP(implode("\n", $out));
$out = array($line);
$chunkSize = $len;
} else {
$out[] = $line;
}
$i++;
}
static::sendAsUDP(implode("\n", $out));
}
/**
* This is the fastest way to ensure locale settings don't affect the
* decimal separator. Really, this is the only way (besides temporarily
* changing the locale) to really get what we want.
*/
protected static function num($value) {
return strtr($value, ',', '.');
}
}