rorvswild 1.7.1 → 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 +201 -36
- data/lib/rorvswild/local/local.html.erb +266 -68
- data/lib/rorvswild/local/middleware.rb +16 -0
- data/lib/rorvswild/local/queue.rb +45 -7
- data/lib/rorvswild/local/stylesheet/local.css +261 -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/middleware.rb +7 -7
- 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 +3 -3
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,33 +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)
|
42
71
|
}
|
43
72
|
|
44
73
|
RorVsWild.Local.prototype.toggleCommand = function(event) {
|
45
|
-
document.querySelector(event.currentTarget.
|
74
|
+
document.querySelector(event.currentTarget.dataset.target).classList.toggle("is-open")
|
46
75
|
}
|
47
76
|
|
48
77
|
RorVsWild.Local.prototype.expand = function() {
|
49
|
-
this.currentRequest = this.requests[0]
|
50
78
|
this.active = true
|
51
|
-
this.
|
52
|
-
window.addEventListener("keydown", this.keydown.bind(this))
|
79
|
+
this.goToRequestDetail(event)
|
53
80
|
}
|
54
81
|
|
55
82
|
RorVsWild.Local.prototype.collapse = function() {
|
56
83
|
this.active = false
|
57
|
-
this.
|
84
|
+
this.goToRequestIndex()
|
58
85
|
}
|
59
86
|
|
60
87
|
RorVsWild.Local.prototype.keydown = function(event) {
|
@@ -62,8 +89,17 @@ RorVsWild.Local.prototype.keydown = function(event) {
|
|
62
89
|
this.collapse()
|
63
90
|
}
|
64
91
|
|
65
|
-
RorVsWild.Local.
|
66
|
-
|
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))
|
67
103
|
}
|
68
104
|
|
69
105
|
RorVsWild.Local.formatImpact = function(impact) {
|
@@ -77,15 +113,38 @@ RorVsWild.Local.formatDateTime = function(date) {
|
|
77
113
|
return [date.getDate(), months[date.getMonth()], hours + ":" + minutes].join(" ")
|
78
114
|
}
|
79
115
|
|
80
|
-
RorVsWild.Local.prototype.
|
81
|
-
|
82
|
-
|
83
|
-
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))
|
131
|
+
}
|
132
|
+
|
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))
|
84
142
|
}
|
85
143
|
|
86
|
-
RorVsWild.Local.prototype.
|
87
|
-
|
88
|
-
this.
|
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")
|
89
148
|
}
|
90
149
|
|
91
150
|
RorVsWild.Local.prototype.containerClass = function() {
|
@@ -102,6 +161,13 @@ RorVsWild.Local.kindToLanguage = function(kind) {
|
|
102
161
|
}
|
103
162
|
}
|
104
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
|
+
|
105
171
|
RorVsWild.Local.lastId = 0
|
106
172
|
|
107
173
|
RorVsWild.Local.nextId = function() {
|
@@ -109,15 +175,15 @@ RorVsWild.Local.nextId = function() {
|
|
109
175
|
}
|
110
176
|
|
111
177
|
RorVsWild.Local.Request = function(data) {
|
112
|
-
this.id = RorVsWild.Local.nextId()
|
113
178
|
this.data = data
|
179
|
+
this.uuid = data.uuid
|
114
180
|
this.name = data.name
|
115
181
|
this.path = data.path
|
116
182
|
this.queuedAt = RorVsWild.Local.formatDateTime(new Date(data.queued_at))
|
117
183
|
}
|
118
184
|
|
119
185
|
RorVsWild.Local.Request.prototype.runtime = function() {
|
120
|
-
return RorVsWild.Local.
|
186
|
+
return RorVsWild.Local.relevantRounding(this.data.runtime)
|
121
187
|
}
|
122
188
|
|
123
189
|
RorVsWild.Local.Request.prototype.sections = function() {
|
@@ -126,19 +192,118 @@ RorVsWild.Local.Request.prototype.sections = function() {
|
|
126
192
|
var object = {
|
127
193
|
id: RorVsWild.Local.nextId(),
|
128
194
|
impact: RorVsWild.Local.formatImpact(runtime * 100 / this.data.runtime),
|
129
|
-
|
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),
|
130
201
|
command: section.kind != "view" ? section.command : null,
|
131
202
|
calls: section.calls,
|
132
203
|
kind: section.kind.substring(0, 7),
|
133
204
|
file: section.file,
|
134
205
|
line: section.line,
|
135
|
-
|
136
|
-
|
137
|
-
}
|
138
|
-
if (RorVsWild.Local.editorUrl) {
|
139
|
-
var path = section.file[0] == "/" ? section.file : this.data.environment.cwd + "/" + section.file
|
140
|
-
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)
|
141
208
|
}
|
142
209
|
return object
|
143
|
-
}.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")
|
144
309
|
}
|