rorvswild 1.7.0 → 1.8.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 +4 -4
- data/lib/rorvswild/agent.rb +38 -11
- data/lib/rorvswild/local/javascript/local.js +205 -35
- data/lib/rorvswild/local/local.html.erb +294 -88
- data/lib/rorvswild/local/middleware.rb +16 -0
- data/lib/rorvswild/local/queue.rb +45 -7
- data/lib/rorvswild/local/stylesheet/local.css +327 -59
- data/lib/rorvswild/local/stylesheet/vendor/prism.css +1 -1
- data/lib/rorvswild/local.rb +1 -1
- data/lib/rorvswild/plugin/action_controller.rb +1 -1
- data/lib/rorvswild/plugin/action_mailer.rb +1 -1
- data/lib/rorvswild/plugin/action_view.rb +1 -1
- data/lib/rorvswild/plugin/active_job.rb +1 -1
- data/lib/rorvswild/plugin/active_record.rb +1 -3
- data/lib/rorvswild/plugin/delayed_job.rb +10 -1
- data/lib/rorvswild/plugin/middleware.rb +36 -6
- data/lib/rorvswild/plugin/redis.rb +2 -6
- data/lib/rorvswild/queue.rb +4 -0
- data/lib/rorvswild/section.rb +62 -29
- data/lib/rorvswild/version.rb +1 -1
- data/lib/rorvswild.rb +13 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1da086576b7ffa892064483efd18f9c545ff1ee6e960f23374e82e78722056c5
|
4
|
+
data.tar.gz: cfc4561f2aec3a8880b80e81daf71492516d2d137901e649db588fe4a05988f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf988a2610372ae91dd61503005382f962b9656dcfd4f5edd48875a281e133cb333c6b1424d001dd76109522b71ea7c3818a69fffa687160bbc3b1ae992d6d9a
|
7
|
+
data.tar.gz: 41ab36b5b9e3eb59bfd9f28edc6a96fce2081df3be66fc4ac3217d94de4606f0edc858f09ece8a7700b0a9b7be84b65e9f779d968294186ccd4b3cc1d6a43c80
|
data/lib/rorvswild/agent.rb
CHANGED
@@ -61,12 +61,34 @@ module RorVsWild
|
|
61
61
|
current_data ? measure_section(name, kind: kind, &block) : measure_job(name, &block)
|
62
62
|
end
|
63
63
|
|
64
|
-
def
|
64
|
+
def measure_method(method)
|
65
|
+
return if method.name.end_with?("_measured_by_rorvswild")
|
66
|
+
if method.is_a?(Method)
|
67
|
+
method_full_name = [method.receiver, method.name].join(".") # Method => class method
|
68
|
+
else
|
69
|
+
method_full_name = [method.owner, method.name].join("#") # UnboundMethod => instance method
|
70
|
+
end
|
71
|
+
method_alias = :"#{method.name}_measured_by_rorvswild"
|
72
|
+
return if method.owner.method_defined?(method_alias)
|
73
|
+
method.owner.alias_method(method_alias, method.name)
|
74
|
+
method_file, method_line = method.source_location
|
75
|
+
method_file = locator.relative_path(File.expand_path(method_file))
|
76
|
+
method.owner.define_method(method.name) do |*args|
|
77
|
+
section = Section.start
|
78
|
+
section.file = method_file
|
79
|
+
section.line = method_line
|
80
|
+
section.commands << method_full_name
|
81
|
+
result = send(method_alias, *args)
|
82
|
+
Section.stop
|
83
|
+
result
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def measure_section(name, kind: "code", &block)
|
65
88
|
return block.call unless current_data
|
66
89
|
begin
|
67
90
|
RorVsWild::Section.start do |section|
|
68
|
-
section.
|
69
|
-
section.command = name
|
91
|
+
section.commands << name
|
70
92
|
section.kind = kind
|
71
93
|
end
|
72
94
|
block.call
|
@@ -85,6 +107,8 @@ module RorVsWild
|
|
85
107
|
push_exception(ex, parameters: parameters, job: {name: name})
|
86
108
|
raise
|
87
109
|
ensure
|
110
|
+
gc = Section.stop_gc_timing(current_data[:gc_section])
|
111
|
+
current_data[:sections] << gc if gc.calls > 0
|
88
112
|
current_data[:runtime] = RorVsWild.clock_milliseconds - current_data[:started_at]
|
89
113
|
queue_job
|
90
114
|
end
|
@@ -95,8 +119,10 @@ module RorVsWild
|
|
95
119
|
end
|
96
120
|
|
97
121
|
def stop_request
|
98
|
-
return unless current_data
|
99
|
-
|
122
|
+
return unless data = current_data
|
123
|
+
gc = Section.stop_gc_timing(data[:gc_section])
|
124
|
+
data[:sections] << gc if gc.calls > 0 && gc.total_ms > 0
|
125
|
+
data[:runtime] = RorVsWild.clock_milliseconds - current_data[:started_at]
|
100
126
|
queue_request
|
101
127
|
end
|
102
128
|
|
@@ -110,7 +136,7 @@ module RorVsWild
|
|
110
136
|
end
|
111
137
|
|
112
138
|
def record_error(exception, context = nil)
|
113
|
-
|
139
|
+
queue_error(exception_to_hash(exception, context)) if !ignored_exception?(exception)
|
114
140
|
end
|
115
141
|
|
116
142
|
def push_exception(exception, options = nil)
|
@@ -171,10 +197,11 @@ module RorVsWild
|
|
171
197
|
|
172
198
|
def initialize_data
|
173
199
|
Thread.current[:rorvswild_data] = {
|
174
|
-
sections: [],
|
175
|
-
section_stack: [],
|
176
|
-
environment: Host.to_h,
|
177
200
|
started_at: RorVsWild.clock_milliseconds,
|
201
|
+
gc_section: Section.start_gc_timing,
|
202
|
+
environment: Host.to_h,
|
203
|
+
section_stack: [],
|
204
|
+
sections: [],
|
178
205
|
}
|
179
206
|
end
|
180
207
|
|
@@ -193,8 +220,8 @@ module RorVsWild
|
|
193
220
|
queue.push_job(cleanup_data)
|
194
221
|
end
|
195
222
|
|
196
|
-
def
|
197
|
-
|
223
|
+
def queue_error(hash)
|
224
|
+
queue.push_error(hash)
|
198
225
|
end
|
199
226
|
|
200
227
|
def exception_to_hash(exception, context = nil)
|
@@ -2,24 +2,47 @@ var RorVsWild = this.RorVsWild = {};
|
|
2
2
|
|
3
3
|
RorVsWild.Local = function(container) {
|
4
4
|
this.root = container
|
5
|
-
this.
|
6
|
-
RorVsWild.Local.editorUrl = container.
|
7
|
-
this.
|
5
|
+
this.active = false
|
6
|
+
RorVsWild.Local.editorUrl = container.dataset.editorUrl
|
7
|
+
if (this.embedded = location.pathname != "/rorvswild")
|
8
|
+
window.addEventListener("keydown", this.keydown.bind(this))
|
9
|
+
else
|
10
|
+
this.active = true
|
11
|
+
this.goToRequestIndex()
|
12
|
+
}
|
13
|
+
|
14
|
+
RorVsWild.Local.prototype.getRequests = function(callback) {
|
15
|
+
this.getJson("/rorvswild/requests.json", function(data) {
|
16
|
+
this.requests = data.map(function(attributes) { return new RorVsWild.Local.Request(attributes) })
|
17
|
+
callback()
|
18
|
+
}.bind(this))
|
19
|
+
}
|
20
|
+
|
21
|
+
RorVsWild.Local.prototype.getJobs = function(callback) {
|
22
|
+
this.getJson("/rorvswild/jobs.json", function(data) {
|
23
|
+
this.jobs = data.map(function(attributes) { return new RorVsWild.Local.Request(attributes) })
|
24
|
+
callback()
|
25
|
+
}.bind(this))
|
26
|
+
}
|
27
|
+
|
28
|
+
RorVsWild.Local.prototype.getErrors = function(callback) {
|
29
|
+
this.getJson("/rorvswild/errors.json", function(data) {
|
30
|
+
this.errors = data.map(function(attributes) { return new RorVsWild.Local.Error(attributes) })
|
31
|
+
callback()
|
32
|
+
}.bind(this))
|
8
33
|
}
|
9
34
|
|
10
|
-
RorVsWild.Local.prototype.
|
35
|
+
RorVsWild.Local.prototype.getJson = function(path, callback) {
|
11
36
|
var request = new XMLHttpRequest()
|
12
|
-
request.open("GET",
|
37
|
+
request.open("GET", path, true)
|
13
38
|
|
14
39
|
request.onload = function(event) {
|
15
40
|
if (request.status >= 200 && request.status < 400) {
|
16
|
-
|
17
|
-
this.requests = this.data.map(function(data) { return new RorVsWild.Local.Request(data) })
|
18
|
-
this.render()
|
41
|
+
callback(JSON.parse(request.response))
|
19
42
|
} else {
|
20
43
|
console.error("Unexpected response code " + request.status + " while fetching RorVswild data.")
|
21
44
|
}
|
22
|
-
}
|
45
|
+
}
|
23
46
|
|
24
47
|
request.onerror = function() {
|
25
48
|
console.error("Error while fetching RorVswild data.")
|
@@ -28,29 +51,37 @@ RorVsWild.Local.prototype.fetchData = function() {
|
|
28
51
|
request.send()
|
29
52
|
}
|
30
53
|
|
31
|
-
RorVsWild.Local.prototype.render = function() {
|
54
|
+
RorVsWild.Local.prototype.render = function(view) {
|
55
|
+
this.view = view
|
32
56
|
Barber.render("RorVsWild.Local", this, this.root)
|
33
57
|
Prism.highlightAllUnder(this.root)
|
34
58
|
}
|
35
59
|
|
60
|
+
RorVsWild.Local.prototype.renderBody = function() {
|
61
|
+
var templates = Barber.partials()
|
62
|
+
return Mustache.render(templates["RorVsWild.Local." + this.view], this, templates)
|
63
|
+
}
|
64
|
+
|
36
65
|
RorVsWild.Local.prototype.lastRuntime = function() {
|
37
66
|
return this.requests[0] ? this.requests[0].runtime() : "N/A"
|
38
67
|
}
|
39
68
|
|
40
|
-
RorVsWild.Local.prototype.toggle = function() {
|
41
|
-
this.active ? this.collapse() : this.expand()
|
69
|
+
RorVsWild.Local.prototype.toggle = function(event) {
|
70
|
+
this.active ? this.collapse() : this.expand(event)
|
71
|
+
}
|
72
|
+
|
73
|
+
RorVsWild.Local.prototype.toggleCommand = function(event) {
|
74
|
+
document.querySelector(event.currentTarget.dataset.target).classList.toggle("is-open")
|
42
75
|
}
|
43
76
|
|
44
77
|
RorVsWild.Local.prototype.expand = function() {
|
45
|
-
this.currentRequest = this.requests[0]
|
46
78
|
this.active = true
|
47
|
-
this.
|
48
|
-
window.addEventListener("keydown", this.keydown.bind(this))
|
79
|
+
this.goToRequestDetail(event)
|
49
80
|
}
|
50
81
|
|
51
82
|
RorVsWild.Local.prototype.collapse = function() {
|
52
83
|
this.active = false
|
53
|
-
this.
|
84
|
+
this.goToRequestIndex()
|
54
85
|
}
|
55
86
|
|
56
87
|
RorVsWild.Local.prototype.keydown = function(event) {
|
@@ -58,8 +89,17 @@ RorVsWild.Local.prototype.keydown = function(event) {
|
|
58
89
|
this.collapse()
|
59
90
|
}
|
60
91
|
|
61
|
-
RorVsWild.Local.
|
62
|
-
|
92
|
+
RorVsWild.Local.relevantRounding = function(value) {
|
93
|
+
if (!value || value == 0)
|
94
|
+
return 0
|
95
|
+
else if (value < 0.01)
|
96
|
+
return value
|
97
|
+
else if (value < 1)
|
98
|
+
return Number(value.toFixed(2))
|
99
|
+
else if (value < 10)
|
100
|
+
return Number(value.toFixed(1))
|
101
|
+
else
|
102
|
+
return Number(value.toFixed(0))
|
63
103
|
}
|
64
104
|
|
65
105
|
RorVsWild.Local.formatImpact = function(impact) {
|
@@ -73,15 +113,38 @@ RorVsWild.Local.formatDateTime = function(date) {
|
|
73
113
|
return [date.getDate(), months[date.getMonth()], hours + ":" + minutes].join(" ")
|
74
114
|
}
|
75
115
|
|
76
|
-
RorVsWild.Local.prototype.
|
77
|
-
|
78
|
-
|
79
|
-
this.
|
116
|
+
RorVsWild.Local.prototype.goToRequestDetail = function(event) {
|
117
|
+
this.root.dataset.tab = "requests"
|
118
|
+
var uuid = event.currentTarget.dataset.uuid
|
119
|
+
this.currentRequest = this.requests.find(function(req) { return req.uuid == uuid })
|
120
|
+
this.render("RequestDetail")
|
121
|
+
}
|
122
|
+
|
123
|
+
RorVsWild.Local.prototype.goToRequestIndex = function(event) {
|
124
|
+
this.root.dataset.tab = "requests"
|
125
|
+
this.getRequests(function() { this.render("RequestIndex") }.bind(this))
|
126
|
+
}
|
127
|
+
|
128
|
+
RorVsWild.Local.prototype.goToJobIndex = function(event) {
|
129
|
+
this.root.dataset.tab = "jobs"
|
130
|
+
this.getJobs(function() { this.render("JobIndex") }.bind(this))
|
80
131
|
}
|
81
132
|
|
82
|
-
RorVsWild.Local.prototype.
|
83
|
-
|
84
|
-
this.
|
133
|
+
RorVsWild.Local.prototype.goToJobDetail = function(event) {
|
134
|
+
var uuid = event.currentTarget.dataset.uuid
|
135
|
+
this.currentJob = this.jobs.find(function(job) { return job.uuid == uuid })
|
136
|
+
this.render("JobDetail")
|
137
|
+
}
|
138
|
+
|
139
|
+
RorVsWild.Local.prototype.goToErrors = function(event) {
|
140
|
+
this.root.dataset.tab = "errors"
|
141
|
+
this.getErrors(function() { this.render("ErrorIndex") }.bind(this))
|
142
|
+
}
|
143
|
+
|
144
|
+
RorVsWild.Local.prototype.goToErrorDetail = function(event) {
|
145
|
+
var uuid = event.currentTarget.dataset.uuid
|
146
|
+
this.currentError = this.errors.find(function(err) { return err.uuid == uuid })
|
147
|
+
this.render("ErrorDetail")
|
85
148
|
}
|
86
149
|
|
87
150
|
RorVsWild.Local.prototype.containerClass = function() {
|
@@ -98,6 +161,13 @@ RorVsWild.Local.kindToLanguage = function(kind) {
|
|
98
161
|
}
|
99
162
|
}
|
100
163
|
|
164
|
+
RorVsWild.Local.pathToUrl = function(cwd, file, line) {
|
165
|
+
if (RorVsWild.Local.editorUrl) {
|
166
|
+
var path = file[0] == "/" ? file : cwd + "/" + file
|
167
|
+
return RorVsWild.Local.editorUrl.replace("${path}", path).replace("${line}", line)
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
101
171
|
RorVsWild.Local.lastId = 0
|
102
172
|
|
103
173
|
RorVsWild.Local.nextId = function() {
|
@@ -105,35 +175,135 @@ RorVsWild.Local.nextId = function() {
|
|
105
175
|
}
|
106
176
|
|
107
177
|
RorVsWild.Local.Request = function(data) {
|
108
|
-
this.id = RorVsWild.Local.nextId()
|
109
178
|
this.data = data
|
179
|
+
this.uuid = data.uuid
|
110
180
|
this.name = data.name
|
111
181
|
this.path = data.path
|
112
182
|
this.queuedAt = RorVsWild.Local.formatDateTime(new Date(data.queued_at))
|
113
183
|
}
|
114
184
|
|
115
185
|
RorVsWild.Local.Request.prototype.runtime = function() {
|
116
|
-
return RorVsWild.Local.
|
186
|
+
return RorVsWild.Local.relevantRounding(this.data.runtime)
|
117
187
|
}
|
118
188
|
|
119
189
|
RorVsWild.Local.Request.prototype.sections = function() {
|
120
190
|
return this.data.sections.map(function(section) {
|
121
191
|
var runtime = (section.total_runtime - section.children_runtime)
|
122
192
|
var object = {
|
193
|
+
id: RorVsWild.Local.nextId(),
|
123
194
|
impact: RorVsWild.Local.formatImpact(runtime * 100 / this.data.runtime),
|
124
|
-
|
195
|
+
language: RorVsWild.Local.kindToLanguage(section.kind),
|
196
|
+
totalRuntime: RorVsWild.Local.relevantRounding(section.total_runtime),
|
197
|
+
childrenRuntime: RorVsWild.Local.relevantRounding(section.children_runtime),
|
198
|
+
selfRuntime: RorVsWild.Local.relevantRounding(runtime),
|
199
|
+
runtime: RorVsWild.Local.relevantRounding(runtime),
|
200
|
+
averageRuntime: RorVsWild.Local.relevantRounding(runtime / section.calls),
|
125
201
|
command: section.kind != "view" ? section.command : null,
|
126
202
|
calls: section.calls,
|
127
203
|
kind: section.kind.substring(0, 7),
|
128
204
|
file: section.file,
|
129
205
|
line: section.line,
|
130
|
-
|
131
|
-
|
132
|
-
}
|
133
|
-
if (RorVsWild.Local.editorUrl) {
|
134
|
-
var path = section.file[0] == "/" ? section.file : this.data.environment.cwd + "/" + section.file
|
135
|
-
object.url = RorVsWild.Local.editorUrl.replace("${path}", path).replace("${line}", section.line)
|
206
|
+
location: section.kind == "view" ? section.file : section.file + ":" + section.line,
|
207
|
+
locationUrl: RorVsWild.Local.pathToUrl(this.data.environment.cwd, section.file, section.line)
|
136
208
|
}
|
137
209
|
return object
|
138
|
-
}.bind(this)).sort(function(a, b) { return b.
|
210
|
+
}.bind(this)).sort(function(a, b) { return b.selfRuntime - a.selfRuntime })
|
211
|
+
}
|
212
|
+
|
213
|
+
RorVsWild.Local.Request.prototype.sectionsImpactPerKind = function() {
|
214
|
+
var total = 0
|
215
|
+
var perKind = this.sections().reduce(function(object, section) {
|
216
|
+
object[section.kind] = (object[section.kind] || 0) + section.runtime
|
217
|
+
total += section.runtime
|
218
|
+
return object
|
219
|
+
}, {})
|
220
|
+
return Object.entries(perKind).sort(function(a, b) { return b[1] - a[1] })
|
221
|
+
.map(function(item) { return {kind: item[0], impact: Math.round((item[1] / total * 100) * 10) / 10} })
|
222
|
+
}
|
223
|
+
|
224
|
+
RorVsWild.Local.Error = function(data) {
|
225
|
+
this.data = data
|
226
|
+
this.backtrace = data.backtrace
|
227
|
+
this.context = data.context
|
228
|
+
this.environment = data.environment
|
229
|
+
this.exception = data.exception
|
230
|
+
this.message = data.message
|
231
|
+
this.file = data.file
|
232
|
+
this.line = data.line
|
233
|
+
this.locationUrl = RorVsWild.Local.pathToUrl(data.environment.cwd, data.file, data.line)
|
234
|
+
this.message = data.message
|
235
|
+
this.queuedAt = RorVsWild.Local.formatDateTime(new Date(data.queued_at))
|
236
|
+
this.uuid = data.uuid
|
237
|
+
this.parameters = data.parameters
|
238
|
+
this.request = data.request
|
239
|
+
this.job = data.job
|
240
|
+
}
|
241
|
+
|
242
|
+
RorVsWild.Local.Error.prototype.shortMessage = function() {
|
243
|
+
return this.message.length < 160 ? this.message : this.message.substring(0, 160) + "…"
|
244
|
+
}
|
245
|
+
|
246
|
+
RorVsWild.Local.Error.prototype.hasRequest = function() {
|
247
|
+
return this.request != null
|
248
|
+
}
|
249
|
+
|
250
|
+
RorVsWild.Local.Error.prototype.eachRequestProperty = function() {
|
251
|
+
return this.request && this.objectToProperties(this.request)
|
252
|
+
}
|
253
|
+
|
254
|
+
RorVsWild.Local.Error.prototype.hasParameters = function() {
|
255
|
+
return this.parameters != null
|
256
|
+
}
|
257
|
+
|
258
|
+
RorVsWild.Local.Error.prototype.parametersInJson = function() {
|
259
|
+
return JSON.stringify(this.parameters, null, 2)
|
260
|
+
}
|
261
|
+
|
262
|
+
RorVsWild.Local.Error.prototype.hasRequestHeaders = function() {
|
263
|
+
return this.request && this.request.headers != null
|
264
|
+
}
|
265
|
+
|
266
|
+
RorVsWild.Local.Error.prototype.eachRequestHeader = function() {
|
267
|
+
return this.request && this.request.headers && this.objectToProperties(this.request.headers)
|
268
|
+
}
|
269
|
+
|
270
|
+
RorVsWild.Local.Error.prototype.eachEnvironment = function() {
|
271
|
+
return this.objectToProperties(this.environment)
|
272
|
+
}
|
273
|
+
|
274
|
+
RorVsWild.Local.Error.prototype.hasContext = function() {
|
275
|
+
return this.context != null
|
276
|
+
}
|
277
|
+
|
278
|
+
RorVsWild.Local.Error.prototype.eachContext = function() {
|
279
|
+
return this.objectToProperties(this.context)
|
280
|
+
}
|
281
|
+
|
282
|
+
RorVsWild.Local.Error.prototype.objectToProperties = function(object) {
|
283
|
+
var array = []
|
284
|
+
for (var name in object)
|
285
|
+
if (object.hasOwnProperty(name))
|
286
|
+
array.push({name: name, value: object[name]})
|
287
|
+
return array
|
288
|
+
}
|
289
|
+
|
290
|
+
RorVsWild.Local.Error.prototype.compactBacktrace = function() {
|
291
|
+
var cwd = this.environment.cwd
|
292
|
+
cwd.endsWith("/") || (cwd += "/")
|
293
|
+
var vendorPath = (cwd + "vendor/bundle")
|
294
|
+
return this.backtrace.filter(function(path) {
|
295
|
+
return path.startsWith(cwd) && !path.startsWith(vendorPath)
|
296
|
+
}).map(function(path) { return path.replace(cwd, "") }).join("\n")
|
297
|
+
}
|
298
|
+
|
299
|
+
RorVsWild.Local.Error.prototype.compactBacktraceLocations = function() {
|
300
|
+
var cwd = this.environment.cwd
|
301
|
+
return this.compactBacktrace().split("\n").map(function(path) {
|
302
|
+
var fileAndLine = path.split(":")
|
303
|
+
return {path: path, url: RorVsWild.Local.pathToUrl(cwd, fileAndLine[0], fileAndLine[1])}
|
304
|
+
})
|
305
|
+
}
|
306
|
+
|
307
|
+
RorVsWild.Local.Error.prototype.formattedBacktrace = function() {
|
308
|
+
return this.backtrace.join("\n")
|
139
309
|
}
|