gremlin 0.0.1 → 0.0.2
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.
- 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:
|