rubycut-metriks 0.9.9.4

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.
@@ -0,0 +1,119 @@
1
+ require 'socket'
2
+
3
+ module Metriks::Reporter
4
+ class Graphite
5
+ attr_reader :host, :port
6
+
7
+ def initialize(host, port, options = {})
8
+ @host = host
9
+ @port = port
10
+
11
+ @prefix = options[:prefix]
12
+
13
+ @registry = options[:registry] || Metriks::Registry.default
14
+ @interval = options[:interval] || 60
15
+ @on_error = options[:on_error] || proc { |ex| }
16
+ end
17
+
18
+ def socket
19
+ @socket = nil if @socket && @socket.closed?
20
+ @socket ||= TCPSocket.new(@host, @port)
21
+ end
22
+
23
+ def start
24
+ @thread ||= Thread.new do
25
+ loop do
26
+ sleep @interval
27
+
28
+ Thread.new do
29
+ begin
30
+ write
31
+ rescue Exception => ex
32
+ @on_error[ex] rescue nil
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ def stop
40
+ @thread.kill if @thread
41
+ @thread = nil
42
+ end
43
+
44
+ def restart
45
+ stop
46
+ start
47
+ end
48
+
49
+ def write
50
+ @registry.each do |name, metric|
51
+ case metric
52
+ when Metriks::Meter
53
+ write_metric name, metric, [
54
+ :count, :one_minute_rate, :five_minute_rate,
55
+ :fifteen_minute_rate, :mean_rate
56
+ ]
57
+ when Metriks::Counter
58
+ write_metric name, metric, [
59
+ :count
60
+ ]
61
+ when Metriks::Gauge
62
+ write_metric name, metric, [
63
+ :value
64
+ ]
65
+ when Metriks::UtilizationTimer
66
+ write_metric name, metric, [
67
+ :count, :one_minute_rate, :five_minute_rate,
68
+ :fifteen_minute_rate, :mean_rate,
69
+ :min, :max, :mean, :stddev,
70
+ :one_minute_utilization, :five_minute_utilization,
71
+ :fifteen_minute_utilization, :mean_utilization,
72
+ ], [
73
+ :median, :get_95th_percentile
74
+ ]
75
+ when Metriks::Timer
76
+ write_metric name, metric, [
77
+ :count, :one_minute_rate, :five_minute_rate,
78
+ :fifteen_minute_rate, :mean_rate,
79
+ :min, :max, :mean, :stddev
80
+ ], [
81
+ :median, :get_95th_percentile
82
+ ]
83
+ when Metriks::Histogram
84
+ write_metric name, metric, [
85
+ :count, :min, :max, :mean, :stddev
86
+ ], [
87
+ :median, :get_95th_percentile
88
+ ]
89
+ end
90
+ end
91
+ end
92
+
93
+ def write_metric(base_name, metric, keys, snapshot_keys = [])
94
+ time = Time.now.to_i
95
+
96
+ base_name = base_name.to_s.gsub(/ +/, '_')
97
+ if @prefix
98
+ base_name = "#{@prefix}.#{base_name}"
99
+ end
100
+
101
+ keys.flatten.each do |key|
102
+ name = key.to_s.gsub(/^get_/, '')
103
+ value = metric.send(key)
104
+ socket.write("#{base_name}.#{name} #{value} #{time}\n")
105
+ end
106
+
107
+ unless snapshot_keys.empty?
108
+ snapshot = metric.snapshot
109
+ snapshot_keys.flatten.each do |key|
110
+ name = key.to_s.gsub(/^get_/, '')
111
+ value = snapshot.send(key)
112
+ socket.write("#{base_name}.#{name} #{value} #{time}\n")
113
+ end
114
+ end
115
+ rescue Errno::EPIPE
116
+ socket.close
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,185 @@
1
+ require 'metriks/time_tracker'
2
+ require 'net/https'
3
+
4
+ module Metriks::Reporter
5
+ class LibratoMetrics
6
+ attr_accessor :prefix, :source
7
+
8
+ def initialize(email, token, options = {})
9
+ @email = email
10
+ @token = token
11
+
12
+ @prefix = options[:prefix]
13
+ @source = options[:source]
14
+
15
+ @registry = options[:registry] || Metriks::Registry.default
16
+ @time_tracker = Metriks::TimeTracker.new(options[:interval] || 60)
17
+ @on_error = options[:on_error] || proc { |ex| }
18
+ end
19
+
20
+ def start
21
+ @thread ||= Thread.new do
22
+ loop do
23
+ @time_tracker.sleep
24
+
25
+ Thread.new do
26
+ begin
27
+ write
28
+ rescue Exception => ex
29
+ @on_error[ex] rescue nil
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def stop
37
+ @thread.kill if @thread
38
+ @thread = nil
39
+ end
40
+
41
+ def restart
42
+ stop
43
+ start
44
+ end
45
+
46
+ def write
47
+ gauges = []
48
+ @registry.each do |name, metric|
49
+ gauges << case metric
50
+ when Metriks::Meter
51
+ prepare_metric name, metric, [
52
+ :count, :one_minute_rate, :five_minute_rate,
53
+ :fifteen_minute_rate, :mean_rate
54
+ ]
55
+ when Metriks::Counter
56
+ prepare_metric name, metric, [
57
+ :count
58
+ ]
59
+ when Metriks::Gauge
60
+ prepare_metric name, metric, [
61
+ :value
62
+ ]
63
+ when Metriks::UtilizationTimer
64
+ prepare_metric name, metric, [
65
+ :count, :one_minute_rate, :five_minute_rate,
66
+ :fifteen_minute_rate, :mean_rate,
67
+ :min, :max, :mean, :stddev,
68
+ :one_minute_utilization, :five_minute_utilization,
69
+ :fifteen_minute_utilization, :mean_utilization,
70
+ ], [
71
+ :median, :get_95th_percentile
72
+ ]
73
+ when Metriks::Timer
74
+ prepare_metric name, metric, [
75
+ :count, :one_minute_rate, :five_minute_rate,
76
+ :fifteen_minute_rate, :mean_rate,
77
+ :min, :max, :mean, :stddev
78
+ ], [
79
+ :median, :get_95th_percentile
80
+ ]
81
+ when Metriks::Histogram
82
+ prepare_metric name, metric, [
83
+ :count, :min, :max, :mean, :stddev
84
+ ], [
85
+ :median, :get_95th_percentile
86
+ ]
87
+ end
88
+ end
89
+
90
+ gauges.flatten!
91
+
92
+ unless gauges.empty?
93
+ submit(form_data(gauges.flatten))
94
+ end
95
+ end
96
+
97
+ def submit(data)
98
+ url = URI.parse('https://metrics-api.librato.com/v1/metrics')
99
+ req = Net::HTTP::Post.new(url.path)
100
+ req.basic_auth(@email, @token)
101
+ req.set_form_data(data)
102
+
103
+ http = Net::HTTP.new(url.host, url.port)
104
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
105
+ http.use_ssl = true
106
+ store = OpenSSL::X509::Store.new
107
+ store.set_default_paths
108
+ http.cert_store = store
109
+
110
+ case res = http.start { |http| http.request(req) }
111
+ when Net::HTTPSuccess, Net::HTTPRedirection
112
+ # OK
113
+ else
114
+ res.error!
115
+ end
116
+ end
117
+
118
+ def form_data(metrics)
119
+ data = {}
120
+
121
+ gauges = metrics.select { |m| m[:type] == "gauge" }
122
+
123
+ gauges.each_with_index do |gauge, idx|
124
+ gauge.each do |key, value|
125
+ if value
126
+ data["gauges[#{idx}][#{key}]"] = value.to_s
127
+ end
128
+ end
129
+ end
130
+
131
+ counters = metrics.select { |m| m[:type] == "counter" }
132
+
133
+ counters.each_with_index do |counter, idx|
134
+ counter.each do |key, value|
135
+ if value
136
+ data["counters[#{idx}][#{key}]"] = value.to_s
137
+ end
138
+ end
139
+ end
140
+
141
+ data
142
+ end
143
+
144
+ def prepare_metric(base_name, metric, keys, snapshot_keys = [])
145
+ results = []
146
+ time = @time_tracker.now_floored
147
+
148
+ base_name = base_name.to_s.gsub(/ +/, '_')
149
+ if @prefix
150
+ base_name = "#{@prefix}.#{base_name}"
151
+ end
152
+
153
+ keys.flatten.each do |key|
154
+ name = key.to_s.gsub(/^get_/, '')
155
+ value = metric.send(key)
156
+
157
+ results << {
158
+ :type => name.to_s == "count" ? "counter" : "gauge",
159
+ :name => "#{base_name}.#{name}",
160
+ :source => @source,
161
+ :measure_time => time,
162
+ :value => value
163
+ }
164
+ end
165
+
166
+ unless snapshot_keys.empty?
167
+ snapshot = metric.snapshot
168
+ snapshot_keys.flatten.each do |key|
169
+ name = key.to_s.gsub(/^get_/, '')
170
+ value = snapshot.send(key)
171
+
172
+ results << {
173
+ :type => name.to_s == "count" ? "counter" : "gauge",
174
+ :name => "#{base_name}.#{name}",
175
+ :source => @source,
176
+ :measure_time => time,
177
+ :value => value
178
+ }
179
+ end
180
+ end
181
+
182
+ results
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,129 @@
1
+ require 'logger'
2
+ require 'metriks/time_tracker'
3
+
4
+ module Metriks::Reporter
5
+ class Logger
6
+ attr_accessor :prefix, :log_level, :logger
7
+
8
+ def initialize(options = {})
9
+ @logger = options[:logger] || ::Logger.new(STDOUT)
10
+ @log_level = options[:log_level] || ::Logger::INFO
11
+ @prefix = options[:prefix] || 'metriks:'
12
+
13
+ @registry = options[:registry] || Metriks::Registry.default
14
+ @time_tracker = Metriks::TimeTracker.new(options[:interval] || 60)
15
+ @on_error = options[:on_error] || proc { |ex| }
16
+ end
17
+
18
+ def start
19
+ @thread ||= Thread.new do
20
+ loop do
21
+ @time_tracker.sleep
22
+
23
+ begin
24
+ write
25
+ rescue Exception => ex
26
+ @on_error[ex] rescue nil
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def stop
33
+ @thread.kill if @thread
34
+ @thread = nil
35
+ end
36
+
37
+ def restart
38
+ stop
39
+ start
40
+ end
41
+
42
+ def flush
43
+ if !@last_write || @last_write.min != Time.now.min
44
+ write
45
+ end
46
+ end
47
+
48
+ def write
49
+ @last_write = Time.now
50
+
51
+ @registry.each do |name, metric|
52
+ case metric
53
+ when Metriks::Meter
54
+ log_metric name, 'meter', metric, [
55
+ :count, :one_minute_rate, :five_minute_rate,
56
+ :fifteen_minute_rate, :mean_rate
57
+ ]
58
+ when Metriks::Counter
59
+ log_metric name, 'counter', metric, [
60
+ :count
61
+ ]
62
+ when Metriks::Gauge
63
+ log_metric name, 'gauge', metric, [
64
+ :value
65
+ ]
66
+ when Metriks::UtilizationTimer
67
+ log_metric name, 'utilization_timer', metric, [
68
+ :count, :one_minute_rate, :five_minute_rate,
69
+ :fifteen_minute_rate, :mean_rate,
70
+ :min, :max, :mean, :stddev,
71
+ :one_minute_utilization, :five_minute_utilization,
72
+ :fifteen_minute_utilization, :mean_utilization,
73
+ ], [
74
+ :median, :get_95th_percentile
75
+ ]
76
+ when Metriks::Timer
77
+ log_metric name, 'timer', metric, [
78
+ :count, :one_minute_rate, :five_minute_rate,
79
+ :fifteen_minute_rate, :mean_rate,
80
+ :min, :max, :mean, :stddev
81
+ ], [
82
+ :median, :get_95th_percentile
83
+ ]
84
+ when Metriks::Histogram
85
+ log_metric name, 'histogram', metric, [
86
+ :count, :min, :max, :mean, :stddev
87
+ ], [
88
+ :median, :get_95th_percentile
89
+ ]
90
+ end
91
+ end
92
+ end
93
+
94
+ def extract_from_metric(metric, *keys)
95
+ keys.flatten.collect do |key|
96
+ name = key.to_s.gsub(/^get_/, '')
97
+ [ { name => metric.send(key) } ]
98
+ end
99
+ end
100
+
101
+ def log_metric(name, type, metric, keys, snapshot_keys = [])
102
+ message = []
103
+
104
+ message << @prefix if @prefix
105
+ message << { :time => Time.now.to_i }
106
+
107
+ message << { :name => name }
108
+ message << { :type => type }
109
+ message += extract_from_metric(metric, keys)
110
+
111
+ unless snapshot_keys.empty?
112
+ snapshot = metric.snapshot
113
+ message += extract_from_metric(snapshot, snapshot_keys)
114
+ end
115
+
116
+ @logger.add(@log_level, format_message(message))
117
+ end
118
+
119
+ def format_message(args)
120
+ args.map do |arg|
121
+ case arg
122
+ when Hash then arg.map { |name, value| "#{name}=#{format_message([value])}" }
123
+ when Array then format_message(arg)
124
+ else arg
125
+ end
126
+ end.join(' ')
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,65 @@
1
+ module Metriks::Reporter
2
+ class ProcTitle
3
+ def initialize(options = {})
4
+ @rounding = options[:rounding] || 1
5
+ @prefix = options[:prefix] || $0.dup
6
+
7
+ @interval = options[:interval] || 5
8
+ @on_error = options[:on_error] || proc { |ex| }
9
+
10
+ @metrics = []
11
+ end
12
+
13
+ def add(name, suffix = nil, &block)
14
+ @metrics << [ name, suffix, block ]
15
+ end
16
+
17
+ def empty?
18
+ @metrics.empty?
19
+ end
20
+
21
+ def start
22
+ @thread ||= Thread.new do
23
+ loop do
24
+ begin
25
+ unless @metrics.empty?
26
+ title = generate_title
27
+ if title && !title.empty?
28
+ $0 = "#{@prefix} #{title}"
29
+ end
30
+ end
31
+ rescue Exception => ex
32
+ @on_error[ex] rescue nil
33
+ end
34
+ sleep @interval
35
+ end
36
+ end
37
+ end
38
+
39
+ def stop
40
+ @thread.kill if @thread
41
+ @thread = nil
42
+ end
43
+
44
+ def restart
45
+ stop
46
+ start
47
+ end
48
+
49
+ protected
50
+ def generate_title
51
+ @metrics.collect do |name, suffix, block|
52
+ val = block.call
53
+ val = "%.#{@rounding}f" % val if val.is_a?(Float)
54
+
55
+ if suffix == '%'
56
+ "#{name}: #{val}#{suffix}"
57
+ elsif suffix
58
+ "#{name}: #{val}/#{suffix}"
59
+ else
60
+ "#{name}: #{val}"
61
+ end
62
+ end.join(' ')
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,119 @@
1
+ module Metriks::Reporter
2
+ class Riemann
3
+ require 'riemann/client'
4
+
5
+ attr_accessor :client
6
+ def initialize(options = {})
7
+ @client = ::Riemann::Client.new(
8
+ :host => options[:host],
9
+ :port => options[:port]
10
+ )
11
+ @registry = options[:registry] || Metriks::Registry.default
12
+ @interval = options[:interval] || 60
13
+ @on_error = options[:on_error] || proc { |ex| }
14
+
15
+ @default_event = options[:default_event] || {}
16
+ @default_event[:ttl] ||= @interval * 1.5
17
+ end
18
+
19
+ def start
20
+ @thread ||= Thread.new do
21
+ loop do
22
+ sleep @interval
23
+
24
+ Thread.new do
25
+ begin
26
+ write
27
+ rescue Exception => ex
28
+ @on_error[ex] rescue nil
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def stop
36
+ @thread.kill if @thread
37
+ @thread = nil
38
+ end
39
+
40
+ def restart
41
+ stop
42
+ start
43
+ end
44
+
45
+ def flush
46
+ # Is this supposed to take interval into account? --aphyr
47
+ if !@last_write || @last_write.min != Time.now.min
48
+ write
49
+ end
50
+ end
51
+
52
+ def write
53
+ @last_write = Time.now
54
+
55
+ @registry.each do |name, metric|
56
+ case metric
57
+ when Metriks::Meter
58
+ send_metric name, 'meter', metric, [
59
+ :count, :one_minute_rate, :five_minute_rate,
60
+ :fifteen_minute_rate, :mean_rate
61
+ ]
62
+ when Metriks::Counter
63
+ send_metric name, 'counter', metric, [
64
+ :count
65
+ ]
66
+ when Metriks::Gauge
67
+ send_metric name, 'gauge', metric, [
68
+ :value
69
+ ]
70
+ when Metriks::UtilizationTimer
71
+ send_metric name, 'utilization_timer', metric, [
72
+ :count, :one_minute_rate, :five_minute_rate,
73
+ :fifteen_minute_rate, :mean_rate,
74
+ :min, :max, :mean, :stddev,
75
+ :one_minute_utilization, :five_minute_utilization,
76
+ :fifteen_minute_utilization, :mean_utilization,
77
+ ], [
78
+ :median, :get_95th_percentile
79
+ ]
80
+ when Metriks::Timer
81
+ send_metric name, 'timer', metric, [
82
+ :count, :one_minute_rate, :five_minute_rate,
83
+ :fifteen_minute_rate, :mean_rate,
84
+ :min, :max, :mean, :stddev
85
+ ], [
86
+ :median, :get_95th_percentile
87
+ ]
88
+ when Metriks::Histogram
89
+ send_metric name, 'histogram', metric, [
90
+ :count, :min, :max, :mean, :stddev
91
+ ], [
92
+ :median, :get_95th_percentile
93
+ ]
94
+ end
95
+ end
96
+ end
97
+
98
+ def send_metric(name, type, metric, keys, snapshot_keys = [])
99
+ keys.each do |key|
100
+ @client << @default_event.merge(
101
+ :service => "#{name} #{key}",
102
+ :metric => metric.send(key),
103
+ :tags => [type]
104
+ )
105
+ end
106
+
107
+ unless snapshot_keys.empty?
108
+ snapshot = metric.snapshot
109
+ snapshot_keys.each do |key|
110
+ @client << @default_event.merge(
111
+ :service => "#{name} #{key}",
112
+ :metric => snapshot.send(key),
113
+ :tags => [type]
114
+ )
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,60 @@
1
+ require 'atomic'
2
+
3
+ module Metriks
4
+ class SimpleMovingAverage
5
+ INTERVAL = 5.0
6
+ SECONDS_PER_MINUTE = 60.0
7
+
8
+ ONE_MINUTE = 1
9
+ FIVE_MINUTES = 5
10
+ FIFTEEN_MINUTES = 15
11
+
12
+ def self.new_m1
13
+ new(ONE_MINUTE * SECONDS_PER_MINUTE, INTERVAL)
14
+ end
15
+
16
+ def self.new_m5
17
+ new(FIVE_MINUTES * SECONDS_PER_MINUTE, INTERVAL)
18
+ end
19
+
20
+ def self.new_m15
21
+ new(FIFTEEN_MINUTES * SECONDS_PER_MINUTE, INTERVAL)
22
+ end
23
+
24
+ def initialize(duration, interval)
25
+ @interval = interval
26
+ @duration = duration
27
+
28
+ @values = Array.new((duration / interval).to_i) { Atomic.new(nil) }
29
+ @index = Atomic.new(0)
30
+ end
31
+
32
+ def clear
33
+ @values.each do |value|
34
+ value.value = nil
35
+ end
36
+ @index.value = 0
37
+ end
38
+
39
+ def update(value)
40
+ @values[@index.value].update { |v| v ? v + value : value }
41
+ end
42
+
43
+ def tick
44
+ @index.update { |v| v < @values.length - 1 ? v + 1 : 0 }
45
+ end
46
+
47
+ def rate
48
+ num, count = 0.0, 0.0
49
+
50
+ @values.each do |value|
51
+ if v = value.value
52
+ num += v
53
+ count += 1
54
+ end
55
+ end
56
+
57
+ num / count / @interval.to_f
58
+ end
59
+ end
60
+ end