rack-statsd_batch 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rack::StatsdBatch
2
+
3
+ Throw your metrics data into your request env, and on egress it will get pushed
4
+ to statsd in as few requests as possible.
5
+
6
+ # Setup
7
+
8
+ Add to your gemfile
9
+
10
+ gem 'rack-statsd_batch', '~> 0.0.1', require: 'rack/statsd_batch'
11
+
12
+ Add to your middleware in config/application.rb
13
+
14
+ config.middleware.use Rack::StatsdBatch, 'statsd-server.myhost.com', 1234
15
+
16
+ # Use
17
+
18
+ The stats collector is included in your request environment. Access it from your
19
+ controller:
20
+
21
+ metrics = request.env['metrics']
22
+
23
+ There are five message types that map to the statsd backend
24
+
25
+ metrics.gauge_diff 'registered-users', +1
26
+ metrics.gauge 'total_things', 2037
27
+ metrics.timing 'render_time_ms', 237
28
+ metrics.count 'things_done', 1
29
+ metrics.sets 'user_ids', 27
@@ -0,0 +1,89 @@
1
+ require 'socket'
2
+
3
+ module Rack
4
+ class StatsdBatch
5
+ def initialize rack_app, hostname, port, mtu=1432
6
+ @app = rack_app
7
+ @hostname = hostname
8
+ @port = port
9
+ @mtu = mtu
10
+ end
11
+
12
+ def call env
13
+ env['metrics'] = Rack::StatsdBatch::Recorder.new
14
+ status, headers, response = @app.call(env)
15
+ env['metrics'].publish(@hostname, @port, @mtu)
16
+ [status, headers, response]
17
+ end
18
+
19
+ class Recorder
20
+ attr_reader :data
21
+
22
+ def initialize
23
+ @data = []
24
+ end
25
+
26
+ def count key, diff
27
+ @data << "#{key}:#{diff}|c"
28
+ end
29
+
30
+ def timing key, ms
31
+ @data << "#{key}:#{ms}|ms"
32
+ end
33
+
34
+ def gauge key, value
35
+ @data << "#{key}:#{value}|g"
36
+ end
37
+
38
+ def gauge_diff key, diff
39
+ value = "#{diff}"
40
+ value = "+#{value}" if diff > 0
41
+ @data << "#{key}:#{value}|g"
42
+ end
43
+
44
+ def sets key, set_entry
45
+ @data << "#{key}:#{set_entry}|s"
46
+ end
47
+
48
+ def publish host, port, mtu
49
+ return if @data.empty?
50
+ c = connection(host, port)
51
+ build_packets(mtu).each {|p| c.send(p) }
52
+ end
53
+
54
+ private
55
+
56
+ def connection host, port
57
+ Rack::StatsdBatch::Connection.new(UDPSocket.new, host, port)
58
+ end
59
+
60
+ def build_packets mtu
61
+ rv = []
62
+ packet = ''
63
+ while !data.empty?
64
+ message = data.shift
65
+ newline_length = packet.empty? ? 0 : 1
66
+ if packet.length + message.length + newline_length > mtu
67
+ rv << packet
68
+ packet = ''
69
+ end
70
+ message = "\n#{message}" unless packet.empty?
71
+ packet << message
72
+ end
73
+ (rv << packet) unless packet.empty?
74
+ rv
75
+ end
76
+ end
77
+
78
+ class Connection
79
+ def initialize socket, *extra_params
80
+ @socket = socket
81
+ @extras = extra_params
82
+ end
83
+
84
+ def send data
85
+ @socket.send(data, flags=0, *@extras)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0")
4
+
5
+ s.name = 'rack-statsd_batch'
6
+ s.version = '0.0.1'
7
+ s.date = '2013-12-13'
8
+
9
+ s.summary = 'Send metrics data to statsd after your request'
10
+ s.description = 'Exposes a metrics collector to the request environment and flushes the data to statsd when the request is finished. Batches the data to send as few packets as possible.'
11
+
12
+ s.authors = ['xtoddx (Todd Willey)']
13
+ s.email = 'xtoddx@gmail.com'
14
+ s.homepage = 'http://github.com/CirrusMio/rack-statsd_batch'
15
+ s.license = 'MIT'
16
+
17
+ s.require_paths = %w[lib]
18
+
19
+ s.add_development_dependency('minitest')
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- tests/*`.split("\n")
23
+ end
@@ -0,0 +1,46 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+
4
+ require_relative '../lib/rack/statsd_batch'
5
+
6
+ class ApplicationInterfaceTest < MiniTest::Test
7
+ def setup
8
+ @recorder = Rack::StatsdBatch::Recorder.new
9
+ end
10
+
11
+ def test_count
12
+ @recorder.count('mykey', 1)
13
+ assert_equal 1, @recorder.data.length
14
+ assert_equal 'mykey:1|c', @recorder.data.first
15
+ end
16
+
17
+ def test_timing
18
+ @recorder.timing('mykey', 1)
19
+ assert_equal 1, @recorder.data.length
20
+ assert_equal 'mykey:1|ms', @recorder.data.first
21
+ end
22
+
23
+ def test_gauge_diff_negative
24
+ @recorder.gauge_diff('mykey', 1)
25
+ assert_equal 1, @recorder.data.length
26
+ assert_equal 'mykey:+1|g', @recorder.data.first
27
+ end
28
+
29
+ def test_gauge_diff_negative
30
+ @recorder.gauge_diff('mykey', -1)
31
+ assert_equal 1, @recorder.data.length
32
+ assert_equal 'mykey:-1|g', @recorder.data.first
33
+ end
34
+
35
+ def test_gauge_set
36
+ @recorder.gauge('mykey', 10)
37
+ assert_equal 1, @recorder.data.length
38
+ assert_equal 'mykey:10|g', @recorder.data.first
39
+ end
40
+
41
+ def test_set_multiple_things
42
+ @recorder.gauge('mykey', 1)
43
+ @recorder.gauge_diff('myotherkey', 10)
44
+ assert_equal 2, @recorder.data.length
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+
4
+ require_relative '../lib/rack/statsd_batch'
5
+
6
+ $statsd_connection = nil
7
+ class TestConnection
8
+ attr_reader :packets
9
+
10
+ def initialize socket, host, port
11
+ $statsd_connection = self
12
+ end
13
+
14
+ def send packet
15
+ (@packets ||= []) << packet
16
+ end
17
+ end
18
+
19
+ class ConnectionTest < MiniTest::Test
20
+ def setup
21
+ @old_const = Rack::StatsdBatch::Connection
22
+ Rack::StatsdBatch.const_set :Connection, TestConnection
23
+ @recorder = Rack::StatsdBatch::Recorder.new
24
+ @recorder.gauge 'mygauge', 1
25
+ @recorder.gauge_diff 'myothergauge', 3
26
+ end
27
+
28
+ def teardown
29
+ Rack::StatsdBatch.const_set :Connection, @old_const
30
+ end
31
+
32
+ def test_sends_packet
33
+ @recorder.publish('hostname', port=1234, mtu=1024)
34
+ assert_equal 1, $statsd_connection.packets.length
35
+ assert_equal "mygauge:1|g\nmyothergauge:+3|g",
36
+ $statsd_connection.packets.first
37
+ end
38
+
39
+ def test_splits_packets
40
+ @recorder.publish('hostname', port=1234, mtu=@recorder.data.first.length)
41
+ assert_equal 2, $statsd_connection.packets.length
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+
4
+ require_relative '../lib/rack/statsd_batch'
5
+
6
+ class MiddlewareTestApp
7
+ attr_accessor :callback
8
+
9
+ def call env
10
+ if @callback
11
+ @callback.call(env)
12
+ end
13
+ return [{}, 200, '']
14
+ end
15
+ end
16
+
17
+ class MiddlewareTest < MiniTest::Test
18
+ def setup
19
+ @tester = MiddlewareTestApp.new
20
+ @app = Rack::StatsdBatch.new(@tester, 'localhost', 1234)
21
+ end
22
+
23
+ def test_env_contains_recorder
24
+ passed = nil
25
+ @tester.callback = ->(env){ passed = env.include?('metrics') }
26
+ @app.call({})
27
+ assert passed
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-statsd_batch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - xtoddx (Todd Willey)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Exposes a metrics collector to the request environment and flushes the
31
+ data to statsd when the request is finished. Batches the data to send as few packets
32
+ as possible.
33
+ email: xtoddx@gmail.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - README.md
39
+ - lib/rack/statsd_batch.rb
40
+ - rack-statsd_batch.gemspec
41
+ - test/application_interface_test.rb
42
+ - test/connection_test.rb
43
+ - test/middleware_test.rb
44
+ homepage: http://github.com/CirrusMio/rack-statsd_batch
45
+ licenses:
46
+ - MIT
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 1.8.25
66
+ signing_key:
67
+ specification_version: 2
68
+ summary: Send metrics data to statsd after your request
69
+ test_files: []
70
+ has_rdoc: