peek-performance_bar 1.2.1 → 1.3.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
  SHA1:
3
- metadata.gz: 857b53ade1e4d64fe7f5ca135a3b3f16596ffc5f
4
- data.tar.gz: 85802d7c4c3b219814b3e1d8abe015dcee927dce
3
+ metadata.gz: 57aac4506b72753e304dd71e6d879103a806c793
4
+ data.tar.gz: 3b68b08e0a1f4f01044d23678b1aba2a32d58990
5
5
  SHA512:
6
- metadata.gz: 8f40085f3fc6ec19f00c14355f60ad6507e162aa0b41cfe3fd400df004eeb0428e28a0abec950bc0b2a673167e5734d93e7faa2915802c095dec6bba902cce7d
7
- data.tar.gz: 363db21a79d680fc00e1f1b93d903dfc890b6bc7103b04d11382dd32b168520953b8002d46c493008f10addc65f0fec83ba03d4284469f2bcdd372f9953e13a0
6
+ metadata.gz: 16c23582330e78462677b54481af3d4b3a5f5368aeb45c7244e8271c543b6c33e7e448e44f076db8c49a289be05abaeb49b43b703693202167535a0d15de4b96
7
+ data.tar.gz: a84688e829e1cfbea5cb8d6f7665586c796887c491445ff7b0b3be7d357e83c2b312ee590cf716e58d1d63562103a0e2d7f1a3821b8f4b1b3e1ff0f04a99ea59
data/CHANGELOG.md CHANGED
@@ -38,3 +38,8 @@
38
38
  # 1.2.1
39
39
 
