rorvswild 0.5.1 → 0.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87b6214d8ddec4d743dc4498fae53c2ce5d39531
4
- data.tar.gz: fe6e1d5192ad34f8b2f9c51659a575fd1f73f170
3
+ metadata.gz: 802001256223c866089c33029d0e0b5b4a396bb0
4
+ data.tar.gz: 501c456458c29d982882775b6d106456a1f23483
5
5
  SHA512:
6
- metadata.gz: dde693b8dca1e8ce5a092b08c814387cbd6eaa5286001ef152ef1b81f8893646bfbaaf913ff34ff9295783ab8d6b1de248f76b0ad620efd79347d6a7e237dffd
7
- data.tar.gz: 118a2bb80c5f60e19a140aed778b42bfa362e22de280b091119c413d974164a4f2a08f14a8f6be06129fdecb57dff6f5caf009d6685a181ae7d4de0f809827a9
6
+ metadata.gz: d49be58f9ec73146b3fd62c437c863cbccca35187ccb0668e2ed072fdd0dea733fe1b09cca4a8d2ae77105132fd8483ba94efcb4e2787ed9de00ca506a811237
7
+ data.tar.gz: 4c1afafbc9312d1e4589f0fc20d478e968267cab12534398a03be2cf74b73c83c676479e3918325ae6ba58c7870eebe97200aed69eee2c5adeabf140dcea44a3
@@ -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, sql: sql, plan: plan, runtime: runtime)
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
- hash = queries.find { |hash| hash[:line] == query[:line] && hash[:file] == query[:file] }
198
- queries << hash = {file: query[:file], line: query[:line], runtime: 0, times: 0} if !hash
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[:sql])
218
+ if !MEANINGLESS_QUERIES.include?(query[:command])
201
219
  hash[:times] += 1
202
- hash[:sql] ||= query[:sql]
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
@@ -1,3 +1,3 @@
1
1
  module RorVsWild
2
- VERSION = "0.5.1".freeze
2
+ VERSION = "0.6.0".freeze
3
3
  end
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,7 @@
1
+ path = File.expand_path("#{File.dirname(__FILE__)}/../lib")
2
+ $LOAD_PATH.unshift(path)
3
+
4
+ require "rorvswild"
5
+ require "minitest/autorun"
6
+ require "mocha/mini_test"
7
+ require "top_tests"
@@ -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
@@ -1,11 +1,4 @@
1
- root_path = File.expand_path(File.dirname(File.dirname(__FILE__)))
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, sql: "BEGIN", runtime: 10})
121
- client.send(:push_query, {file: "file", line: 123, sql: "SELECT 1", runtime: 10})
122
- client.send(:push_query, {file: "file", line: 123, sql: "SELECT 1", runtime: 10})
123
- client.send(:push_query, {file: "file", line: 123, sql: "COMMIT", runtime: 10})
124
- assert_equal([{file: "file", line: 123, sql: "SELECT 1", runtime: 40, times: 2}], client.send(:queries))
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
@@ -0,0 +1,3 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/helper")
2
+
3
+ Dir.glob("**/*_test.rb").each { |file_path| require File.expand_path(file_path) }
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.5.1
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-20 00:00:00.000000000 Z
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: