gremlin 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gemfile.lock +6 -6
- data/benchmark.rb +143 -0
- data/gremlin.gemspec +1 -1
- data/lib/gremlin.rb +33 -1
- data/lib/gremlin/instruments.rb +3 -12
- data/lib/gremlin/instruments/counter.rb +7 -4
- data/lib/gremlin/instruments/gauge.rb +8 -3
- data/lib/gremlin/notification_observer.rb +38 -0
- data/lib/gremlin/railtie.rb +75 -112
- data/lib/gremlin/registry.rb +6 -0
- data/lib/gremlin/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f3277bdf017d08b45ad5deb0313a9aa4fe713dd
|
4
|
+
data.tar.gz: 359c2c16c2438cd7366911abf975c3b802776b87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecc158ed3ff1540d04d163e4ffc5dd2d5d1a02b5cb396133e221d3d41ef521e918612c55a7db11bce2095a72b2d001e6cf820ab03898ab6d5cd1539e9b31e3e4
|
7
|
+
data.tar.gz: a3477c8661b90c1a227f5870dcccddc0f75b4a171ea372fe766fa552abd1324536621f1d4dd4dcadacce6afe0839d32cf702e1f11fc9de764d7d9f77da14a5b7
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
gremlin (0.0.
|
4
|
+
gremlin (0.0.2)
|
5
5
|
quantile
|
6
6
|
rails
|
7
7
|
redis (~> 3.2)
|
@@ -54,7 +54,7 @@ GEM
|
|
54
54
|
erubis (2.7.0)
|
55
55
|
globalid (0.3.7)
|
56
56
|
activesupport (>= 4.1.0)
|
57
|
-
i18n (0.
|
57
|
+
i18n (0.8.1)
|
58
58
|
loofah (2.0.3)
|
59
59
|
nokogiri (>= 1.5.9)
|
60
60
|
mail (2.6.4)
|
@@ -97,7 +97,7 @@ GEM
|
|
97
97
|
thor (>= 0.18.1, < 2.0)
|
98
98
|
rake (10.5.0)
|
99
99
|
rdoc (5.0.0)
|
100
|
-
redis (3.3.
|
100
|
+
redis (3.3.3)
|
101
101
|
redis-native_hash (0.2.1)
|
102
102
|
redis (>= 2.0.0)
|
103
103
|
rspec (3.5.0)
|
@@ -121,10 +121,10 @@ GEM
|
|
121
121
|
activesupport (>= 4.0)
|
122
122
|
sprockets (>= 3.0.0)
|
123
123
|
thor (0.19.4)
|
124
|
-
thread_safe (0.3.
|
124
|
+
thread_safe (0.3.6)
|
125
125
|
tzinfo (1.2.2)
|
126
126
|
thread_safe (~> 0.1)
|
127
|
-
websocket-driver (0.6.
|
127
|
+
websocket-driver (0.6.5)
|
128
128
|
websocket-extensions (>= 0.1.0)
|
129
129
|
websocket-extensions (0.1.2)
|
130
130
|
|
@@ -139,4 +139,4 @@ DEPENDENCIES
|
|
139
139
|
rspec (~> 3.3, >= 3.3.0)
|
140
140
|
|
141
141
|
BUNDLED WITH
|
142
|
-
1.
|
142
|
+
1.12.4
|
data/benchmark.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'gremlin'
|
3
|
+
|
4
|
+
|
5
|
+
include Benchmark
|
6
|
+
|
7
|
+
print "Starting benchmarks..."
|
8
|
+
|
9
|
+
orig_std_out = STDOUT.clone
|
10
|
+
STDOUT.reopen(File::open('/dev/null', 'w'))
|
11
|
+
|
12
|
+
counter_init_benchmarks = (1..100).map do |n|
|
13
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
14
|
+
counter_name = "test_#{SecureRandom.hex(5)}_counter".to_sym
|
15
|
+
x.report("Counter initialize") { Gremlin::Instruments::Counter.new counter_name, "placeholder", {} }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
counter_init_and_fetch_benchmarks = (1..100).map do |n|
|
20
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
21
|
+
counter_name = "test_#{SecureRandom.hex(5)}_counter".to_sym
|
22
|
+
x.report("Counter initialize then fetch") do
|
23
|
+
Gremlin::Instruments::Counter.new counter_name, "placeholder", {}
|
24
|
+
Gremlin.registry.get counter_name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
counter_init_and_incr_benchmarks = (1..100).map do |n|
|
30
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
31
|
+
counter_name = "test_#{SecureRandom.hex(5)}_counter".to_sym
|
32
|
+
x.report("Counter increment") do
|
33
|
+
counter = Gremlin::Instruments::Counter.new counter_name, "placeholder", {}
|
34
|
+
counter.increment
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
gauge_init_benchmarks = (1..100).map do |n|
|
40
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
41
|
+
gauge_name = "test_#{SecureRandom.hex(5)}_gauge".to_sym
|
42
|
+
gauge_set_val = rand(1..25000000)
|
43
|
+
x.report("Gauge initialize") { Gremlin::Instruments::Gauge.new gauge_name, "placeholder", {} }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
gauge_init_and_fetch_benchmarks = (1..100).map do |n|
|
48
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
49
|
+
gauge_name = "test_#{SecureRandom.hex(5)}_gauge".to_sym
|
50
|
+
gauge_set_val = rand(1..25000000)
|
51
|
+
x.report("Gauge fetch") do
|
52
|
+
Gremlin::Instruments::Gauge.new gauge_name, "placeholder", {}
|
53
|
+
Gremlin.registry.get gauge_name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
gauge_init_and_set_benchmarks = (1..100).map do |n|
|
59
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
60
|
+
gauge_name = "test_#{SecureRandom.hex(5)}_gauge".to_sym
|
61
|
+
gauge_set_val = rand(1..25000000)
|
62
|
+
x.report("Gauge set") do
|
63
|
+
gauge = Gremlin::Instruments::Gauge.new gauge_name, "placeholder", {}
|
64
|
+
gauge.set({ :foo => "baz" }, gauge_set_val)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
summary_init_benchmarks = (1..100).map do |n|
|
70
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
71
|
+
summary_name = "test_#{SecureRandom.hex(5)}_summary".to_sym
|
72
|
+
summary_observe_val = rand(1..25000000)
|
73
|
+
x.report("Summary initialize") { Gremlin::Instruments::Summary.new summary_name.to_sym, "placeholder", {} }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
summary_init_and_fetch_benchmarks = (1..100).map do |n|
|
78
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
79
|
+
summary_name = "test_#{SecureRandom.hex(5)}_summary".to_sym
|
80
|
+
summary_observe_val = rand(1..25000000)
|
81
|
+
x.report("Summary fetch") do
|
82
|
+
Gremlin::Instruments::Summary.new summary_name.to_sym, "placeholder", {}
|
83
|
+
Gremlin.registry.get summary_name
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
summary_init_and_observe_benchmarks = (1..100).map do |n|
|
89
|
+
Benchmark.benchmark(CAPTION, 35, FORMAT) do |x|
|
90
|
+
summary_name = "test_#{SecureRandom.hex(5)}_summary".to_sym
|
91
|
+
summary_observe_val = rand(1..25000000)
|
92
|
+
x.report("Summary observe") do
|
93
|
+
summary = Gremlin::Instruments::Summary.new summary_name.to_sym, "placeholder", {}
|
94
|
+
summary.observe({ :bar => "foo" }, summary_observe_val)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
STDOUT.reopen(orig_std_out)
|
100
|
+
print "Done!\n"
|
101
|
+
|
102
|
+
counter_init_agg = counter_init_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
103
|
+
counter_init_and_incr_agg = counter_init_and_incr_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
104
|
+
counter_init_and_fetch_agg = counter_init_and_fetch_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
105
|
+
|
106
|
+
puts "--------------------------------------------------------"
|
107
|
+
puts ""
|
108
|
+
puts "Counter Initialize Total: #{counter_init_agg*1000} ms"
|
109
|
+
puts "Counter Initialize Avg: #{counter_init_agg/100*1000} ms over 100 iterations"
|
110
|
+
puts "Counter Initialize and Fetch Total: #{counter_init_and_fetch_agg*1000} ms"
|
111
|
+
puts "Counter Initialize and Fetch Avg: #{counter_init_and_fetch_agg/100*1000} ms over 100 iterations"
|
112
|
+
puts "Counter Initialize and Fetch Total: #{counter_init_and_incr_agg*1000} ms"
|
113
|
+
puts "Counter Initialize and Fetch Avg: #{counter_init_and_incr_agg/100*1000} ms over 100 iterations"
|
114
|
+
puts ""
|
115
|
+
|
116
|
+
gauge_init_agg = gauge_init_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
117
|
+
gauge_init_and_fetch_agg = gauge_init_and_fetch_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
118
|
+
gauge_init_and_set_agg = gauge_init_and_set_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
119
|
+
|
120
|
+
puts "--------------------------------------------------------"
|
121
|
+
puts ""
|
122
|
+
puts "Gauge Initialize Total: #{gauge_init_agg*1000} ms"
|
123
|
+
puts "Gauge Initialize Avg: #{gauge_init_agg/100*1000} ms over 100 iterations"
|
124
|
+
puts "Gauge Initialize and Fetch Total: #{gauge_init_and_fetch_agg*1000} ms"
|
125
|
+
puts "Gauge Initialize and Fetch Avg: #{gauge_init_and_fetch_agg/100*1000} ms over 100 iterations"
|
126
|
+
puts "Gauge Initialize and Set Total: #{gauge_init_and_set_agg*1000} ms"
|
127
|
+
puts "Gauge Initialize and Set Avg: #{gauge_init_and_set_agg/100*1000} ms over 100 iterations"
|
128
|
+
puts ""
|
129
|
+
puts "--------------------------------------------------------"
|
130
|
+
|
131
|
+
summary_init_agg = summary_init_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
132
|
+
summary_init_and_fetch_agg = summary_init_and_fetch_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
133
|
+
summary_init_and_observe_agg = summary_init_and_observe_benchmarks.flatten.inject(0) { |sum, x| sum + x.real }
|
134
|
+
|
135
|
+
puts ""
|
136
|
+
puts "Summary Initialize Total: #{summary_init_agg*1000} ms"
|
137
|
+
puts "Summary Initialize Avg: #{summary_init_agg/100*1000} ms over 100 iterations"
|
138
|
+
puts "Summary Initialize and Fetch Total: #{summary_init_and_fetch_agg*1000} ms"
|
139
|
+
puts "Summary Initialize and Fetch Avg: #{summary_init_and_fetch_agg/100*1000} ms over 100 iterations"
|
140
|
+
puts "Summary Initialize and Observe Total: #{summary_init_and_observe_agg*1000} ms"
|
141
|
+
puts "Summary Initialize and Observe Avg: #{summary_init_and_observe_agg/100*1000} ms over 100 iterations"
|
142
|
+
puts ""
|
143
|
+
puts "--------------------------------------------------------"
|
data/gremlin.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = %q{Gem to sanely emit metrics from Omadahealth rails applications}
|
13
13
|
spec.description = %q{A modular metrics harness for Omadahealth rails applications}
|
14
|
-
spec.homepage = "https://github.com/omadahealth/
|
14
|
+
spec.homepage = "https://github.com/omadahealth/gremlin"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
17
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
data/lib/gremlin.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# Supporting librarires
|
2
2
|
require "active_support/cache"
|
3
3
|
require "active_support/notifications" if defined?(::Rails)
|
4
|
-
require "
|
4
|
+
require "erb"
|
5
5
|
require "json"
|
6
|
+
require "quantile"
|
6
7
|
require "redis_hash"
|
8
|
+
require "yaml"
|
7
9
|
|
8
10
|
# Gem internals
|
9
11
|
require "gremlin/version"
|
@@ -13,6 +15,7 @@ require "gremlin/instruments/counter"
|
|
13
15
|
require "gremlin/instruments/gauge"
|
14
16
|
require "gremlin/instruments/summary"
|
15
17
|
require "gremlin/quantile"
|
18
|
+
require "gremlin/notification_observer"
|
16
19
|
|
17
20
|
# Rails support
|
18
21
|
require "gremlin/engine" if defined?(::Rails::Engine)
|
@@ -20,8 +23,37 @@ require "gremlin/railtie" if defined?(::Rails)
|
|
20
23
|
|
21
24
|
module Gremlin
|
22
25
|
class << self
|
26
|
+
attr_reader :configuration
|
27
|
+
|
23
28
|
def registry
|
24
29
|
@registry ||= Gremlin::Registry.new
|
25
30
|
end
|
31
|
+
|
32
|
+
def configuration
|
33
|
+
unless @configuration
|
34
|
+
@configuration = configure do |c|
|
35
|
+
c.redis = { :host => "localhost", :port => 6379, :db => 15 }
|
36
|
+
c.enabled = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@configuration
|
40
|
+
end
|
41
|
+
|
42
|
+
def configure
|
43
|
+
config = Config.new
|
44
|
+
yield config
|
45
|
+
@configuration = config
|
46
|
+
end
|
47
|
+
|
48
|
+
def enabled?
|
49
|
+
@configuration.enabled
|
50
|
+
end
|
51
|
+
|
52
|
+
def disabled?
|
53
|
+
not enabled?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Config < Struct.new(:redis, :enabled)
|
26
58
|
end
|
27
59
|
end
|
data/lib/gremlin/instruments.rb
CHANGED
@@ -9,7 +9,10 @@ module Gremlin
|
|
9
9
|
@base_labels = base_labels
|
10
10
|
@mutex = Mutex.new
|
11
11
|
|
12
|
+
Redis::Client.default = Redis.new(**Gremlin.configuration.redis)
|
13
|
+
@r = Redis.new(**Gremlin.configuration.redis)
|
12
14
|
@values = Redis::NativeHash.find(retention_key) || Redis::NativeHash.new
|
15
|
+
@values.redis = Redis.new(**Gremlin.configuration.redis)
|
13
16
|
@values.key = retention_key
|
14
17
|
@values.save
|
15
18
|
end
|
@@ -65,18 +68,6 @@ module Gremlin
|
|
65
68
|
end
|
66
69
|
end
|
67
70
|
end
|
68
|
-
|
69
|
-
def get(labels={})
|
70
|
-
v = @values[labels.to_json]
|
71
|
-
case type
|
72
|
-
when :counter
|
73
|
-
v.to_i
|
74
|
-
when :gauge
|
75
|
-
v.to_f
|
76
|
-
else
|
77
|
-
v
|
78
|
-
end
|
79
|
-
end
|
80
71
|
end
|
81
72
|
end
|
82
73
|
end
|
@@ -5,10 +5,7 @@ module Gremlin
|
|
5
5
|
class Counter < Base
|
6
6
|
def increment(labels={}, by=1)
|
7
7
|
@mutex.synchronize do
|
8
|
-
|
9
|
-
@values[labels.to_json] = prev_val + by
|
10
|
-
@values.save
|
11
|
-
@values[labels.to_json]
|
8
|
+
@r.hincrby retention_key, labels.to_json, by
|
12
9
|
end
|
13
10
|
end
|
14
11
|
|
@@ -23,6 +20,12 @@ module Gremlin
|
|
23
20
|
def retention_key
|
24
21
|
"gremlin_prometheus_#{node}_metrics_counter_#{name}"
|
25
22
|
end
|
23
|
+
|
24
|
+
def get(labels={})
|
25
|
+
@values.reload!
|
26
|
+
v = @values[labels.to_json]
|
27
|
+
v.to_i
|
28
|
+
end
|
26
29
|
end
|
27
30
|
end
|
28
31
|
end
|
@@ -5,9 +5,8 @@ module Gremlin
|
|
5
5
|
class Gauge < Base
|
6
6
|
def set(labels={}, value)
|
7
7
|
@mutex.synchronize do
|
8
|
-
@
|
9
|
-
|
10
|
-
@values[labels.to_json]
|
8
|
+
@r.hset retention_key, labels.to_json, value
|
9
|
+
get(labels)
|
11
10
|
end
|
12
11
|
end
|
13
12
|
|
@@ -18,6 +17,12 @@ module Gremlin
|
|
18
17
|
def retention_key
|
19
18
|
"gremlin_prometheus_#{node}_metrics_gauge_#{name}"
|
20
19
|
end
|
20
|
+
|
21
|
+
def get(labels={})
|
22
|
+
@values.reload!
|
23
|
+
v = @values[labels.to_json]
|
24
|
+
v.to_f
|
25
|
+
end
|
21
26
|
end
|
22
27
|
end
|
23
28
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gremlin
|
2
|
+
module NotificationObserver
|
3
|
+
class CounterReceiver
|
4
|
+
def initialize(name, docstring, labels)
|
5
|
+
@instrument = Gremlin::Instruments::Counter.new(name, docstring, labels)
|
6
|
+
begin
|
7
|
+
Gremlin.registry.register @instrument
|
8
|
+
rescue Gremlin::Registry::AlreadyRegisteredError; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(name, start, finish, id, payload)
|
12
|
+
instrument.increment({})
|
13
|
+
end
|
14
|
+
|
15
|
+
def instrument
|
16
|
+
Gremlin.registry.get(@instrument.name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class SummaryReceiver
|
21
|
+
def initialize(name, docstring, labels, payload_field)
|
22
|
+
@instrument = Gremlin::Instruments::Summary.new(name, docstring, labels)
|
23
|
+
begin
|
24
|
+
Gremlin.registry.register @instrument
|
25
|
+
rescue Gremlin::Registry::AlreadyRegisteredError; end
|
26
|
+
@field_to_observe = payload_field
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(name, start, finish, id, payload)
|
30
|
+
instrument.observe({}, payload[@field_to_observe.to_sym])
|
31
|
+
end
|
32
|
+
|
33
|
+
def instrument
|
34
|
+
Gremlin.registry.get(@instrument.name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/gremlin/railtie.rb
CHANGED
@@ -1,130 +1,93 @@
|
|
1
1
|
module Gremlin
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
6
|
-
|
7
|
-
initializer "gremlin.base_instrumentation" do |app|
|
8
|
-
environment = ::Rails.env.to_s
|
9
|
-
application_name = ::Rails.application.class.parent_name.downcase
|
10
|
-
node = `hostname`.strip
|
11
|
-
|
12
|
-
#
|
13
|
-
# ActionController
|
14
|
-
#
|
15
|
-
|
16
|
-
ActiveSupport::Notifications.subscribe "start_processing.action_controller" do |name, start, finish, id, payload|
|
17
|
-
# Payload contains:
|
18
|
-
# :controller --- The controller name
|
19
|
-
# :action --- The action
|
20
|
-
# :params --- Hash of request parameters without any filtered parameter
|
21
|
-
# :headers --- Request headers
|
22
|
-
# :format --- html/js/json/xml etc
|
23
|
-
# :method --- HTTP request verb
|
24
|
-
# :path --- Request path
|
25
|
-
|
26
|
-
# Counter to track event occurances
|
2
|
+
module ActionController
|
3
|
+
class StartProcessingCounterReceiver < Gremlin::NotificationObserver::CounterReceiver
|
4
|
+
def call(name, start, finish, id, payload)
|
27
5
|
begin
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
rescue Gremlin::Registry::AlreadyRegisteredError
|
33
|
-
occurance_counter = Gremlin.registry.get "action_controller_start_processing_events".to_sym
|
34
|
-
end
|
35
|
-
|
36
|
-
occurance_counter.increment({ controller: payload[:controller].to_s, format: payload[:format].to_s, action: payload[:action] })
|
6
|
+
instrument.increment({ controller: payload[:controller].to_s,
|
7
|
+
format: payload[:format].to_s,
|
8
|
+
action: payload[:action] })
|
9
|
+
rescue; end
|
37
10
|
end
|
11
|
+
end
|
38
12
|
|
39
|
-
|
40
|
-
|
41
|
-
# :controller --- The controller name
|
42
|
-
# :action --- The action
|
43
|
-
# :params --- Hash of request parameters *without any filtered parameter*
|
44
|
-
# :headers --- Request headers
|
45
|
-
# :format --- html/js/json/xml etc
|
46
|
-
# :method --- HTTP request verb
|
47
|
-
# :path --- Request path
|
48
|
-
# :status --- HTTP status code
|
49
|
-
# :view_runtime --- Amount spent in view in ms
|
50
|
-
# :db_runtime --- Amount spent executing database queries in ms
|
51
|
-
|
52
|
-
# Counter to track event occurances
|
53
|
-
begin
|
54
|
-
occurance_counter = Gremlin::Instruments::Counter.new("action_controller_process_action_events".to_sym,
|
55
|
-
"ActionController process action occurance counter.",
|
56
|
-
application: application_name, environment: environment, node: node)
|
57
|
-
Gremlin.registry.register occurance_counter
|
58
|
-
rescue Gremlin::Registry::AlreadyRegisteredError
|
59
|
-
occurance_counter = Gremlin.registry.get "action_controller_process_action_events".to_sym
|
60
|
-
end
|
61
|
-
|
62
|
-
occurance_counter.increment({ controller: payload[:controller].to_s, format: payload[:format].to_s, action: payload[:action], status: payload[:status] })
|
63
|
-
|
13
|
+
class ProcessActionCounterReceiver < Gremlin::NotificationObserver::CounterReceiver
|
14
|
+
def call(name, start, finish, id, payload)
|
64
15
|
begin
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
rescue
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
db_summary.observe({ controller: payload[:controller], method: payload[:method], status: payload[:status], action: payload[:action] }, payload[:db_runtime])
|
16
|
+
instrument.increment({ controller: payload[:controller].to_s,
|
17
|
+
format: payload[:format].to_s,
|
18
|
+
action: payload[:action],
|
19
|
+
status: payload[:status] })
|
20
|
+
rescue; end
|
21
|
+
end
|
22
|
+
end
|
74
23
|
|
24
|
+
class ProcessActionSummaryReceiver < Gremlin::NotificationObserver::SummaryReceiver
|
25
|
+
def call(name, start, finish, id, payload)
|
75
26
|
begin
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
27
|
+
instrument.observe({ controller: payload[:controller],
|
28
|
+
method: payload[:method],
|
29
|
+
status: payload[:status],
|
30
|
+
action: payload[:action] },
|
31
|
+
payload[@field_to_observe.to_sym])
|
32
|
+
rescue; end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Railtie < ::Rails::Railtie
|
38
|
+
config.before_initialize do
|
39
|
+
Gremlin.configure do |c|
|
40
|
+
c.redis = { url: "localhost", port: 6379, db: 15 }
|
41
|
+
c.enabled = true
|
85
42
|
end
|
86
43
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
begin
|
94
|
-
occurance_counter = Gremlin::Instruments::Counter.new("action_controller_redirect_to_events".to_sym,
|
95
|
-
"ActionController redirect to occurance counter.",
|
96
|
-
application: application_name, environment: environment, node: node)
|
97
|
-
Gremlin.registry.register occurance_counter
|
98
|
-
rescue Gremlin::Registry::AlreadyRegisteredError
|
99
|
-
occurance_counter = Gremlin.registry.get "action_controller_redirect_to_events".to_sym
|
44
|
+
conf_file = ::Rails.root.join("config", "gremlin.yml")
|
45
|
+
config = YAML.load(ERB.new(File.read(conf_file)).result) if File.exists?(conf_file)
|
46
|
+
if config
|
47
|
+
Gremlin.configure do |c|
|
48
|
+
c.redis = config[::Rails.env] ? config[::Rails.env]["redis"] : config["redis"]
|
49
|
+
c.enabled = config[::Rails.env] ? config[::Rails.env]["enabled"] : config["enabled"]
|
100
50
|
end
|
101
|
-
|
102
|
-
occurance_counter.increment({ status: payload[:status] })
|
103
51
|
end
|
52
|
+
end
|
104
53
|
|
105
|
-
|
106
|
-
|
107
|
-
|
54
|
+
initializer "gremlin.base_instrumentation" do |app|
|
55
|
+
environment = ::Rails.env.to_s
|
56
|
+
application_name = ::Rails.application.class.parent_name.downcase
|
57
|
+
node = `hostname`.strip
|
58
|
+
basic_labels = { node: node, app: application_name, env: environment }
|
108
59
|
|
109
|
-
|
110
|
-
# Payload contains:
|
111
|
-
# :sql --- SQL statement
|
112
|
-
# :name --- Name of the operation
|
113
|
-
# :connection_id --- self.object_id
|
114
|
-
# :binds --- Bind parameters
|
60
|
+
next if Gremlin.disabled?
|
115
61
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
"ActiveRecord SQL occurance counter.",
|
120
|
-
application: application_name, environment: environment, node: node)
|
121
|
-
Gremlin.registry.register occurance_counter
|
122
|
-
rescue Gremlin::Registry::AlreadyRegisteredError
|
123
|
-
occurance_counter = Gremlin.registry.get "active_record_sql_events".to_sym
|
124
|
-
end
|
62
|
+
#
|
63
|
+
# ActionController instrumentation
|
64
|
+
#
|
125
65
|
|
126
|
-
|
127
|
-
|
66
|
+
# Generic instrumentation for /(start_processing|process_action|redirect_to)\.action_controller/
|
67
|
+
occurance_counter = Gremlin::NotificationObserver::CounterReceiver.new("notification_count",
|
68
|
+
"Count of notifications handled by Gremlin.",
|
69
|
+
basic_labels)
|
70
|
+
ActiveSupport::Notifications.subscribe /(start_processing|process_action|redirect_to)\.action_controller/, occurance_counter
|
71
|
+
|
72
|
+
# Instrumentation for start_processing.action_controller
|
73
|
+
start_processing_occurance_counter = Gremlin::ActionController::StartProcessingCounterReceiver.new("action_controller_start_processing_count",
|
74
|
+
"Count of start_processing.action_controller notifications handled by Gremlin.",
|
75
|
+
basic_labels)
|
76
|
+
ActiveSupport::Notifications.subscribe "start_processing.action_controller", start_processing_occurance_counter
|
77
|
+
|
78
|
+
# Instrumentation for process_action.action_controller
|
79
|
+
view_summary = Gremlin::ActionController::ProcessActionSummaryReceiver.new("action_controller_process_action_view_runtime_ms",
|
80
|
+
"ActionController process action view runtime in milliseconds.",
|
81
|
+
basic_labels, "view_runtime")
|
82
|
+
db_summary = Gremlin::ActionController::ProcessActionSummaryReceiver.new("action_controller_process_action_db_runtime_ms",
|
83
|
+
"ActionController process action db runtime in milliseconds.",
|
84
|
+
basic_labels, "db_runtime")
|
85
|
+
process_action_occurance_counter = Gremlin::ActionController::ProcessActionCounterReceiver.new("action_controller_process_action_count",
|
86
|
+
"Count of process_action.action_controller notifications handled by Gremlin.",
|
87
|
+
basic_labels)
|
88
|
+
ActiveSupport::Notifications.subscribe "process_action.action_controller", process_action_occurance_counter
|
89
|
+
ActiveSupport::Notifications.subscribe "process_action.action_controller", view_summary
|
90
|
+
ActiveSupport::Notifications.subscribe "process_action.action_controller", db_summary
|
128
91
|
end
|
129
92
|
end
|
130
93
|
end
|
data/lib/gremlin/registry.rb
CHANGED
@@ -5,7 +5,9 @@ module Gremlin
|
|
5
5
|
NotAMetricError = Class.new StandardError
|
6
6
|
|
7
7
|
def initialize
|
8
|
+
Redis::Client.default = Redis.new(**Gremlin.configuration.redis)
|
8
9
|
@metrics = Redis::NativeHash.find(retention_key) || Redis::NativeHash.new()
|
10
|
+
@metrics.redis = Redis.new(**Gremlin.configuration.redis)
|
9
11
|
@metrics.key = retention_key
|
10
12
|
@metrics.save
|
11
13
|
|
@@ -26,6 +28,10 @@ module Gremlin
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
31
|
+
def dump_metrics
|
32
|
+
@metrics
|
33
|
+
end
|
34
|
+
|
29
35
|
def get(name)
|
30
36
|
m = @metrics[name.to_sym]
|
31
37
|
deserialize(m) unless m.nil?
|
data/lib/gremlin/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gremlin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin G. Phillips
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -139,6 +139,7 @@ files:
|
|
139
139
|
- Gemfile
|
140
140
|
- Gemfile.lock
|
141
141
|
- app/controllers/gremlin/metrics_controller.rb
|
142
|
+
- benchmark.rb
|
142
143
|
- config/routes.rb
|
143
144
|
- gremlin.gemspec
|
144
145
|
- lib/gremlin.rb
|
@@ -147,13 +148,14 @@ files:
|
|
147
148
|
- lib/gremlin/instruments/counter.rb
|
148
149
|
- lib/gremlin/instruments/gauge.rb
|
149
150
|
- lib/gremlin/instruments/summary.rb
|
151
|
+
- lib/gremlin/notification_observer.rb
|
150
152
|
- lib/gremlin/quantile.rb
|
151
153
|
- lib/gremlin/quantile/estimator.rb
|
152
154
|
- lib/gremlin/quantile/quantile.rb
|
153
155
|
- lib/gremlin/railtie.rb
|
154
156
|
- lib/gremlin/registry.rb
|
155
157
|
- lib/gremlin/version.rb
|
156
|
-
homepage: https://github.com/omadahealth/
|
158
|
+
homepage: https://github.com/omadahealth/gremlin
|
157
159
|
licenses:
|
158
160
|
- MIT
|
159
161
|
metadata:
|