|
14 | 14 | # statsd = Statsd.new('localhost').tap{|sd| sd.namespace = 'account'}
|
15 | 15 | # statsd.increment 'activate'
|
16 | 16 | class Statsd
|
| 17 | + class UDPClient |
| 18 | + attr_reader :sock |
| 19 | + |
| 20 | + def initialize(address, port = nil) |
| 21 | + address, port = address.split(':') if address.include?(':') |
| 22 | + addrinfo = Addrinfo.ip(address) |
| 23 | + |
| 24 | + @sock = UDPSocket.new(addrinfo.pfamily) |
| 25 | + @sock.connect(addrinfo.ip_address, port) |
| 26 | + end |
| 27 | + |
| 28 | + def send(msg) |
| 29 | + sock.write(msg) |
| 30 | + rescue SystemCallError |
| 31 | + nil |
| 32 | + end |
| 33 | + end |
| 34 | + |
17 | 35 | class SecureUDPClient < UDPClient
|
18 | 36 | def initialize(address, port, key)
|
19 | 37 | super(address, port)
|
@@ -51,24 +69,6 @@ def nonce
|
51 | 69 | end
|
52 | 70 | end
|
53 | 71 |
|
54 |
| - class UDPClient |
55 |
| - attr_reader :sock |
56 |
| - |
57 |
| - def initialize(address, port = nil) |
58 |
| - address, port = address.split(':') if address.include?(':') |
59 |
| - addrinfo = Addrinfo.ip(address) |
60 |
| - |
61 |
| - @sock = UDPSocket.new(addrinfo.pfamily) |
62 |
| - @sock.connect(addrinfo.ip_address, port) |
63 |
| - end |
64 |
| - |
65 |
| - def send(msg) |
66 |
| - sock.write(msg) |
67 |
| - rescue => boom |
68 |
| - nil |
69 |
| - end |
70 |
| - end |
71 |
| - |
72 | 72 | # A namespace to prepend to all statsd calls.
|
73 | 73 | attr_reader :namespace
|
74 | 74 |
|
@@ -103,6 +103,25 @@ def add_shard(*args)
|
103 | 103 | self
|
104 | 104 | end
|
105 | 105 |
|
| 106 | + def enable_buffering(buffer_size = nil) |
| 107 | + return if @buffering |
| 108 | + @shards.map! { |client| Buffer.new(client, buffer_size) } |
| 109 | + @buffering = true |
| 110 | + end |
| 111 | + |
| 112 | + def disable_buffering |
| 113 | + return unless @buffering |
| 114 | + flush_all |
| 115 | + @shards.map! { |client| client.base_client } |
| 116 | + @buffering = false |
| 117 | + end |
| 118 | + |
| 119 | + def flush_all |
| 120 | + return unless @buffering |
| 121 | + @shards.each { |client| client.flush } |
| 122 | + end |
| 123 | + |
| 124 | + |
106 | 125 | # Sends an increment (count = 1) for the given stat to the statsd server.
|
107 | 126 | #
|
108 | 127 | # @param stat (see #count)
|
@@ -200,4 +219,29 @@ def select_shard(stat)
|
200 | 219 | @shards[Zlib.crc32(stat) % @shards.size]
|
201 | 220 | end
|
202 | 221 | end
|
| 222 | + |
| 223 | + class Buffer |
| 224 | + DEFAULT_BUFFER_CAP = 512 |
| 225 | + |
| 226 | + attr_reader :base_client |
| 227 | + |
| 228 | + def initialize(client, buffer_cap = nil) |
| 229 | + @base_client = client |
| 230 | + @buffer = String.new |
| 231 | + @buffer_cap = buffer_cap || DEFAULT_BUFFER_CAP |
| 232 | + end |
| 233 | + |
| 234 | + def flush |
| 235 | + return unless @buffer.bytesize > 0 |
| 236 | + @base_client.send(@buffer) |
| 237 | + @buffer.clear |
| 238 | + end |
| 239 | + |
| 240 | + def send(msg) |
| 241 | + flush if @buffer.bytesize + msg.bytesize >= @buffer_cap |
| 242 | + @buffer << msg |
| 243 | + @buffer << "\n".freeze |
| 244 | + nil |
| 245 | + end |
| 246 | + end |
203 | 247 | end
|
0 commit comments