rorvswild 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rorvswild/client.rb +23 -5
- data/lib/rorvswild/plugin/mongo.rb +37 -0
- data/lib/rorvswild/plugin/net_http.rb +22 -0
- data/lib/rorvswild/plugin/redis.rb +24 -0
- data/lib/rorvswild/version.rb +1 -1
- data/lib/rorvswild.rb +3 -0
- data/test/helper.rb +7 -0
- data/test/plugin/mongo_test.rb +35 -0
- data/test/plugin/net_http_test.rb +41 -0
- data/test/plugin/redis_test.rb +42 -0
- data/test/ror_vs_wild_test.rb +6 -13
- data/test/run.rb +3 -0
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 802001256223c866089c33029d0e0b5b4a396bb0
|
4
|
+
data.tar.gz: 501c456458c29d982882775b6d106456a1f23483
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d49be58f9ec73146b3fd62c437c863cbccca35187ccb0668e2ed072fdd0dea733fe1b09cca4a8d2ae77105132fd8483ba94efcb4e2787ed9de00ca506a811237
|
7
|
+
data.tar.gz: 4c1afafbc9312d1e4589f0fc20d478e968267cab12534398a03be2cf74b73c83c676479e3918325ae6ba58c7870eebe97200aed69eee2c5adeabf140dcea44a3
|
data/lib/rorvswild/client.rb
CHANGED
@@ -58,8 +58,11 @@ module RorVsWild
|
|
58
58
|
ActionController::Base.rescue_from(StandardError) { |exception| client.after_exception(exception, self) }
|
59
59
|
end
|
60
60
|
|
61
|
+
Plugin::Redis.setup
|
62
|
+
Plugin::Mongo.setup
|
61
63
|
Plugin::Resque.setup
|
62
64
|
Plugin::Sidekiq.setup
|
65
|
+
Plugin::NetHttp.setup
|
63
66
|
Kernel.at_exit(&method(:at_exit))
|
64
67
|
ActiveJob::Base.around_perform(&method(:around_active_job)) if defined?(ActiveJob::Base)
|
65
68
|
Delayed::Worker.lifecycle.around(:invoke_job, &method(:around_delayed_job)) if defined?(Delayed::Worker)
|
@@ -86,7 +89,7 @@ module RorVsWild
|
|
86
89
|
file, line, method = extract_most_relevant_location(caller)
|
87
90
|
runtime, sql = compute_duration(start, finish), payload[:sql]
|
88
91
|
plan = runtime >= explain_sql_threshold ? explain(payload[:sql], payload[:binds]) : nil
|
89
|
-
push_query(file: file, line: line, method: method,
|
92
|
+
push_query(kind: "sql", file: file, line: line, method: method, command: sql, plan: plan, runtime: runtime)
|
90
93
|
rescue => exception
|
91
94
|
log_error(exception)
|
92
95
|
end
|
@@ -143,6 +146,20 @@ module RorVsWild
|
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
149
|
+
def measure_query(kind, command, &block)
|
150
|
+
return block.call if @query_started_at # Prevent from recursive queries
|
151
|
+
@query_started_at = Time.now.utc
|
152
|
+
begin
|
153
|
+
result = block.call
|
154
|
+
runtime = (Time.now.utc - @query_started_at) * 1000
|
155
|
+
file, line, method = extract_most_relevant_location(caller)
|
156
|
+
push_query(kind: kind, command: command, file: file, line: line, method: method, runtime: runtime)
|
157
|
+
result
|
158
|
+
ensure
|
159
|
+
@query_started_at = nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
146
163
|
def catch_error(extra_details = nil, &block)
|
147
164
|
begin
|
148
165
|
block.call
|
@@ -194,12 +211,13 @@ module RorVsWild
|
|
194
211
|
MEANINGLESS_QUERIES = %w[BEGIN COMMIT].freeze
|
195
212
|
|
196
213
|
def push_query(query)
|
197
|
-
|
198
|
-
queries
|
214
|
+
return if !queries
|
215
|
+
hash = queries.find { |hash| hash[:line] == query[:line] && hash[:file] == query[:file] && hash[:kind] == query[:kind] }
|
216
|
+
queries << hash = {kind: query[:kind], file: query[:file], line: query[:line], runtime: 0, times: 0} if !hash
|
199
217
|
hash[:runtime] += query[:runtime]
|
200
|
-
if !MEANINGLESS_QUERIES.include?(query[:
|
218
|
+
if !MEANINGLESS_QUERIES.include?(query[:command])
|
201
219
|
hash[:times] += 1
|
202
|
-
hash[:
|
220
|
+
hash[:command] ||= query[:command]
|
203
221
|
hash[:plan] ||= query[:plan] if query[:plan]
|
204
222
|
end
|
205
223
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RorVsWild
|
2
|
+
module Plugin
|
3
|
+
class Mongo
|
4
|
+
def self.setup
|
5
|
+
return if @installed
|
6
|
+
return if !defined?(::Mongo::Monitoring::Global)
|
7
|
+
::Mongo::Monitoring::Global.subscribe(::Mongo::Monitoring::COMMAND, Mongo.new)
|
8
|
+
@installed = true
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :commands
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@commands = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def started(event)
|
18
|
+
commands[event.request_id] = event.command
|
19
|
+
end
|
20
|
+
|
21
|
+
def failed(event)
|
22
|
+
after_query(event)
|
23
|
+
end
|
24
|
+
|
25
|
+
def succeeded(event)
|
26
|
+
after_query(event)
|
27
|
+
end
|
28
|
+
|
29
|
+
def after_query(event)
|
30
|
+
runtime = event.duration * 1000
|
31
|
+
command = commands.delete(event.request_id).to_s
|
32
|
+
file, line, method = RorVsWild.client.extract_most_relevant_location(caller)
|
33
|
+
RorVsWild.client.send(:push_query, kind: "mongo", command: command, file: file, line: line, method: method, runtime: runtime)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RorVsWild
|
2
|
+
module Plugin
|
3
|
+
class NetHttp
|
4
|
+
def self.setup
|
5
|
+
return if !defined?(Net::HTTP)
|
6
|
+
return if Net::HTTP.method_defined?(:request_without_rorvswild)
|
7
|
+
|
8
|
+
Net::HTTP.class_eval do
|
9
|
+
alias_method :request_without_rorvswild, :request
|
10
|
+
|
11
|
+
def request(req, body = nil, &block)
|
12
|
+
scheme = use_ssl? ? "https".freeze : "http".freeze
|
13
|
+
url = "#{req.method} #{scheme}://#{address}#{req.path}"
|
14
|
+
RorVsWild.client.measure_query("http".freeze, url) do
|
15
|
+
request_without_rorvswild(req, body = nil, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RorVsWild
|
2
|
+
module Plugin
|
3
|
+
class Redis
|
4
|
+
def self.setup
|
5
|
+
return if !defined?(::Redis)
|
6
|
+
return if ::Redis::Client.method_defined?(:process_without_rorvswild)
|
7
|
+
::Redis::Client.class_eval do
|
8
|
+
alias_method :process_without_rorvswild, :process
|
9
|
+
|
10
|
+
def process(commands, &block)
|
11
|
+
string = RorVsWild::Plugin::Redis.commands_to_string(commands)
|
12
|
+
RorVsWild.client.measure_query("redis".freeze, string) do
|
13
|
+
process_without_rorvswild(commands, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.commands_to_string(commands)
|
20
|
+
commands.map { |c| c[0] == :auth ? "auth *****" : c.join(" ".freeze) }.join("\n".freeze)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/rorvswild/version.rb
CHANGED
data/lib/rorvswild.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require "rorvswild/version"
|
2
2
|
require "rorvswild/location"
|
3
|
+
require "rorvswild/plugin/redis"
|
4
|
+
require "rorvswild/plugin/mongo"
|
3
5
|
require "rorvswild/plugin/resque"
|
4
6
|
require "rorvswild/plugin/sidekiq"
|
7
|
+
require "rorvswild/plugin/net_http"
|
5
8
|
require "rorvswild/client"
|
6
9
|
|
7
10
|
module RorVsWild
|
data/test/helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
2
|
+
|
3
|
+
require "mongo"
|
4
|
+
|
5
|
+
class RorVsWild::Plugin::MongoTest < Minitest::Test
|
6
|
+
Mongo::Logger.logger.level = ::Logger::FATAL
|
7
|
+
|
8
|
+
def test_callback
|
9
|
+
mountains = [
|
10
|
+
{name: "Mont Blanc", altitude: 4807},
|
11
|
+
{name: "Mont Cervin", altitude: 4478},
|
12
|
+
]
|
13
|
+
client.measure_block("mongo") do
|
14
|
+
client = Mongo::Client.new('mongodb://127.0.0.1:27017/test')
|
15
|
+
mountains.each { |m| client[:mountains].insert_one(m) }
|
16
|
+
end
|
17
|
+
assert_equal(1, client.send(:queries).size)
|
18
|
+
assert_equal(2, client.send(:queries)[0][:times])
|
19
|
+
assert_equal("mongo", client.send(:queries)[0][:kind])
|
20
|
+
assert_match('{"insert"=>"mountains", "documents"=>', client.send(:queries)[0][:command])
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def client
|
26
|
+
@client ||= initialize_client(app_root: "/rails/root")
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize_client(options = {})
|
30
|
+
client = RorVsWild::Client.new(options)
|
31
|
+
client.stubs(:post_request)
|
32
|
+
client.stubs(:post_job)
|
33
|
+
client
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
|
5
|
+
class RorVsWild::Plugin::NetHttpTest < Minitest::Test
|
6
|
+
def test_callback
|
7
|
+
client.measure_block("test") { Net::HTTP.get("ruby-lang.org", "/index.html") }
|
8
|
+
assert_equal(1, client.send(:queries).size)
|
9
|
+
assert_equal(1, client.send(:queries)[0][:times])
|
10
|
+
assert_equal("http", client.send(:queries)[0][:kind])
|
11
|
+
assert_match("GET http://ruby-lang.org/index.html", client.send(:queries)[0][:command])
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_callback_with_https
|
15
|
+
client.measure_block("test") { Net::HTTP.get(URI("https://www.ruby-lang.org/index.html")) }
|
16
|
+
assert_match("GET https://www.ruby-lang.org/index.html", client.send(:queries)[0][:command])
|
17
|
+
assert_equal("http", client.send(:queries)[0][:kind])
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_nested_query_because_net_http_request_is_recursive_when_connection_is_not_started
|
21
|
+
client.measure_block("test") do
|
22
|
+
uri = URI("http://www.ruby-lang.org/index.html")
|
23
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
24
|
+
http.request(Net::HTTP::Get.new(uri.path))
|
25
|
+
end
|
26
|
+
assert_equal(1, client.send(:queries)[0][:times])
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def client
|
32
|
+
@client ||= initialize_client(app_root: "/rails/root")
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_client(options = {})
|
36
|
+
client = RorVsWild::Client.new(options)
|
37
|
+
client.stubs(:post_request)
|
38
|
+
client.stubs(:post_job)
|
39
|
+
client
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
2
|
+
|
3
|
+
require "redis"
|
4
|
+
|
5
|
+
class RorVsWild::Plugin::RedisTest < Minitest::Test
|
6
|
+
def test_callback
|
7
|
+
client.measure_code("::Redis.new.get('foo')")
|
8
|
+
assert_equal(1, client.send(:queries).size)
|
9
|
+
assert_equal("redis", client.send(:queries)[0][:kind])
|
10
|
+
assert_equal("get foo", client.send(:queries)[0][:command])
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_callback_with_pipeline
|
14
|
+
skip
|
15
|
+
client.measure_block("pipeline") do
|
16
|
+
redis = ::Redis.new
|
17
|
+
redis.get("foo")
|
18
|
+
redis.set("foo", "bar")
|
19
|
+
end
|
20
|
+
assert_equal(2, client.send(:queries).size)
|
21
|
+
assert_equal("redis", client.send(:queries)[0][:kind])
|
22
|
+
assert_equal("get foo", client.send(:queries)[0][:command])
|
23
|
+
assert_equal("set foo bar", client.send(:queries)[1][:command])
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_commands_to_string_hide_auth_password
|
27
|
+
assert_equal("auth *****", RorVsWild::Plugin::Redis.commands_to_string([[:auth, "SECRET"]]))
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def client
|
33
|
+
@client ||= initialize_client(app_root: "/rails/root")
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize_client(options = {})
|
37
|
+
client ||= RorVsWild::Client.new(options)
|
38
|
+
client.stubs(:post_request)
|
39
|
+
client.stubs(:post_job)
|
40
|
+
client
|
41
|
+
end
|
42
|
+
end
|
data/test/ror_vs_wild_test.rb
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
|
2
|
-
$LOAD_PATH.unshift(root_path + "/lib")
|
3
|
-
|
4
|
-
require "rorvswild"
|
5
|
-
|
6
|
-
require "minitest/autorun"
|
7
|
-
require 'mocha/mini_test'
|
8
|
-
require "top_tests"
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/helper")
|
9
2
|
|
10
3
|
class RorVsWildTest < Minitest::Test
|
11
4
|
include TopTests
|
@@ -117,11 +110,11 @@ class RorVsWildTest < Minitest::Test
|
|
117
110
|
def test_push_query
|
118
111
|
client = initialize_client
|
119
112
|
client.send(:data)[:queries] = []
|
120
|
-
client.send(:push_query, {file: "file", line: 123,
|
121
|
-
client.send(:push_query, {file: "file", line: 123,
|
122
|
-
client.send(:push_query, {file: "file", line: 123,
|
123
|
-
client.send(:push_query, {file: "file", line: 123,
|
124
|
-
assert_equal([{file: "file", line: 123,
|
113
|
+
client.send(:push_query, {kind: "sql", file: "file", line: 123, command: "BEGIN", runtime: 10})
|
114
|
+
client.send(:push_query, {kind: "sql", file: "file", line: 123, command: "SELECT 1", runtime: 10})
|
115
|
+
client.send(:push_query, {kind: "sql", file: "file", line: 123, command: "SELECT 1", runtime: 10})
|
116
|
+
client.send(:push_query, {kind: "sql", file: "file", line: 123, command: "COMMIT", runtime: 10})
|
117
|
+
assert_equal([{kind: "sql", file: "file", line: 123, command: "SELECT 1", runtime: 40, times: 2}], client.send(:queries))
|
125
118
|
end
|
126
119
|
|
127
120
|
def test_after_exception
|
data/test/run.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rorvswild
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Bernard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -43,12 +43,20 @@ files:
|
|
43
43
|
- lib/rorvswild/client.rb
|
44
44
|
- lib/rorvswild/installer.rb
|
45
45
|
- lib/rorvswild/location.rb
|
46
|
+
- lib/rorvswild/plugin/mongo.rb
|
47
|
+
- lib/rorvswild/plugin/net_http.rb
|
48
|
+
- lib/rorvswild/plugin/redis.rb
|
46
49
|
- lib/rorvswild/plugin/resque.rb
|
47
50
|
- lib/rorvswild/plugin/sidekiq.rb
|
48
51
|
- lib/rorvswild/rails_loader.rb
|
49
52
|
- lib/rorvswild/version.rb
|
50
53
|
- rorvswild.gemspec
|
54
|
+
- test/helper.rb
|
55
|
+
- test/plugin/mongo_test.rb
|
56
|
+
- test/plugin/net_http_test.rb
|
57
|
+
- test/plugin/redis_test.rb
|
51
58
|
- test/ror_vs_wild_test.rb
|
59
|
+
- test/run.rb
|
52
60
|
homepage: https://www.rorvswild.com
|
53
61
|
licenses:
|
54
62
|
- MIT
|
@@ -74,5 +82,10 @@ signing_key:
|
|
74
82
|
specification_version: 4
|
75
83
|
summary: Ruby on Rails app monitoring
|
76
84
|
test_files:
|
85
|
+
- test/helper.rb
|
86
|
+
- test/plugin/mongo_test.rb
|
87
|
+
- test/plugin/net_http_test.rb
|
88
|
+
- test/plugin/redis_test.rb
|
77
89
|
- test/ror_vs_wild_test.rb
|
90
|
+
- test/run.rb
|
78
91
|
has_rdoc:
|