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 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
  }