stack_tracy 0.1.3 → 0.1.4
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.
- data/CHANGELOG.rdoc +18 -0
- data/README.md +45 -14
- data/VERSION +1 -1
- data/bin/tracy +2 -2
- data/demo.rb +8 -0
- data/lib/stack_tracy/cli.rb +26 -0
- data/lib/stack_tracy/core_ext/kernel.rb +5 -2
- data/lib/stack_tracy/sinatra.rb +13 -4
- data/lib/stack_tracy/version.rb +1 -1
- data/lib/stack_tracy.rb +15 -7
- data/stack_tracy.gemspec +2 -1
- data/test/unit/test_tracy.rb +27 -3
- data/ui/assets/comments.js +15 -0
- data/ui/assets/stack_tracy.css +8 -11
- data/ui/assets/stack_tracy.js +8 -2
- data/ui/index.html.erb +55 -62
- metadata +16 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
= StackTracy CHANGELOG
|
2
2
|
|
3
|
+
== Version 0.1.4 (August 25, 2012)
|
4
|
+
|
5
|
+
* Added major improvements regarding browser performance when opening heavy HTML stack trace pages:
|
6
|
+
- using padding instead of non-breakable spaces (doh!)
|
7
|
+
- reduced white lines and white space
|
8
|
+
- added a threshold (< 0.001s) for folding calls at default and rendering its 'child calls' as comment (see http://ravirajsblog.blogspot.nl/2010/12/another-hack-to-render-heavy-html-pages.html)
|
9
|
+
- parsing commented 'child calls' at initial unfold
|
10
|
+
* Falling back to current directory when invoking StackTracy.open (or `tracy` within the Terminal)
|
11
|
+
* Letting StackTracy auto-determine its dump directory when calling `stack_tracy(:open) {}`
|
12
|
+
* Clearing StackTracy.stack_trace after having invoked StackTracy.dump
|
13
|
+
* Displaying passed path when invoking StackTracy.open with use_current_stack_trace == true
|
14
|
+
* Improved StackTracy::Sinatra middleware a bit regarding the `/tracy` route
|
15
|
+
* Added three configuration options:
|
16
|
+
- dump_source_location (default: `false`) include the source location when dumping recorded stack trace
|
17
|
+
- limit (default: `7500`) stack traces with more calls than the limit will be limited (core class / module calls will be excluded) when displaying
|
18
|
+
- threshold (default: `0.001`) fold calls faster than the threshold when exceeding the calls limit
|
19
|
+
* Enhanced the CLI interface `tracy` by using Thor in order to process the :limit and :threshold option
|
20
|
+
|
3
21
|
== Version 0.1.3 (August 19, 2012)
|
4
22
|
|
5
23
|
* Being able to compile StackTracy native extension on Windows (thanks ramsees for issuing)
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ The gem is partly written in C to reduce the application performance as minimal
|
|
10
10
|
|
11
11
|

|
12
12
|
|
13
|
-
Watch ["**Using StackTracy within a small Sinatra application**"](https://vimeo.com/archan937/stacktracy) to see StackTracy in action!
|
13
|
+
Watch the ["**Using StackTracy within a small Sinatra application**"](https://vimeo.com/archan937/stacktracy) **screencast** to see StackTracy in action!
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
@@ -80,12 +80,15 @@ A couple of examples:
|
|
80
80
|
|
81
81
|
### Configure StackTracy
|
82
82
|
|
83
|
-
You can configure the default stack tree reduction behaviour
|
83
|
+
You can configure `StackTracy` regarding the default stack tree reduction behaviour, its dump directory and whether to include the source location when dumping recorded stack events:
|
84
84
|
|
85
85
|
StackTracy.configure do |c|
|
86
|
-
c.dump_dir
|
87
|
-
c.
|
88
|
-
c.
|
86
|
+
c.dump_dir = "." #=> default: Dir::tmpdir
|
87
|
+
c.dump_source_location = "." #=> default: false
|
88
|
+
c.limit = 1000 #=> default: 7500
|
89
|
+
c.threshold = 0.005 #=> default: 0.001
|
90
|
+
c.only = "Foo*" #=> default: nil
|
91
|
+
c.exclude = %w(Foo::Bar Foo::CandyBar) #=> default: nil
|
89
92
|
end
|
90
93
|
|
91
94
|
### Using recorded stack events
|
@@ -155,6 +158,14 @@ You can dump (optionally filtered) recorded stack events to a CSV file.
|
|
155
158
|
|
156
159
|
This is what the contents of `result.csv` would look like:
|
157
160
|
|
161
|
+
event;;;singleton;object;method;nsec;call;depth;duration
|
162
|
+
c-call;;;false;Kernel;puts;1344466943040581120;Kernel#puts;0;0.000120832
|
163
|
+
c-call;;;false;IO;puts;1344466943040599040;IO#puts;1;9.1904e-05
|
164
|
+
c-call;;;false;IO;write;1344466943040613120;IO#write;2;3.2768e-05
|
165
|
+
c-call;;;false;IO;write;1344466943040658944;IO#write;2;1.9968e-05
|
166
|
+
|
167
|
+
When invoking `StackTracy.dump "result.csv", true` and thus including the source location:
|
168
|
+
|
158
169
|
event;file;line;singleton;object;method;nsec;call;depth;duration
|
159
170
|
c-call;(pry);2;false;Kernel;puts;1344466943040581120;Kernel#puts;0;0.000120832
|
160
171
|
c-call;(pry);2;false;IO;puts;1344466943040599040;IO#puts;1;9.1904e-05
|
@@ -167,16 +178,32 @@ You can easily view the dumped stack events within your browser by either callin
|
|
167
178
|
|
168
179
|
[1] pry(main)> StackTracy.open "some/dir/file.csv"
|
169
180
|
|
170
|
-
or the following within the Terminal:
|
171
|
-
|
172
|
-
$ tracy "some/dir/file.csv"
|
173
|
-
|
174
181
|
Your default browser will be launched in which the stack events will be displayed.
|
175
182
|
|
176
|
-
When passing no path,
|
183
|
+
When passing no path, StackTracy will look for `stack_events-<random generated postfix>.csv` in either the default dump directory, the current directory or `Dir::tmpdir` and display it in the browser. When not found, it will display the last compiled stack tree when available:
|
177
184
|
|
178
185
|
$ tracy
|
179
186
|
|
187
|
+
### Using the CLI (command line interface)
|
188
|
+
|
189
|
+
Another way for viewing stack events in your browser is using the CLI `tracy` within the Terminal:
|
190
|
+
|
191
|
+
$ tracy #=> let StackTracy auto-determine which file to display
|
192
|
+
$ tracy . #=> display the last data file within the current directory
|
193
|
+
$ tracy foo/bar.csv #=> display foo/bar.csv
|
194
|
+
|
195
|
+
To get info about its options, type `tracy help open`:
|
196
|
+
|
197
|
+
$ tracy help open
|
198
|
+
Usage:
|
199
|
+
tracy open [PATH]
|
200
|
+
|
201
|
+
Options:
|
202
|
+
-l, [--limit=LIMIT]
|
203
|
+
-t, [--threshold=THRESHOLD]
|
204
|
+
|
205
|
+
Display StackTracy data within the browser (PATH is optional)
|
206
|
+
|
180
207
|
### Kernel#stack_tracy
|
181
208
|
|
182
209
|
As already mentioned, there is a convenience method called `stack_tracy` convenience method. The following shows a couple variants with its equivalent "normal implementation".
|
@@ -268,8 +295,9 @@ Its equivalent:
|
|
268
295
|
[1] pry(main)> StackTracy.start
|
269
296
|
[2] pry(main)> puts "testing"
|
270
297
|
[3] pry(main)> StackTracy.stop
|
271
|
-
[4] pry(main)>
|
272
|
-
[
|
298
|
+
[4] pry(main)> StackTracy.dump do |file|
|
299
|
+
[4] pry(main)> StackTracy.open file, true
|
300
|
+
[4] pry(main)> end
|
273
301
|
|
274
302
|
## Hooking into Sinatra requests
|
275
303
|
|
@@ -278,7 +306,7 @@ You can easily hook `StackTracy` into [Sinatra](http://www.sinatrarb.com) reques
|
|
278
306
|
require "sinatra"
|
279
307
|
require "stack_tracy"
|
280
308
|
|
281
|
-
use StackTracy::Sinatra
|
309
|
+
use StackTracy::Sinatra, :open
|
282
310
|
|
283
311
|
get "/" do
|
284
312
|
"Hello world!"
|
@@ -286,7 +314,9 @@ You can easily hook `StackTracy` into [Sinatra](http://www.sinatrarb.com) reques
|
|
286
314
|
|
287
315
|
**Note**: Make sure you have the `sinatra` and `stack_tracy` gems installed.
|
288
316
|
|
289
|
-
Open the Sinatra application in your browser at [http://localhost:4567](http://localhost:4567) and
|
317
|
+
Open the Sinatra application in your browser at [http://localhost:4567](http://localhost:4567) and the complete stack tree will be displayed in your browser! ^^
|
318
|
+
|
319
|
+
You can also open [http://localhost:4567/tracy](http://localhost:4567/tracy) afterwards by the way.
|
290
320
|
|
291
321
|
### Taking more control
|
292
322
|
|
@@ -354,6 +384,7 @@ For support, remarks and requests, please mail me at [paul.engel@holder.nl](mail
|
|
354
384
|
|
355
385
|
* Two functions within the StackTracy C implementation are taken from [ruby-prof](https://github.com/rdp/ruby-prof).
|
356
386
|
* The table sort within the Cumulatives tab is implemented with [TinySort](http://tinysort.sjeiti.com/).
|
387
|
+
* Being able to improve browser performance when loading heavy HTML stack trace pages using Ravi Raj's ([@raviraj4u](https://twitter.com/raviraj4u)) blog post: [http://ravirajsblog.blogspot.nl/2010/12/another-hack-to-render-heavy-html-pages.html](http://ravirajsblog.blogspot.nl/2010/12/another-hack-to-render-heavy-html-pages.html)
|
357
388
|
|
358
389
|
## License
|
359
390
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
data/bin/tracy
CHANGED
data/demo.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "stack_tracy"
|
3
|
+
|
4
|
+
module StackTracy
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
default_task :open
|
8
|
+
|
9
|
+
desc "open [PATH]", "Display StackTracy data within the browser (PATH is optional)"
|
10
|
+
method_options [:limit, "-l"] => :numeric, [:threshold, "-t"] => :numeric
|
11
|
+
def open(path = ".")
|
12
|
+
StackTracy.open path, false, options.threshold, options.limit
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def method_missing(method, *args)
|
18
|
+
if File.exists? File.expand_path(method.to_s)
|
19
|
+
`tracy open #{method} #{args.join " "}`
|
20
|
+
else
|
21
|
+
raise Error, "Unrecognized command \"#{method}\". Please consult `tracy help`."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -5,6 +5,8 @@ module Kernel
|
|
5
5
|
options = arg
|
6
6
|
arg = nil
|
7
7
|
end
|
8
|
+
threshold = options.delete :threshold
|
9
|
+
limit = options.delete :limit
|
8
10
|
StackTracy.start options
|
9
11
|
yield
|
10
12
|
StackTracy.stop
|
@@ -13,8 +15,9 @@ module Kernel
|
|
13
15
|
elsif arg == :dump
|
14
16
|
StackTracy.dump
|
15
17
|
elsif arg == :open
|
16
|
-
|
17
|
-
|
18
|
+
StackTracy.dump do |file|
|
19
|
+
StackTracy.open file, true, threshold, limit
|
20
|
+
end
|
18
21
|
elsif arg.is_a? String
|
19
22
|
StackTracy.dump arg
|
20
23
|
end
|
data/lib/stack_tracy/sinatra.rb
CHANGED
@@ -10,10 +10,9 @@ module StackTracy
|
|
10
10
|
|
11
11
|
def call(env)
|
12
12
|
request = ::Sinatra::Request.new env
|
13
|
-
if request.path.match /^\/tracy
|
14
|
-
return open($1)
|
13
|
+
if request.path.match /^\/tracy(-.*)?/
|
14
|
+
return open($1.to_s.gsub(/^-/, ""))
|
15
15
|
end
|
16
|
-
|
17
16
|
if @before_filter.nil? || !!@before_filter.call(request.path, request.params)
|
18
17
|
result = nil
|
19
18
|
stack_tracy @arg || Dir::tmpdir, @options do
|
@@ -28,7 +27,17 @@ module StackTracy
|
|
28
27
|
private
|
29
28
|
|
30
29
|
def open(match)
|
31
|
-
|
30
|
+
if match.empty?
|
31
|
+
if StackTracy.stack_trace.empty?
|
32
|
+
StackTracy.open nil, false, @options[:threshold], @options[:limit]
|
33
|
+
else
|
34
|
+
StackTracy.dump do |file|
|
35
|
+
StackTracy.open file, true, @options[:threshold], @options[:limit]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
else
|
39
|
+
StackTracy.open match, false, @options[:threshold], @options[:limit]
|
40
|
+
end
|
32
41
|
[200, {"Content-Type" => "text/html;charset=utf-8", "Content-Length" => Rack::Utils.bytesize("").to_s}, ""]
|
33
42
|
end
|
34
43
|
|
data/lib/stack_tracy/version.rb
CHANGED
data/lib/stack_tracy.rb
CHANGED
@@ -18,7 +18,7 @@ module StackTracy
|
|
18
18
|
:active_record => "ActiveRecord::Base",
|
19
19
|
:data_mapper => "DataMapper::Resource"
|
20
20
|
}
|
21
|
-
@options = Struct.new(:dump_dir, :only, :exclude).new(Dir::tmpdir)
|
21
|
+
@options = Struct.new(:dump_dir, :dump_source_location, :limit, :threshold, :only, :exclude).new(Dir::tmpdir, false, 7500, 0.001)
|
22
22
|
|
23
23
|
class Error < StandardError; end
|
24
24
|
|
@@ -67,26 +67,32 @@ module StackTracy
|
|
67
67
|
}
|
68
68
|
end
|
69
69
|
|
70
|
-
def dump(path = nil, *only)
|
70
|
+
def dump(path = nil, dump_source_location = nil, *only)
|
71
71
|
unless path && path.match(/\.csv$/)
|
72
72
|
path = File.join [path || @options.dump_dir, "stack_events-#{SecureRandom.hex(3)}.csv"].compact
|
73
73
|
end
|
74
74
|
File.expand_path(path).tap do |path|
|
75
|
-
|
75
|
+
bool = dump_source_location.nil? ? @options[:dump_source_location] : dump_source_location
|
76
|
+
keys = [:event, (:file if bool), (:line if bool), :singleton, :object, :method, :nsec, :time, :call, :depth, :duration]
|
76
77
|
File.open(path, "w") do |file|
|
77
78
|
file << keys.join(";") + "\n"
|
78
79
|
select(only).each do |event|
|
79
80
|
file << event.values_at(*keys).join(";") + "\n"
|
80
81
|
end
|
81
82
|
end
|
83
|
+
yield path if block_given?
|
84
|
+
stack_trace.clear
|
82
85
|
end
|
83
86
|
end
|
84
87
|
|
85
|
-
def open(path = nil, use_current_stack_trace = false)
|
86
|
-
|
88
|
+
def open(path = nil, use_current_stack_trace = false, threshold = nil, limit = nil)
|
89
|
+
if use_current_stack_trace
|
90
|
+
file = File.expand_path(path) if path
|
91
|
+
else
|
87
92
|
unless path && path.match(/\.csv$/)
|
88
|
-
path
|
89
|
-
path ||= Dir[File.join(
|
93
|
+
path = Dir[File.join(path || @options.dump_dir, "stack_events-*.csv")].sort_by{|f| File.mtime(f)}.last
|
94
|
+
path ||= Dir[File.join(".", "stack_events-*.csv")].sort_by{|f| File.mtime(f)}.last
|
95
|
+
path ||= Dir[File.join(Dir::tmpdir, "stack_events-*.csv")].sort_by{|f| File.mtime(f)}.last
|
90
96
|
end
|
91
97
|
if path
|
92
98
|
file = File.expand_path(path)
|
@@ -98,6 +104,8 @@ module StackTracy
|
|
98
104
|
index = ui("index.html")
|
99
105
|
|
100
106
|
if use_current_stack_trace || (file && File.exists?(file))
|
107
|
+
threshold = threshold.nil? ? @options[:threshold] : threshold
|
108
|
+
limit = limit.nil? ? @options[:limit] : limit
|
101
109
|
events = use_current_stack_trace ? select : StackTracy::EventInfo.to_hashes(File.read(file))
|
102
110
|
erb = ERB.new File.new(ui("index.html.erb")).read
|
103
111
|
File.open(index, "w"){|f| f.write erb.result(binding)}
|
data/stack_tracy.gemspec
CHANGED
@@ -13,8 +13,9 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
14
|
gem.name = "stack_tracy"
|
15
15
|
gem.require_paths = ["lib"]
|
16
|
-
gem.version = "0.1.
|
16
|
+
gem.version = "0.1.4"
|
17
17
|
|
18
18
|
gem.add_dependency "rich_support", "~> 0.1.2"
|
19
19
|
gem.add_dependency "launchy", "2.1.0"
|
20
|
+
gem.add_dependency "thor"
|
20
21
|
end
|
data/test/unit/test_tracy.rb
CHANGED
@@ -25,7 +25,7 @@ module Unit
|
|
25
25
|
it "should be configurable" do
|
26
26
|
StackTracy.config do |c|
|
27
27
|
assert_equal true, c.is_a?(Struct)
|
28
|
-
assert_equal [:dump_dir, :only, :exclude], c.members
|
28
|
+
assert_equal [:dump_dir, :dump_source_location, :limit, :threshold, :only, :exclude], c.members
|
29
29
|
c.only = "Kernel"
|
30
30
|
c.exclude = ["IO", "String"]
|
31
31
|
end
|
@@ -77,8 +77,8 @@ module Unit
|
|
77
77
|
end
|
78
78
|
}
|
79
79
|
|
80
|
-
|
81
|
-
|
80
|
+
assert_equal true, StackTracy.stack_trace.first.call?
|
81
|
+
assert_equal false, StackTracy.stack_trace.first.return?
|
82
82
|
|
83
83
|
StackTracy.config do |c|
|
84
84
|
c.exclude = ["IO"]
|
@@ -130,6 +130,30 @@ module Unit
|
|
130
130
|
}
|
131
131
|
end
|
132
132
|
|
133
|
+
it "should clear StackTracy.stack_trace after having invoked StackTracy.dump" do
|
134
|
+
stack_tracy do
|
135
|
+
puts "testing"
|
136
|
+
end
|
137
|
+
assert_equal false, StackTracy.stack_trace.empty?
|
138
|
+
|
139
|
+
StackTracy.dump
|
140
|
+
assert_equal true, StackTracy.stack_trace.empty?
|
141
|
+
|
142
|
+
stack_tracy do
|
143
|
+
puts "testing"
|
144
|
+
end
|
145
|
+
assert_equal false, StackTracy.stack_trace.empty?
|
146
|
+
|
147
|
+
StackTracy.expects(:foo)
|
148
|
+
StackTracy.dump do |file|
|
149
|
+
assert file.match(/\/.*\.csv/)
|
150
|
+
assert_equal false, StackTracy.stack_trace.empty?
|
151
|
+
StackTracy.foo
|
152
|
+
end
|
153
|
+
|
154
|
+
assert_equal true, StackTracy.stack_trace.empty?
|
155
|
+
end
|
156
|
+
|
133
157
|
it "should filter methods as expected" do
|
134
158
|
stack_tracy do
|
135
159
|
puts "testing"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
jQuery.fn.comments = function() {
|
2
|
+
var comments = [];
|
3
|
+
|
4
|
+
this.each(function(i, node) {
|
5
|
+
var child = node.firstChild;
|
6
|
+
while (child) {
|
7
|
+
if (child.nodeType === 8) {
|
8
|
+
comments.push(child.nodeValue);
|
9
|
+
}
|
10
|
+
child = child.nextSibling;
|
11
|
+
}
|
12
|
+
});
|
13
|
+
|
14
|
+
return comments;
|
15
|
+
};
|
data/ui/assets/stack_tracy.css
CHANGED
@@ -56,24 +56,25 @@ a {
|
|
56
56
|
#page .tab-pane {
|
57
57
|
line-height: 28px; }
|
58
58
|
|
59
|
-
#page .tab-pane div {
|
60
|
-
border-bottom: 1px solid #EFEFEF; }
|
61
|
-
|
62
59
|
#page .tab-pane div.head {
|
63
60
|
padding-bottom: 4px;
|
64
61
|
font-weight: bold; }
|
65
62
|
#page .tab-pane div.head a {
|
66
63
|
color: #222; }
|
67
64
|
|
68
|
-
#page .tab-pane div.
|
65
|
+
#page .tab-pane div.head,
|
66
|
+
#page .tab-pane div.body div {
|
67
|
+
border-bottom: 1px solid #EFEFEF; }
|
68
|
+
|
69
|
+
#page .tab-pane div.body div.group {
|
69
70
|
border: 0; }
|
70
71
|
|
71
72
|
#page .tab-pane div span.time,
|
72
73
|
#page .tab-pane div span.average,
|
73
74
|
#page .tab-pane div span.duration,
|
74
75
|
#page .tab-pane div span.count {
|
75
|
-
width:
|
76
|
-
padding-right:
|
76
|
+
width: 70px;
|
77
|
+
padding-right: 20px;
|
77
78
|
text-align: right;
|
78
79
|
display: -moz-inline-block;
|
79
80
|
display: inline-block;
|
@@ -82,17 +83,13 @@ a {
|
|
82
83
|
|
83
84
|
#page .tab-pane div span.call {
|
84
85
|
width: 950px;
|
85
|
-
padding-left: 15px;
|
86
86
|
display: -moz-inline-block;
|
87
87
|
display: inline-block;
|
88
88
|
*display: inline;
|
89
89
|
zoom: 1; }
|
90
90
|
|
91
91
|
#page #cumulatives div span.count {
|
92
|
-
width:
|
93
|
-
|
94
|
-
#page #cumulatives div span.call {
|
95
|
-
width: 790px; }
|
92
|
+
width: 45px; }
|
96
93
|
|
97
94
|
#footer {
|
98
95
|
padding-top: 45px;
|
data/ui/assets/stack_tracy.js
CHANGED
@@ -4,7 +4,13 @@ StackTracy = (function() {
|
|
4
4
|
var sortation = [];
|
5
5
|
|
6
6
|
var toggle = function(event) {
|
7
|
-
$(event.target).closest("div").next("div.group")
|
7
|
+
var group = $(event.target).closest("div").next("div.group");
|
8
|
+
var comments = group.comments();
|
9
|
+
if (comments.length) {
|
10
|
+
group.html(comments.join("\n"));
|
11
|
+
} else {
|
12
|
+
group.toggle();
|
13
|
+
}
|
8
14
|
};
|
9
15
|
|
10
16
|
$(function() {
|
@@ -16,7 +22,7 @@ StackTracy = (function() {
|
|
16
22
|
});
|
17
23
|
|
18
24
|
return {
|
19
|
-
version: "0.1.
|
25
|
+
version: "0.1.4",
|
20
26
|
sort: function(column) {
|
21
27
|
sortation[column] = sortation[column] == "asc" ? "desc" : "asc";
|
22
28
|
$("#cumulatives>.body>div").tsort("span:eq(" + column + ")[abbr]", {
|
data/ui/index.html.erb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
<script src="assets/jquery.js" type="text/javascript"></script>
|
9
9
|
<script src="assets/bootstrap-tab.js" type="text/javascript"></script>
|
10
10
|
<script src="assets/tiny_sort.js" type="text/javascript"></script>
|
11
|
+
<script src="assets/comments.js" type="text/javascript"></script>
|
11
12
|
<script src="assets/stack_tracy.js" type="text/javascript"></script>
|
12
13
|
<link href="assets/bootstrap-tab.css" type="text/css" rel="stylesheet" media="screen"/>
|
13
14
|
<link href="assets/stack_tracy.css" type="text/css" rel="stylesheet" media="screen"/>
|
@@ -26,26 +27,27 @@
|
|
26
27
|
<a href="#cumulatives" data-toggle="tab">Cumulatives</a>
|
27
28
|
</li>
|
28
29
|
</ul>
|
29
|
-
<div class="tab-content"
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
<div class="tab-content"><%
|
31
|
+
limited = events.size > limit
|
32
|
+
threshold = nil unless limited
|
33
|
+
excluded_objects = if limited
|
34
|
+
%w(Array BasicObject Enumerable Fixnum Float Hash IO Integer Kernel Module Mutex Numeric Object Rational String Symbol Thread Time)
|
35
|
+
else
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
comment_depth = nil
|
39
|
+
last_depth = nil
|
40
|
+
last_duration = nil
|
41
|
+
corrections = []
|
42
|
+
cumulatives = {} %>
|
40
43
|
<div class="tab-pane active" id="stack_trace">
|
41
44
|
<div class="head">
|
42
45
|
<span class="time">Time</span>
|
43
46
|
<span class="duration">Duration</span>
|
44
47
|
<span class="call">Call</span>
|
45
48
|
</div>
|
46
|
-
<div class="body"
|
47
|
-
|
48
|
-
<%
|
49
|
+
<div class="body"><%
|
50
|
+
events.each_with_index do |event, index|
|
49
51
|
skip = excluded_objects.include?(event[:object]) || "#{event[:object]}".match(/^#/)
|
50
52
|
cumulatives[event[:call]] ||= {:duration => 0.0, :count => 0}
|
51
53
|
cumulatives[event[:call]][:duration] += event[:duration].to_f
|
@@ -54,37 +56,38 @@
|
|
54
56
|
corrections.size.times do |i|
|
55
57
|
event[:depth] <= corrections[0] ? corrections.shift : break
|
56
58
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
59
|
+
if skip
|
60
|
+
corrections.unshift event[:depth] if corrections.empty? || corrections.first != event[:depth]
|
61
|
+
else
|
62
|
+
if last_depth.to_i < event[:depth] - corrections.size %>
|
63
|
+
<div class="group"><% if threshold && comment_depth.nil? && last_duration && last_duration < threshold %><% comment_depth = event[:depth] - corrections.size %><%= "\n<!--" %><% end %><% else
|
64
|
+
close_tags = ((event[:depth] - corrections.size + 1)..last_depth.to_i).collect do |depth|
|
65
|
+
if comment_depth && depth == comment_depth
|
66
|
+
comment_depth = nil
|
67
|
+
"\n-->\n</div>"
|
68
|
+
else
|
69
|
+
"\n</div>"
|
70
|
+
end
|
71
|
+
end.reverse.join("")
|
72
|
+
%><%= close_tags %><% end %>
|
73
|
+
<div>
|
74
|
+
<span class="time"><%= "%.6f" % event[:time] %></span>
|
75
|
+
<span class="duration"><%= event[:duration] ? ("%.6f" % event[:duration]) : "?" %></span>
|
76
|
+
<span style="padding-left: <%= 10 * (event[:depth] - corrections.size) %>px"><% if (next_event = events[index + 1]) && next_event[:depth] > event[:depth] %><a class="toggler" href="#" onclick="return false"><%= event[:call] %></a><% else %><%= event[:call] %><% end %></span>
|
77
|
+
</div><%
|
78
|
+
last_depth = event[:depth] - corrections.size
|
79
|
+
last_duration = event[:duration]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
close_tags = (1..last_depth.to_i).collect do |depth|
|
83
|
+
if comment_depth && depth == comment_depth
|
84
|
+
comment_depth = nil
|
85
|
+
"\n-->\n</div>"
|
86
|
+
else
|
87
|
+
"\n</div>"
|
88
|
+
end
|
89
|
+
end.reverse.join("")
|
90
|
+
%><%= close_tags %>
|
88
91
|
</div>
|
89
92
|
</div>
|
90
93
|
<div class="tab-pane" id="cumulatives">
|
@@ -94,23 +97,13 @@
|
|
94
97
|
<span class="count"><a href="javascript:StackTracy.sort(2)">Count</a></span>
|
95
98
|
<span class="call"><a href="javascript:StackTracy.sort(3)">Call</a></span>
|
96
99
|
</div>
|
97
|
-
<div class="body"
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
<%= "%.6f" % stats[:duration] %>
|
105
|
-
</span>
|
106
|
-
<span class="count" abbr="<%= stats[:count] %>">
|
107
|
-
<%= stats[:count] %>
|
108
|
-
</span>
|
109
|
-
<span class="call" abbr="<%= call.gsub("<", "<").gsub(">", ">") %>">
|
110
|
-
<%= call.gsub("<", "<").gsub(">", ">") %>
|
111
|
-
</span>
|
112
|
-
</div>
|
113
|
-
<% end %>
|
100
|
+
<div class="body"><% cumulatives.sort{|(ak, av), (bk, bv)| bv[:average] <=> av[:average]}.each do |call, stats| %>
|
101
|
+
<div>
|
102
|
+
<span class="average" abbr="<%= "%.6f" % stats[:average] %>"><%= "%.6f" % stats[:average] %></span>
|
103
|
+
<span class="duration" abbr="<%= "%.6f" % stats[:duration] %>"><%= "%.6f" % stats[:duration] %></span>
|
104
|
+
<span class="count" abbr="<%= stats[:count] %>"><%= stats[:count] %></span>
|
105
|
+
<span class="call" abbr="<%= call.gsub("<", "<").gsub(">", ">") %>"><%= call.gsub("<", "<").gsub(">", ">") %></span>
|
106
|
+
</div><% end %>
|
114
107
|
</div>
|
115
108
|
</div>
|
116
109
|
</div>
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: stack_tracy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paul Engel
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-08-
|
13
|
+
date: 2012-08-26 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rich_support
|
@@ -34,6 +34,17 @@ dependencies:
|
|
34
34
|
version: 2.1.0
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: thor
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
37
48
|
description: Investigate and detect slow methods within the stack trace of your Ruby (optionally Sinatra) application
|
38
49
|
email:
|
39
50
|
- paul.engel@holder.nl
|
@@ -53,10 +64,12 @@ files:
|
|
53
64
|
- VERSION
|
54
65
|
- benchmarks/benchmark.rb
|
55
66
|
- bin/tracy
|
67
|
+
- demo.rb
|
56
68
|
- ext/stack_tracy/extconf.rb
|
57
69
|
- ext/stack_tracy/stack_tracy.c
|
58
70
|
- ext/stack_tracy/stack_tracy.h
|
59
71
|
- lib/stack_tracy.rb
|
72
|
+
- lib/stack_tracy/cli.rb
|
60
73
|
- lib/stack_tracy/core_ext.rb
|
61
74
|
- lib/stack_tracy/core_ext/kernel.rb
|
62
75
|
- lib/stack_tracy/event_info.rb
|
@@ -69,6 +82,7 @@ files:
|
|
69
82
|
- test/unit/test_tracy.rb
|
70
83
|
- ui/assets/bootstrap-tab.css
|
71
84
|
- ui/assets/bootstrap-tab.js
|
85
|
+
- ui/assets/comments.js
|
72
86
|
- ui/assets/jquery.js
|
73
87
|
- ui/assets/stack_tracy.css
|
74
88
|
- ui/assets/stack_tracy.js
|