rorvswild 1.7.1 → 1.8.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/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
|
}
|