/
stats_d.rb
146 lines (122 loc) · 4.03 KB
/
stats_d.rb
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
require 'socket'
module StatsD
class << self
attr_accessor :host, :port, :mode, :logger, :enabled
end
self.enabled = true
trap("TTOU") { self.enabled = false }
trap("TTIN") { self.enabled = true }
# StatsD.server = 'localhost:1234'
def self.server=(conn)
self.host, port = conn.split(':')
self.port = port.to_i
end
module Instrument
def statsd_measure(method, name)
add_to_method(method, name, :measure) do |old_method, new_method, metric_name, *args|
define_method(new_method) do |*args|
StatsD.measure(send(metric_name)) { send(old_method, *args) }
end
end
end
def statsd_count_success(method, name)
add_to_method(method, name, :count_success) do |old_method, new_method, metric_name|
define_method(new_method) do |*args|
begin
truthiness = result = send(old_method, *args)
rescue
truthiness = false
raise
else
truthiness = (yield(result) rescue false) if block_given?
result
ensure
StatsD.increment("#{send(metric_name)}." + (truthiness == false ? 'failure' : 'success'))
end
end
end
end
def statsd_count_if(method, name)
add_to_method(method, name, :count_if) do |old_method, new_method, metric_name|
define_method(new_method) do |*args|
begin
truthiness = result = send(old_method, *args)
rescue
truthiness = false
raise
else
truthiness = (yield(result) rescue false) if block_given?
result
ensure
StatsD.increment(send(metric_name)) if truthiness
end
end
end
end
def statsd_count(method, name)
add_to_method(method, name, :count) do |old_method, new_method, metric_name|
define_method(new_method) do |*args|
StatsD.increment(send(metric_name))
send(old_method, *args)
end
end
end
#private
def statsd_memoize(metric_name, name)
define_method(metric_name) do
name = eval("\"#{name}\"", binding)
self.class.send(:define_method, metric_name) do
name
end
send(metric_name)
end
end
def add_to_method(method, name, action, &block)
metric_name = :"#{method}_#{name}_metric_name"
statsd_memoize(metric_name, name)
method_name_without_statsd = :"#{method}_for_#{action}_on_#{self.name}_without_#{name}"
# raw_ssl_request_for_measure_on_FedEx_without_ActiveMerchant.Shipping.#{self.class.name}.ssl_request
method_name_with_statsd = :"#{method}_for_#{action}_on_#{self.name}_with_#{name}"
# raw_ssl_request_for_measure_on_FedEx_with_ActiveMerchant.Shipping.#{self.class.name}.ssl_request
raise ArgumentError, "already instrumented #{method} for #{self.name}" if method_defined? method_name_without_statsd
raise ArgumentError, "could not find method #{method} for #{self.name}" unless method_defined?(method) || private_method_defined?(method)
alias_method method_name_without_statsd, method
yield method_name_without_statsd, method_name_with_statsd, metric_name
alias_method method, method_name_with_statsd
end
end
# glork:320|ms
def self.measure(key, milli = nil)
result = nil
ms = Benchmark.ms do
result = yield
end if milli.nil?
write(key, ms, :ms)
result
end
# gorets:1|c
def self.increment(key, delta = 1, sample_rate = 1)
write(key, delta, :incr, sample_rate)
end
private
def self.socket
@socket ||= socket = UDPSocket.new
end
def self.write(k,v,op, sample_rate = 1)
return unless enabled
return if sample_rate < 1 && rand > sample_rate
command = "#{k}:#{v}"
case op
when :incr
command << '|c'
when :ms
command << '|ms'
end
command << "|@#{sample_rate}" if sample_rate < 1
if mode == :production
socket.send(command, 0, host, port)
else
logger.info "[StatsD] #{command}"
end
end
end