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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0dc87868138ecb496f99d1d4adc670f0776b3fe4fa8312ec8c9126e33800c62
4
- data.tar.gz: 05334e640532cefa98e18c895d2c599d45714812ed948dd5150748df0d139722
3
+ metadata.gz: 1da086576b7ffa892064483efd18f9c545ff1ee6e960f23374e82e78722056c5
4
+ data.tar.gz: cfc4561f2aec3a8880b80e81daf71492516d2d137901e649db588fe4a05988f1
5
5
  SHA512:
6
- metadata.gz: e1476eb8421864a1cdfc904988204b5da750249d1054d72ee0a1d2ab1a07a1aba14fe9851ee54a66f9f7cae442f9e025b216f5b1d99fc73f26474f2c3e8a0347
7
- data.tar.gz: 66e61e2d41d97d42a80e8f6854badd6cd1247449a8a1e3192415885864bdca62339aff4b23640edd067f8931f4e9c1f81bbda84ec4df975e61be3e34df1556ed
6
+ metadata.gz: bf988a2610372ae91dd61503005382f962b9656dcfd4f5edd48875a281e133cb333c6b1424d001dd76109522b71ea7c3818a69fffa687160bbc3b1ae992d6d9a
7
+ data.tar.gz: 41ab36b5b9e3eb59bfd9f28edc6a96fce2081df3be66fc4ac3217d94de4606f0edc858f09ece8a7700b0a9b7be84b65e9f779d968294186ccd4b3cc1d6a43c80
@@ -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 measure_section(name, kind: "code", appendable_command: false, &block)
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.appendable_command = appendable_command
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
- current_data[:runtime] = RorVsWild.clock_milliseconds - current_data[:started_at]
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
- send_error(exception_to_hash(exception, context)) if !ignored_exception?(exception)
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 send_error(hash)
197
- client.post_async("/errors".freeze, error: hash)
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.embedded = !(this.active = location.pathname == "/rorvswild")
6
- RorVsWild.Local.editorUrl = container.getAttribute("data-editor-url")
7
- this.fetchData()
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.fetchData = function() {
35
+ RorVsWild.Local.prototype.getJson = function(path, callback) {
11
36
  var request = new XMLHttpRequest()
12
- request.open("GET", "/rorvswild.json", true)
37
+ request.open("GET", path, true)
13
38
 
14
39
  request.onload = function(event) {
15
40
  if (request.status >= 200 && request.status < 400) {
16
- this.data = JSON.parse(request.response)
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
- }.bind(this)
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.render()
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.render()
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.formatRuntime = function(runtime) {
62
- return runtime > 0 && runtime < 1 ? "<1" : Math.round(runtime)
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.goToRequestDetails = function(event) {
77
- var id = parseInt(event.currentTarget.getAttribute("data-request-id"))
78
- this.currentRequest = this.requests.find(function(req) { return req.id == id })
79
- this.render()
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.goToHistory = function(event) {
83
- this.currentRequest = null
84
- this.render()
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.formatRuntime(this.data.runtime)
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
- averageRuntime: RorVsWild.Local.formatRuntime(runtime / section.calls),
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
- runtime: runtime,
131
- language: RorVsWild.Local.kindToLanguage(section.kind),
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.runtime - a.runtime })
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
  }