metriksd_reporter 0.5.0

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/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'rake', '0.8.7'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Eric Lindvall
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ # Metriks Server Reporter
2
+
3
+ A reporter to send metrics from [metriks][] to [metriksd][].
4
+
5
+
6
+ ## Usage
7
+
8
+ Add the gem to your `Gemfile`:
9
+
10
+ ``` ruby
11
+ gem 'metriksd_reporter'
12
+ ```
13
+
14
+ Use the reporter:
15
+
16
+ ``` ruby
17
+ reporter = MetriksdReporter.new(:host => 'metriksd.local', :port => 3331)
18
+ ```
19
+
20
+
21
+ # License
22
+
23
+ Copyright (c) 2012 Eric Lindvall
24
+
25
+ Published under the MIT License, see LICENSE
26
+
27
+ [metriks]: https://github.com/eric/metriks
28
+ [metriksd]: https://github.com/eric/metriksd
@@ -0,0 +1,144 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def gemspec_file
25
+ "#{name}.gemspec"
26
+ end
27
+
28
+ def gem_file
29
+ "#{name}-#{version}.gem"
30
+ end
31
+
32
+ def replace_header(head, header_name)
33
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
34
+ end
35
+
36
+ #############################################################################
37
+ #
38
+ # Standard tasks
39
+ #
40
+ #############################################################################
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/testtask'
45
+ Rake::TestTask.new(:test) do |test|
46
+ test.libs << 'lib' << 'test'
47
+ test.pattern = 'test/**/*_test.rb'
48
+ test.verbose = true
49
+ end
50
+
51
+ desc "Generate RCov test coverage and open in your browser"
52
+ task :coverage do
53
+ require 'rcov'
54
+ sh "rm -fr coverage"
55
+ sh "rcov test/test_*.rb"
56
+ sh "open coverage/index.html"
57
+ end
58
+
59
+ require 'rake/rdoctask'
60
+ Rake::RDocTask.new do |rdoc|
61
+ rdoc.rdoc_dir = 'rdoc'
62
+ rdoc.title = "#{name} #{version}"
63
+ rdoc.rdoc_files.include('README*')
64
+ rdoc.rdoc_files.include('lib/**/*.rb')
65
+ end
66
+
67
+ desc "Open an irb session preloaded with this library"
68
+ task :console do
69
+ sh "irb -rubygems -r ./lib/#{name}.rb"
70
+ end
71
+
72
+ #############################################################################
73
+ #
74
+ # Custom tasks (add your own tasks here)
75
+ #
76
+ #############################################################################
77
+
78
+
79
+
80
+ #############################################################################
81
+ #
82
+ # Packaging tasks
83
+ #
84
+ #############################################################################
85
+
86
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
87
+ task :release => :build do
88
+ unless `git branch` =~ /^\* master$/
89
+ puts "You must be on the master branch to release!"
90
+ exit!
91
+ end
92
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
93
+ sh "git tag v#{version}"
94
+ sh "git push origin master"
95
+ sh "git push origin v#{version}"
96
+ sh "gem push pkg/#{name}-#{version}.gem"
97
+ end
98
+
99
+ desc "Build #{gem_file} into the pkg directory"
100
+ task :build => :gemspec do
101
+ sh "mkdir -p pkg"
102
+ sh "gem build #{gemspec_file}"
103
+ sh "mv #{gem_file} pkg"
104
+ end
105
+
106
+ desc "Generate #{gemspec_file}"
107
+ task :gemspec => :validate do
108
+ # read spec file and split out manifest section
109
+ spec = File.read(gemspec_file)
110
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
111
+
112
+ # replace name version and date
113
+ replace_header(head, :name)
114
+ replace_header(head, :version)
115
+ replace_header(head, :date)
116
+
117
+ # determine file list from git ls-files
118
+ files = `git ls-files`.
119
+ split("\n").
120
+ sort.
121
+ reject { |file| file =~ /^\./ }.
122
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
123
+ map { |file| " #{file}" }.
124
+ join("\n")
125
+
126
+ # piece file back together and write
127
+ manifest = " s.files = %w[\n#{files}\n ]\n"
128
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
129
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
130
+ puts "Updated #{gemspec_file}"
131
+ end
132
+
133
+ desc "Validate #{gemspec_file}"
134
+ task :validate do
135
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
136
+ unless libfiles.empty?
137
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
138
+ exit!
139
+ end
140
+ unless Dir['VERSION*'].empty?
141
+ puts "A `VERSION` file at root level violates Gem best practices."
142
+ exit!
143
+ end
144
+ end
@@ -0,0 +1,9 @@
1
+ module MetriksdReporter
2
+ VERSION = '0.5.0'
3
+
4
+ def self.new(*args)
5
+ Reporter.new(*args)
6
+ end
7
+ end
8
+
9
+ require 'metriksd_reporter/reporter'
@@ -0,0 +1,197 @@
1
+ require 'snappy'
2
+ require 'msgpack'
3
+
4
+ module MetriksdReporter
5
+ class Reporter
6
+ def initialize(options = {})
7
+ missing_keys = %w(port host) - options.keys.map(&:to_s)
8
+ unless missing_keys.empty?
9
+ raise ArgumentError, "Missing required options: #{missing_keys * ', '}"
10
+ end
11
+
12
+ @port = options[:port]
13
+ @host = options[:host]
14
+
15
+ @client_id = options[:client_id] || "#{Socket.gethostname}:#{$$}"
16
+ @extras = options[:extras] || {}
17
+ @registry = options[:registry] || Metriks::Registry.default
18
+
19
+ @max_packet_size = options[:max_packet_size] || 1000
20
+ @interval = options[:interval] || 60
21
+ @interval_offset = options[:interval_offset] || 0
22
+ @flush_delay = options[:flush_delay] || 0.6
23
+
24
+ @on_error = options[:on_error] || proc { |ex| }
25
+ end
26
+
27
+ def start
28
+ @socket ||= UDPSocket.new
29
+
30
+ @thread ||= Thread.new do
31
+ loop do
32
+ sleep_until_deadline
33
+
34
+ begin
35
+ write
36
+ rescue Exception => ex
37
+ @on_error[ex] rescue nil
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def stop
44
+ if @thread
45
+ @thread.exit
46
+ @thread = nil
47
+ end
48
+
49
+ flush
50
+
51
+ if @socket
52
+ @socket.close
53
+ @socket = nil
54
+ end
55
+ end
56
+
57
+ def join
58
+ if @thread
59
+ @thread.join
60
+ end
61
+ end
62
+
63
+ def restart
64
+ stop
65
+ start
66
+ end
67
+
68
+ def flush
69
+ write
70
+ end
71
+
72
+ def write
73
+ @registry.each do |name, metric|
74
+ case metric
75
+ when Metriks::Meter
76
+ write_metric name, 'meter', metric, [
77
+ :count, :one_minute_rate, :five_minute_rate,
78
+ :fifteen_minute_rate, :mean_rate
79
+ ]
80
+ when Metriks::Counter
81
+ write_metric name, 'counter', metric, [
82
+ :count
83
+ ]
84
+ when Metriks::UtilizationTimer
85
+ write_metric name, 'utilization_timer', metric, [
86
+ :count, :one_minute_rate, :five_minute_rate,
87
+ :fifteen_minute_rate, :mean_rate,
88
+ :min, :max, :mean, :stddev,
89
+ :one_minute_utilization, :five_minute_utilization,
90
+ :fifteen_minute_utilization, :mean_utilization,
91
+ ], [
92
+ :median, :get_95th_percentile
93
+ ]
94
+ when Metriks::Timer
95
+ write_metric name, 'timer', metric, [
96
+ :count, :one_minute_rate, :five_minute_rate,
97
+ :fifteen_minute_rate, :mean_rate,
98
+ :min, :max, :mean, :stddev
99
+ ], [
100
+ :median, :get_95th_percentile
101
+ ]
102
+ when Metriks::Histogram
103
+ write_metric name, 'histogram', metric, [
104
+ :count, :min, :max, :mean, :stddev
105
+ ], [
106
+ :median, :get_95th_percentile
107
+ ]
108
+ end
109
+ end
110
+
111
+ flush_packet
112
+ end
113
+
114
+ def append_to_packet(data)
115
+ @packet ||= ''
116
+ @packet << data.to_msgpack
117
+ flush_packet_if_full
118
+ end
119
+
120
+ def flush_packet_if_full
121
+ if @packet && @packet.length > 0 && @packet.length > max_packet_size_with_compression_ratio
122
+ flush_packet
123
+ sleep_for_up_to(0.6)
124
+ end
125
+ end
126
+
127
+ def flush_packet
128
+ if @packet && @packet.length > 0
129
+ compressed = Snappy.deflate(@packet)
130
+
131
+ # Calculate the compression ratio
132
+ @compression_ratio = @packet.length / compressed.length
133
+
134
+ # Send the packet
135
+ @socket.send(compressed, 0, @host, @port)
136
+ @packet = ''
137
+ end
138
+ end
139
+
140
+ def max_packet_size_with_compression_ratio
141
+ if @compression_ratio
142
+ @max_packet_size * @compression_ratio * 0.9
143
+ else
144
+ @max_packet_size
145
+ end
146
+ end
147
+
148
+ def extract_from_metric(metric, *keys)
149
+ h = {}
150
+
151
+ keys.flatten.collect do |key|
152
+ name = key.to_s.gsub(/^get_/, '')
153
+ h[name] = metric.send(key)
154
+ end
155
+
156
+ h
157
+ end
158
+
159
+ def write_metric(name, type, metric, keys, snapshot_keys = [])
160
+ message = @extras.merge(
161
+ :client_id => @client_id,
162
+ :time => Time.now.to_i,
163
+ :name => name,
164
+ :type => type
165
+ )
166
+
167
+ message.merge!(extract_from_metric(metric, keys))
168
+
169
+ unless snapshot_keys.empty?
170
+ snapshot = metric.snapshot
171
+ message.merge!(extract_from_metric(snapshot, snapshot_keys))
172
+ end
173
+
174
+ append_to_packet(message)
175
+ end
176
+
177
+ def sleep_until_deadline
178
+ # Ensure we round up when we should
179
+ now = Time.now.to_f + @interval_offset
180
+
181
+ rounded = now - (now % @interval)
182
+ next_rounded = rounded + @interval - @interval_offset
183
+ sleep_time = next_rounded - Time.now.to_f
184
+
185
+ if sleep_time > 0
186
+ sleep(sleep_time)
187
+ end
188
+ end
189
+
190
+ def sleep_for_up_to(duration)
191
+ duration *= rand
192
+ if duration > 0
193
+ sleep(duration)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,77 @@
1
+ ## This is the rakegem gemspec template. Make sure you read and understand
2
+ ## all of the comments. Some sections require modification, and others can
3
+ ## be deleted if you don't need them. Once you understand the contents of
4
+ ## this file, feel free to delete any comments that begin with two hash marks.
5
+ ## You can find comprehensive Gem::Specification documentation, at
6
+ ## http://docs.rubygems.org/read/chapter/20
7
+ Gem::Specification.new do |s|
8
+ s.specification_version = 2 if s.respond_to? :specification_version=
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.rubygems_version = '1.3.5'
11
+
12
+ ## Leave these as is they will be modified for you by the rake gemspec task.
13
+ ## If your rubyforge_project name is different, then edit it and comment out
14
+ ## the sub! line in the Rakefile
15
+ s.name = 'metriksd_reporter'
16
+ s.version = '0.5.0'
17
+ s.date = '2012-07-29'
18
+
19
+ ## Make sure your summary is short. The description may be as long
20
+ ## as you like.
21
+ s.summary = "Metriks reporter for Metriks Server"
22
+ s.description = "Reporter component for the metriks metrics library to report to a metriks server"
23
+
24
+ ## List the primary authors. If there are a bunch of authors, it's probably
25
+ ## better to set the email to an email list or something. If you don't have
26
+ ## a custom homepage, consider using your GitHub URL or the like.
27
+ s.authors = ["Eric Lindvall"]
28
+ s.email = 'eric@sevenscale.com'
29
+ s.homepage = 'https://github.com/eric/metriks_server_reporter'
30
+
31
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
32
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
33
+ s.require_paths = %w[lib]
34
+
35
+ ## This sections is only necessary if you have C extensions.
36
+ # s.require_paths << 'ext'
37
+ # s.extensions = %w[ext/extconf.rb]
38
+
39
+ ## If your gem includes any executables, list them here.
40
+ # s.executables = ["name"]
41
+
42
+ ## Specify any RDoc options here. You'll want to add your README and
43
+ ## LICENSE files to the extra_rdoc_files list.
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.extra_rdoc_files = %w[README.md LICENSE]
46
+
47
+ ## List your runtime dependencies here. Runtime dependencies are those
48
+ ## that are needed for an end user to actually USE your code.
49
+ s.add_dependency('metriks', '>= 0.9.9')
50
+ s.add_dependency('snappy')
51
+ s.add_dependency('msgpack')
52
+
53
+ ## List your development dependencies here. Development dependencies are
54
+ ## those that are only needed during development
55
+ # s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
56
+
57
+ ## Leave this section as-is. It will be automatically generated from the
58
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
59
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
60
+ # = MANIFEST =
61
+ s.files = %w[
62
+ Gemfile
63
+ LICENSE
64
+ README.md
65
+ Rakefile
66
+ lib/metriksd_reporter.rb
67
+ lib/metriksd_reporter/reporter.rb
68
+ metriksd_reporter.gemspec
69
+ test/metriksd_reporter_test.rb
70
+ test/test_helper.rb
71
+ ]
72
+ # = MANIFEST =
73
+
74
+ ## Test files will be grabbed from the file list. Make sure the path glob
75
+ ## matches what you actually use.
76
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
77
+ end
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+ require 'metriks'
3
+
4
+ class MetriksdReporterTest < Test::Unit::TestCase
5
+ def setup
6
+ @registry = Metriks::Registry.new
7
+ @reporter = MetriksdReporter.new(:host => '127.0.0.1', :port => 8372, :registry => @registry)
8
+ end
9
+
10
+ def test_basic
11
+ @reporter.start
12
+ @registry.timer('testing').update(4)
13
+ @reporter.stop
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'pp'
3
+
4
+ # require 'mocha'
5
+
6
+ require 'metriksd_reporter'
7
+
8
+ Thread.abort_on_exception = true
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metriksd_reporter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 5
8
+ - 0
9
+ version: 0.5.0
10
+ platform: ruby
11
+ authors:
12
+ - Eric Lindvall
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-07-29 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ - 9
29
+ - 9
30
+ version: 0.9.9
31
+ name: metriks
32
+ requirement: *id001
33
+ prerelease: false
34
+ - !ruby/object:Gem::Dependency
35
+ type: :runtime
36
+ version_requirements: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ name: snappy
44
+ requirement: *id002
45
+ prerelease: false
46
+ - !ruby/object:Gem::Dependency
47
+ type: :runtime
48
+ version_requirements: &id003 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ name: msgpack
56
+ requirement: *id003
57
+ prerelease: false
58
+ description: Reporter component for the metriks metrics library to report to a metriks server
59
+ email: eric@sevenscale.com
60
+ executables: []
61
+
62
+ extensions: []
63
+
64
+ extra_rdoc_files:
65
+ - README.md
66
+ - LICENSE
67
+ files:
68
+ - Gemfile
69
+ - LICENSE
70
+ - README.md
71
+ - Rakefile
72
+ - lib/metriksd_reporter.rb
73
+ - lib/metriksd_reporter/reporter.rb
74
+ - metriksd_reporter.gemspec
75
+ - test/metriksd_reporter_test.rb
76
+ - test/test_helper.rb
77
+ has_rdoc: true
78
+ homepage: https://github.com/eric/metriks_server_reporter
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 2
106
+ summary: Metriks reporter for Metriks Server
107
+ test_files:
108
+ - test/test_helper.rb