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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 587f67697724c84547a0fde87674a10b35b4a36c61d5de4d032bd775fa339443
4
- data.tar.gz: 5da27bd25a15ba85948731d383084852778545a7a86c95921194c22bf80efc7e
3
+ metadata.gz: 1da086576b7ffa892064483efd18f9c545ff1ee6e960f23374e82e78722056c5
4
+ data.tar.gz: cfc4561f2aec3a8880b80e81daf71492516d2d137901e649db588fe4a05988f1
5
5
  SHA512:
6
- metadata.gz: 92cef045840fe613886cd7d2fd8370cf69afff5e86517025efaaf33d2e694c629225cd82dd728cbf8d1f89045119479dc7667ad44cb1cf935131e84e0720b067
7
- data.tar.gz: 127d539486858d0f73ad38cb5ab4c2164c43b56c01673e114f08760e0a394b70be2bc569a0b332a7bc901347a05066d84e7407f772dd6c46ae227584930cdc49
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,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.getAttribute("data-target")).classList.toggle("is-open")
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.render()
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.render()
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.formatRuntime = function(runtime) {
66
- 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))
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.goToRequestDetails = function(event) {
81
- var id = parseInt(event.currentTarget.getAttribute("data-request-id"))
82
- this.currentRequest = this.requests.find(function(req) { return req.id == id })
83
- 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))
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.goToHistory = function(event) {
87
- this.currentRequest = null
88
- this.render()
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.formatRuntime(this.data.runtime)
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
- 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),
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
- runtime: runtime,
136
- language: RorVsWild.Local.kindToLanguage(section.kind),
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.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")
144
309
  }