rorvswild 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/lib/rorvswild/version.rb +1 -1
- data/lib/rorvswild.rb +118 -112
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e75768f7cf7390cfb3c36192245897160fb1529
|
4
|
+
data.tar.gz: 83570aeb82387bec304eb5998f49ac72c2c23f00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73d40d8b2d14317b7fb16ee61942c6212580951c2d337fe407c5d9765e0076c7950006f2401f87985750fbbd6439dfcda40321bd394edf713f802e33c869fe52
|
7
|
+
data.tar.gz: 24ec5bad1f5b8f0dfcafcb37fc3b7b30c4581829673b540c294ff93d0cab79ec2f5f83694ad839dbceee28fb0ec5047b8268cc8ad248f4ffb8bbaa675c10dffb
|
data/lib/rorvswild/version.rb
CHANGED
data/lib/rorvswild.rb
CHANGED
@@ -1,139 +1,145 @@
|
|
1
1
|
require "rorvswild/version"
|
2
2
|
|
3
|
-
|
4
|
-
def self.
|
5
|
-
|
6
|
-
api_url: "http://www.rorvswild.com/api",
|
7
|
-
sql_threshold: 500
|
8
|
-
}
|
3
|
+
module RorVsWild
|
4
|
+
def self.new(*args)
|
5
|
+
Client.new(*args) # Compatibility with 0.0.1
|
9
6
|
end
|
10
7
|
|
11
|
-
|
8
|
+
class Client
|
9
|
+
def self.default_config
|
10
|
+
{
|
11
|
+
api_url: "http://www.rorvswild.com/api",
|
12
|
+
sql_threshold: 500
|
13
|
+
}
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
config = RorVsWild.default_config.merge(config)
|
15
|
-
@sql_threshold = config[:sql_threshold]
|
16
|
-
@api_url = config[:api_url]
|
17
|
-
@api_key = config[:api_key]
|
18
|
-
@app_id = config[:app_id]
|
19
|
-
setup_callbacks
|
20
|
-
end
|
16
|
+
attr_reader :api_url, :api_key, :app_id, :sql_threshold, :error, :request
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
def initialize(config)
|
19
|
+
config = self.class.default_config.merge(config)
|
20
|
+
@sql_threshold = config[:sql_threshold]
|
21
|
+
@api_url = config[:api_url]
|
22
|
+
@api_key = config[:api_key]
|
23
|
+
@app_id = config[:app_id]
|
24
|
+
setup_callbacks
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
def setup_callbacks
|
28
|
+
ApplicationController.rescue_from(StandardError, &method(:after_exception))
|
29
|
+
ActiveSupport::Notifications.subscribe("sql.active_record", &method(:after_sql_query))
|
30
|
+
ActiveSupport::Notifications.subscribe("render_template.action_view", &method(:after_view_rendering))
|
31
|
+
ActiveSupport::Notifications.subscribe("process_action.action_controller", &method(:after_http_request))
|
32
|
+
ActiveSupport::Notifications.subscribe("start_processing.action_controller", &method(:before_http_request))
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
rescue => ex
|
44
|
-
Rails.logger.error("[RorVsWild] " + ex.inspect)
|
45
|
-
Rails.logger.error("[RorVsWild] " + ex.backtrace.join("\n[RorVsWild] "))
|
46
|
-
end
|
35
|
+
def before_http_request(name, start, finish, id, payload)
|
36
|
+
@request = {controller: payload[:controller], action: payload[:action], path: payload[:path]}
|
37
|
+
@queries = []
|
38
|
+
@views = []
|
39
|
+
@error = nil
|
40
|
+
end
|
47
41
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
42
|
+
def after_http_request(name, start, finish, id, payload)
|
43
|
+
request[:db_runtime] = (payload[:db_runtime] || 0).round
|
44
|
+
request[:view_runtime] = (payload[:view_runtime] || 0).round
|
45
|
+
request[:other_runtime] = compute_duration(start, finish) - request[:db_runtime] - request[:view_runtime]
|
46
|
+
request[:params] = params_filter.filter(payload[:params]) if error
|
47
|
+
Thread.new { post_request }
|
48
|
+
rescue => ex
|
49
|
+
Rails.logger.error("[RorVsWild] " + ex.inspect)
|
50
|
+
Rails.logger.error("[RorVsWild] " + ex.backtrace.join("\n[RorVsWild] "))
|
51
|
+
end
|
58
52
|
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
def after_sql_query(name, start, finish, id, payload)
|
54
|
+
return if !queries || payload[:name] == "EXPLAIN".freeze
|
55
|
+
runtime, sql, plan = compute_duration(start, finish), nil, nil
|
56
|
+
file, line, method = extract_file_and_line_from_call_stack(caller)
|
57
|
+
plan = explain(sql = payload[:sql], payload[:binds]) if runtime > sql_threshold
|
58
|
+
queries << {file: file, line: line, sql: sql, plan: plan, runtime: runtime}
|
59
|
+
rescue => ex
|
60
|
+
Rails.logger.error("[RorVsWild] " + ex.inspect)
|
61
|
+
Rails.logger.error("[RorVsWild] " + ex.backtrace.join("\n[RorVsWild] "))
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
exception: exception.class.to_s,
|
67
|
-
backtrace: exception.backtrace,
|
68
|
-
message: exception.message,
|
69
|
-
file: relative_path(file),
|
70
|
-
line: line.to_i
|
71
|
-
}
|
72
|
-
raise exception
|
73
|
-
end
|
64
|
+
def after_view_rendering(name, start, finish, id, payload)
|
65
|
+
views << {file: relative_path(payload[:identifier]), runtime: compute_duration(start, finish)} if views
|
66
|
+
end
|
74
67
|
|
75
|
-
|
76
|
-
|
77
|
-
|
68
|
+
def after_exception(exception)
|
69
|
+
file, line = exception.backtrace.first.split(":")
|
70
|
+
@error = {
|
71
|
+
exception: exception.class.to_s,
|
72
|
+
backtrace: exception.backtrace,
|
73
|
+
message: exception.message,
|
74
|
+
file: relative_path(file),
|
75
|
+
line: line.to_i
|
76
|
+
}
|
77
|
+
raise exception
|
78
|
+
end
|
78
79
|
|
79
|
-
|
80
|
+
#######################
|
81
|
+
### Private methods ###
|
82
|
+
#######################
|
80
83
|
|
81
|
-
|
82
|
-
@queries
|
83
|
-
end
|
84
|
+
private
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
86
|
+
def queries
|
87
|
+
@queries
|
88
|
+
end
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
90
|
+
def views
|
91
|
+
@views
|
92
|
+
end
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
def slowest_views
|
95
|
+
views.sort { |h1, h2| h2[:runtime] <=> h1[:runtime] }[0, 25]
|
96
|
+
end
|
96
97
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
rescue => ex
|
101
|
-
end
|
98
|
+
def slowest_queries
|
99
|
+
queries.sort { |h1, h2| h2[:runtime] <=> h1[:runtime] }[0, 25]
|
100
|
+
end
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
def explain(sql, binds)
|
103
|
+
rows = ActiveRecord::Base.connection.exec_query("EXPLAIN " + sql, "EXPLAIN", binds)
|
104
|
+
rows.map { |row| row["QUERY PLAN"] }.join("\n")
|
105
|
+
rescue => ex
|
106
|
+
end
|
106
107
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
file.sub!(Rails.root.to_s, "")
|
111
|
-
method.sub!("block in ", "")
|
112
|
-
method.sub!("in `", "")
|
113
|
-
method.sub!("'", "")
|
114
|
-
[file, line, method]
|
115
|
-
end
|
108
|
+
def post_request
|
109
|
+
post("/requests", request: request.merge(queries: slowest_queries, views: slowest_views, error: error))
|
110
|
+
end
|
116
111
|
|
117
|
-
|
118
|
-
|
119
|
-
|
112
|
+
def extract_file_and_line_from_call_stack(stack)
|
113
|
+
file, line, method = (stack.find { |str| str.include?(Rails.root.to_s) } ||
|
114
|
+
stack.find { |str| str.include?("(irb):") }).split(":")
|
115
|
+
file.sub!(Rails.root.to_s, "")
|
116
|
+
method.sub!("block in ", "")
|
117
|
+
method.sub!("in `", "")
|
118
|
+
method.sub!("'", "")
|
119
|
+
[file, line, method]
|
120
|
+
end
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
|
122
|
+
def compute_duration(start, finish)
|
123
|
+
((finish - start) * 1000).round
|
124
|
+
end
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
126
|
+
def relative_path(path)
|
127
|
+
path.sub(Rails.root.to_s, "")
|
128
|
+
end
|
129
|
+
|
130
|
+
def post(path, data)
|
131
|
+
uri = URI(api_url + path)
|
132
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
133
|
+
post = Net::HTTP::Post.new(uri)
|
134
|
+
post.content_type = "application/json"
|
135
|
+
post.basic_auth(app_id, api_key)
|
136
|
+
post.body = data.to_json
|
137
|
+
http.request(post)
|
138
|
+
end
|
133
139
|
end
|
134
|
-
end
|
135
140
|
|
136
|
-
|
137
|
-
|
141
|
+
def params_filter
|
142
|
+
@params_filter ||= ActionDispatch::Http::ParameterFilter.new(Rails.application.config.filter_parameters)
|
143
|
+
end
|
138
144
|
end
|
139
145
|
end
|
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.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Bernard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|