40
40
  - Listen to Turbolinks v5 `turbolinks:request-start` and `turbolinks:load` JS events to trigger peek-performance_bar updates. - [#26](https://github.com/peek/peek-performance_bar/pull/26) [@lucasmazza](https://github.com/lucasmazza)
41
+
42
+ # 1.3.0
43
+
44
+ - Remove CoffeeScript support in favor of plain JavaScript. - [#28](https://github.com/peek/peek-performance_bar/pull/28) [@gfx](https://github.com/gfx)
45
+ - Use Rack::BodyProxy to fix X-Sendfile header being incorrectly set. - [#27](https://github.com/peek/peek-performance_bar/pull/27) [@rymai](https://github.com/rymai)
@@ -0,0 +1,192 @@
1
+ // The mission control window.performance.timing display area.
2
+ //
3
+ // Breaks the window.performance.timing numbers down into these groups:
4
+ //
5
+ // dns - Time looking up domain. Usually zero.
6
+ // tcp and ssl - Time used establishing tcp and ssl connections.
7
+ // redirect - Time spent redirecting since navigation began.
8
+ // app - Real server time as recorded in the app.
9
+ // latency - Extra backend and network time where browser was waiting.
10
+ // frontend - Time spent loading and rendering the DOM until interactive.
11
+ //
12
+ // Not all frontend time is counted. The page is considered ready when the
13
+ // domInteractive ready state is reached. This is before DOMContentLoaded and
14
+ // onload javascript handlers.
15
+ class PerformanceBar {
16
+ static initClass() {
17
+ // Additional app info to show with the app timing.
18
+ this.prototype.appInfo = null;
19
+
20
+ // The pixel width we're rendering the timing graph into.
21
+ this.prototype.width = null;
22
+ }
23
+
24
+ // Format a time as ms or s based on how big it is.
25
+ static formatTime(value) {
26
+ if (value >= 1000) {
27
+ return `${(value / 1000).toFixed(3)}s`;
28
+ } else {
29
+ return `${value.toFixed(0)}ms`;
30
+ }
31
+ }
32
+
33
+ // Create a new PerformanceBar view bound to a given element. The el and width
34
+ // options should be provided here.
35
+ constructor(options) {
36
+ if (options == null) { options = {}; }
37
+ this.el = $('#peek-view-performance-bar .performance-bar');
38
+ for (let k in options) { let v = options[k]; this[k] = v; }
39
+ if (this.width == null) { this.width = this.el.width(); }
40
+ if (this.timing == null) { this.timing = window.performance.timing; }
41
+ }
42
+
43
+ // Render the performance bar in the associated element. This is a little weird
44
+ // because it includes the server-side rendering time reported with the
45
+ // response document which may not line up when using the back/forward button
46
+ // and loading from cache.
47
+ render(serverTime) {
48
+ if (serverTime == null) { serverTime = 0; }
49
+ this.el.empty();
50
+ this.addBar('frontend', '#90d35b', 'domLoading', 'domInteractive');
51
+
52
+ // time spent talking with the app according to performance.timing
53
+ let perfNetworkTime = (this.timing.responseEnd - this.timing.requestStart);
54
+
55
+ // only include serverTime if it's less than than the browser reported
56
+ // talking-to-the-app time; otherwise, assume we're loading from cache.
57
+ if (serverTime && (serverTime <= perfNetworkTime)) {
58
+ let networkTime = perfNetworkTime - serverTime;
59
+ this.addBar('latency / receiving', '#f1faff',
60
+ this.timing.requestStart + serverTime,
61
+ this.timing.requestStart + serverTime + networkTime);
62
+ this.addBar('app', '#90afcf',
63
+ this.timing.requestStart,
64
+ this.timing.requestStart + serverTime,
65
+ this.appInfo);
66
+ } else {
67
+ this.addBar('backend', '#c1d7ee', 'requestStart', 'responseEnd');
68
+ }
69
+
70
+ this.addBar('tcp / ssl', '#45688e', 'connectStart', 'connectEnd');
71
+ this.addBar('redirect', '#0c365e', 'redirectStart', 'redirectEnd');
72
+ this.addBar('dns', '#082541', 'domainLookupStart', 'domainLookupEnd');
73
+
74
+ return this.el;
75
+ }
76
+
77
+ // Determine if the page has reached the interactive state yet.
78
+ isLoaded() {
79
+ return this.timing.domInteractive;
80
+ }
81
+
82
+ // Integer unix timestamp representing the very beginning of the graph.
83
+ start() {
84
+ return this.timing.navigationStart;
85
+ }
86
+
87
+ // Integer unix timestamp representing the very end of the graph.
88
+ end() {
89
+ return this.timing.domInteractive;
90
+ }
91
+
92
+ // Total number of milliseconds between the start and end times.
93
+ total() {
94
+ return this.end() - this.start();
95
+ }
96
+
97
+ // Helper used to add a bar to the graph.
98
+ addBar(name, color, start, end, info) {
99
+ if (typeof start === 'string') { start = this.timing[start]; }
100
+ if (typeof end === 'string') { end = this.timing[end]; }
101
+
102
+ // Skip missing stats
103
+ if ((start == null) || (end == null)) { return; }
104
+
105
+ let time = end - start;
106
+ let offset = start - this.start();
107
+ let left = this.mapH(offset);
108
+ let width = this.mapH(time);
109
+
110
+ let title = `${name}: ${PerformanceBar.formatTime(time)}`;
111
+ let bar = $('<li></li>', {title, class: 'peek-tooltip'});
112
+ bar.css({
113
+ width: `${width}px`,
114
+ left: `${left}px`,
115
+ background: color
116
+ });
117
+ bar.tipsy({gravity: $.fn.tipsy.autoNS});
118
+ return this.el.append(bar);
119
+ }
120
+
121
+ // Map a time offset value to a horizontal pixel offset.
122
+ mapH(offset) {
123
+ return offset * (this.width / this.total());
124
+ }
125
+ }
126
+ PerformanceBar.initClass();
127
+
128
+ let renderPerformanceBar = function() {
129
+ let resp = $('#peek-server_response_time');
130
+ let time = Math.round(resp.data('time') * 1000);
131
+
132
+ let bar = new PerformanceBar;
133
+ bar.render(time);
134
+
135
+ let span = $('<span>', {'class': 'peek-tooltip', title: 'Total navigation time for this page.'})
136
+ .text(PerformanceBar.formatTime(bar.total()));
137
+ span.tipsy({gravity: $.fn.tipsy.autoNS});
138
+ return updateStatus(span);
139
+ };
140
+
141
+ var updateStatus = html => $('#serverstats').html(html);
142
+
143
+ let ajaxStart = null;
144
+ $(document).on('pjax:start page:fetch turbolinks:request-start', event => ajaxStart = event.timeStamp);
145
+
146
+ $(document).on('pjax:end page:load turbolinks:load', function(event, xhr) {
147
+ if (ajaxStart == null) { return; }
148
+ let ajaxEnd = event.timeStamp;
149
+ let total = ajaxEnd - ajaxStart;
150
+ let serverTime = xhr ? parseInt(xhr.getResponseHeader('X-Runtime')) : 0;
151
+
152
+ // Defer to include the timing of pjax hook evaluation
153
+ return setTimeout(function() {
154
+ let tech;
155
+ let now = new Date().getTime();
156
+ let bar = new PerformanceBar({
157
+ timing: {
158
+ requestStart: ajaxStart,
159
+ responseEnd: ajaxEnd,
160
+ domLoading: ajaxEnd,
161
+ domInteractive: now
162
+ },
163
+ isLoaded() { return true; },
164
+ start() { return ajaxStart; },
165
+ end() { return now; }
166
+ });
167
+
168
+ bar.render(serverTime);
169
+
170
+ if ($.fn.pjax != null) {
171
+ tech = 'PJAX';
172
+ } else {
173
+ tech = 'Turbolinks';
174
+ }
175
+
176
+ let span = $('<span>', {'class': 'peek-tooltip', title: `${tech} navigation time`})
177
+ .text(PerformanceBar.formatTime(total));
178
+ span.tipsy({gravity: $.fn.tipsy.autoNS});
179
+ updateStatus(span);
180
+
181
+ return ajaxStart = null;
182
+ }
183
+ , 0);
184
+ });
185
+
186
+ $(function() {
187
+ if (window.performance) {
188
+ return renderPerformanceBar();
189
+ } else {
190
+ return $('#peek-view-performance-bar').remove();
191
+ }
192
+ });
@@ -1,5 +1,5 @@
1
1
  module Peek
2
2
  module PerformanceBar
3
- VERSION = '1.2.1'
3
+ VERSION = '1.3.0'
4
4
  end
5
5
  end
@@ -1,3 +1,5 @@
1
+ require "rack/body_proxy"
2
+
1
3
  module Peek
2
4
  module Views
3
5
  class PerformanceBar
@@ -104,32 +106,6 @@ module Peek
104
106
  warn "ProcessUtilization#record_request failed: #{boom.inspect}"
105
107
  end
106
108
 
107
- # Body wrapper. Yields to the block when body is closed. This is used to
108
- # signal when a response is fully finished processing.
109
- class Body
110
- def initialize(body, &block)
111
- @body = body
112
- @block = block
113
- end
114
-
115
- def each(&block)
116
- @body.each(&block)
117
- end
118
-
119
- def close
120
- @body.close if @body.respond_to?(:close)
121
- @block.call
122
- nil
123
- end
124
-
125
- # Delegate calls to @body to be compatible with other middlewares
126
- def method_missing(name, *args, &block)
127
- super unless @body.respond_to?(name)
128
-
129
- @body.send(name, *args, &block)
130
- end
131
- end
132
-
133
109
  # Rack entry point.
134
110
  def call(env)
135
111
  @env = env
@@ -142,7 +118,7 @@ module Peek
142
118
  env['process.total_requests'] = total_requests
143
119
 
144
120
  status, headers, body = @app.call(env)
145
- body = Body.new(body) { record_request }
121
+ body = Rack::BodyProxy.new(body) { record_request }
146
122
  [status, headers, body]
147
123
  end
148
124
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: peek-performance_bar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garrett Bjerkhoel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-04 00:00:00.000000000 Z
11
+ date: 2017-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: peek
@@ -37,7 +37,7 @@ files:
37
37
  - LICENSE.txt
38
38
  - README.md
39
39
  - Rakefile
40
- - app/assets/javascripts/peek/views/performance_bar.coffee
40
+ - app/assets/javascripts/peek/views/performance_bar.js
41
41
  - app/assets/stylesheets/peek/views/performance_bar.scss
42
42
  - app/helpers/peek/performance_bar_helper.rb
43
43
  - app/views/peek/results/_performance_bar.html.erb
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
67
  version: '0'
68
68
  requirements: []
69
69
  rubyforge_project:
70
- rubygems_version: 2.5.1
70
+ rubygems_version: 2.6.11
71
71
  signing_key:
72
72
  specification_version: 4
73
73
  summary: Take a peek into the MySQL queries made during your application's requests.
@@ -1,167 +0,0 @@
1
- # The mission control window.performance.timing display area.
2
- #
3
- # Breaks the window.performance.timing numbers down into these groups:
4
- #
5
- # dns - Time looking up domain. Usually zero.
6
- # tcp and ssl - Time used establishing tcp and ssl connections.
7
- # redirect - Time spent redirecting since navigation began.
8
- # app - Real server time as recorded in the app.
9
- # latency - Extra backend and network time where browser was waiting.
10
- # frontend - Time spent loading and rendering the DOM until interactive.
11
- #
12
- # Not all frontend time is counted. The page is considered ready when the
13
- # domInteractive ready state is reached. This is before DOMContentLoaded and
14
- # onload javascript handlers.
15
- class PerformanceBar
16
- # Additional app info to show with the app timing.
17
- appInfo: null
18
-
19
- # The pixel width we're rendering the timing graph into.
20
- width: null
21
-
22
- # Format a time as ms or s based on how big it is.
23
- @formatTime: (value) ->
24
- if value >= 1000
25
- "#{(value / 1000).toFixed(3)}s"
26
- else
27
- "#{value.toFixed(0)}ms"
28
-
29
- # Create a new PerformanceBar view bound to a given element. The el and width
30
- # options should be provided here.
31
- constructor: (options={}) ->
32
- @el = $('#peek-view-performance-bar .performance-bar')
33
- @[k] = v for k, v of options
34
- @width ?= @el.width()
35
- @timing ?= window.performance.timing
36
-
37
- # Render the performance bar in the associated element. This is a little weird
38
- # because it includes the server-side rendering time reported with the
39
- # response document which may not line up when using the back/forward button
40
- # and loading from cache.
41
- render: (serverTime=0) ->
42
- @el.empty()
43
- @addBar 'frontend', '#90d35b', 'domLoading', 'domInteractive'
44
-
45
- # time spent talking with the app according to performance.timing
46
- perfNetworkTime = (@timing.responseEnd - @timing.requestStart)
47
-
48
- # only include serverTime if it's less than than the browser reported
49
- # talking-to-the-app time; otherwise, assume we're loading from cache.
50
- if serverTime and serverTime <= perfNetworkTime
51
- networkTime = perfNetworkTime - serverTime
52
- @addBar 'latency / receiving', '#f1faff',
53
- @timing.requestStart + serverTime,
54
- @timing.requestStart + serverTime + networkTime
55
- @addBar 'app', '#90afcf',
56
- @timing.requestStart,
57
- @timing.requestStart + serverTime,
58
- @appInfo
59
- else
60
- @addBar 'backend', '#c1d7ee', 'requestStart', 'responseEnd'
61
-
62
- @addBar 'tcp / ssl', '#45688e', 'connectStart', 'connectEnd'
63
- @addBar 'redirect', '#0c365e', 'redirectStart', 'redirectEnd'
64
- @addBar 'dns', '#082541', 'domainLookupStart', 'domainLookupEnd'
65
-
66
- @el
67
-
68
- # Determine if the page has reached the interactive state yet.
69
- isLoaded: ->
70
- @timing.domInteractive
71
-
72
- # Integer unix timestamp representing the very beginning of the graph.
73
- start: ->
74
- @timing.navigationStart
75
-
76
- # Integer unix timestamp representing the very end of the graph.
77
- end: ->
78
- @timing.domInteractive
79
-
80
- # Total number of milliseconds between the start and end times.
81
- total: ->
82
- @end() - @start()
83
-
84
- # Helper used to add a bar to the graph.
85
- addBar: (name, color, start, end, info) ->
86
- start = @timing[start] if typeof start is 'string'
87
- end = @timing[end] if typeof end is 'string'
88
-
89
- # Skip missing stats
90
- return unless start? and end?
91
-
92
- time = end - start
93
- offset = start - @start()
94
- left = @mapH(offset)
95
- width = @mapH(time)
96
-
97
- title = "#{name}: #{PerformanceBar.formatTime(time)}"
98
- bar = $ '<li></li>', title: title, class: 'peek-tooltip'
99
- bar.css
100
- width: "#{width}px"
101
- left: "#{left}px"
102
- background: color
103
- bar.tipsy gravity: $.fn.tipsy.autoNS
104
- @el.append bar
105
-
106
- # Map a time offset value to a horizontal pixel offset.
107
- mapH: (offset) ->
108
- offset * (@width / @total())
109
-
110
- renderPerformanceBar = ->
111
- resp = $('#peek-server_response_time')
112
- time = Math.round(resp.data('time') * 1000)
113
-
114
- bar = new PerformanceBar
115
- bar.render time
116
-
117
- span = $('<span>', {'class': 'peek-tooltip', title: 'Total navigation time for this page.'})
118
- .text(PerformanceBar.formatTime(bar.total()))
119
- span.tipsy gravity: $.fn.tipsy.autoNS
120
- updateStatus span
121
-
122
- updateStatus = (html) ->
123
- $('#serverstats').html html
124
-
125
- ajaxStart = null
126
- $(document).on 'pjax:start page:fetch turbolinks:request-start', (event) ->
127
- ajaxStart = event.timeStamp
128
-
129
- $(document).on 'pjax:end page:load turbolinks:load', (event, xhr) ->
130
- return unless ajaxStart?
131
- ajaxEnd = event.timeStamp
132
- total = ajaxEnd - ajaxStart
133
- serverTime = if xhr then parseInt(xhr.getResponseHeader('X-Runtime')) else 0
134
-
135
- # Defer to include the timing of pjax hook evaluation
136
- setTimeout ->
137
- now = new Date().getTime()
138
- bar = new PerformanceBar
139
- timing:
140
- requestStart: ajaxStart,
141
- responseEnd: ajaxEnd,
142
- domLoading: ajaxEnd,
143
- domInteractive: now
144
- isLoaded: -> true
145
- start: -> ajaxStart
146
- end: -> now
147
-
148
- bar.render serverTime
149
-
150
- if $.fn.pjax?
151
- tech = 'PJAX'
152
- else
153
- tech = 'Turbolinks'
154
-
155
- span = $('<span>', {'class': 'peek-tooltip', title: "#{tech} navigation time"})
156
- .text(PerformanceBar.formatTime(total))
157
- span.tipsy gravity: $.fn.tipsy.autoNS
158
- updateStatus span
159
-
160
- ajaxStart = null
161
- , 0
162
-
163
- $ ->
164
- if window.performance
165
- renderPerformanceBar()
166
- else
167
- $('#peek-view-performance-bar').remove()