rack-speedtracer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,88 @@
1
+ Rack::SpeedTracer
2
+ =========
3
+
4
+ Blog post: [Speed Tracer Server-side Tracing with Rack](http://www.igvita.com/2010/07/19/speed-tracer-server-side-tracing-with-rack/)
5
+
6
+ Rack::SpeedTracer middleware provides server-side tracing capabilities to any Rack compatible app. Include the middleware, instrument your application, and then load it in your Google Chrome + SpeedTracer to view detailed breakdown of your JavaScript/CSS load times, GC cycles, as well as, server side performance data provided by this middleware - you can preview both server side and client side performance data all within the same view in SpeedTracer!
7
+
8
+ Preview of a sample, server side Rails trace (see below for setup) in SpeedTracer:
9
+ ![rails trace](http://img.skitch.com/20100717-cd31bhd5dh13sge7c2q1hefh4p.png)
10
+
11
+ Todo / Wishlist
12
+ ---------------
13
+
14
+ * Pluggable storage, ala rack-cache: capped mongo collection, or capped redis list would be ideal
15
+ * At the moment all of the data is stored directly in memory (unbounded)
16
+ * It would be great to have a mechanism to either (a) limit number of store traces or (b) expire them
17
+ * Authentication / optional enable, ala rack-bug: IP-based, password based
18
+ * At the moment, every request will record & store a trace
19
+ * Could also do conditional tracing based on a request header: 'X-SpeedTracer: true'
20
+ * Automagic Rails instrumentation for AR, layout, etc, ala rack-bug
21
+
22
+ Because the middleware has no authentication, or does not yet provide a capped memory footprint, it is not ready to be run in production - use it in development mode until these mechanisms are in place. Patches are welcome, of course!
23
+
24
+ How it works
25
+ ------------
26
+
27
+ Rack::SpeedTracer provides a Tracer class which you can use to instrument your code. From there, the trace details are stored as a JSON blob, and a special X-TraceUrl header is sent back to the client. If the user clicks on the network resource that corresponds to a request which returned a X-TraceUrl header, then SpeedTracer will make a request to our app to load the server side trace. Rack::SpeedTracer responds to this request and returns the full trace - aka, the data is provided on demand.
28
+
29
+ ### Quickstart Guide ###
30
+
31
+ gem install rack-speedtracer
32
+
33
+ # in your rack app / rackup file
34
+ use Rack::SpeedTracer
35
+
36
+ # in your app
37
+ env['st.tracer'].run('name of operation') do
38
+ ... your code ...
39
+ end
40
+
41
+ Check out a full sample rack app: examples/runner.rb
42
+
43
+ ### Manually instrumenting Rails ###
44
+ To produce a server-side trace equivalent to one in the screenshot above:
45
+
46
+ # in your Gemfile
47
+ gem 'rack-speedtracer', :require => 'rack/speedtracer'
48
+
49
+ # in development.rb environment
50
+ config.middleware.use Rack::SpeedTracer
51
+
52
+ # define a widgets controller
53
+ class WidgetsController < ApplicationController
54
+ def index
55
+ env['st.tracer'].run('Widgets#index') do
56
+ env['st.tracer'].run("ActiveRecord: Widgets.all") do
57
+ Widget.all
58
+ end
59
+
60
+ env['st.tracer'].run('Render') { render :text => 'oh hai' }
61
+ end
62
+ end
63
+ end
64
+
65
+ Speed Tracer
66
+ ------------
67
+
68
+ Speed Tracer is a Google Chrome extension to help you identify and fix performance problems in your web applications. It visualizes metrics that are taken from low level instrumentation points inside of the browser and analyzes them as your application runs. Speed Tracer is available as a Chrome extension and works on all platforms where extensions are currently supported (Windows and Linux).
69
+
70
+ Using Speed Tracer you are able to get a better picture of where time is being spent in your application. This includes problems caused by JavaScript parsing and execution, layout, CSS style recalculation and selector matching, DOM event handling, network resource loading, timer fires, XMLHttpRequest callbacks, painting, and more.
71
+
72
+ * [Official SpeedTracer site](http://code.google.com/webtoolkit/speedtracer/)
73
+ * [Install SpeedTracer](http://code.google.com/webtoolkit/speedtracer/get-started.html#downloading)
74
+ * [Getting Started](http://code.google.com/webtoolkit/speedtracer/speed-tracer-examples.html)
75
+ * [Google Group](https://groups.google.com/group/speedtracer/topics)
76
+
77
+ License
78
+ -------
79
+
80
+ (The MIT License)
81
+
82
+ Copyright © 2010 Ilya Grigorik
83
+
84
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
85
+
86
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
87
+
88
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = 'rack-speedtracer'
8
+ gemspec.summary = 'SpeedTracer middleware for server side debugging'
9
+ gemspec.description = gemspec.summary
10
+ gemspec.email = 'ilya@igvita.com'
11
+ gemspec.homepage = 'http://github.com/igrigorik/rack-speedtracer'
12
+ gemspec.authors = ['Ilya Grigorik']
13
+ gemspec.add_dependency('rack')
14
+ gemspec.add_dependency('uuid')
15
+ gemspec.add_dependency('yajl-ruby')
16
+ gemspec.rubyforge_project = 'rack-speedtracer'
17
+ end
18
+
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts 'Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org'
22
+ end
23
+
24
+ task :default => :spec
25
+
26
+ Spec::Rake::SpecTask.new do |t|
27
+ t.ruby_opts = ['-rtest/unit']
28
+ t.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
Binary file
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+
4
+ $LOAD_PATH.unshift 'lib'
5
+ require 'rack/speedtracer'
6
+
7
+ class SomeApp
8
+ def call(env)
9
+ env['st.tracer'].run('computation: 5**100000') do
10
+ env['st.tracer'].run('computation 2: 5**10000') do
11
+ 5**10000
12
+ end
13
+
14
+ env['st.tracer'].run('sleep(0.01)') { sleep(0.01) }
15
+
16
+ 5**100000
17
+ end
18
+
19
+ env['st.tracer'].run('sleep(0.5)') do
20
+ sleep(0.5)
21
+ end
22
+
23
+ [200, {"Content-Type" => "text/plain"}, "Hello World"]
24
+ end
25
+ end
26
+
27
+ builder = Rack::Builder.new do
28
+ use Rack::CommonLogger
29
+ use Rack::SpeedTracer
30
+
31
+ run SomeApp.new
32
+ end
33
+
34
+ Rack::Handler::Thin.run builder.to_app, :Port => 4567
@@ -0,0 +1,14 @@
1
+ require 'rack'
2
+ require 'yajl'
3
+ require 'uuid'
4
+
5
+ require 'rack/speedtracer/context'
6
+ require 'rack/speedtracer/tracer'
7
+
8
+ module Rack
9
+ module SpeedTracer
10
+ def self.new(app, options = {}, &blk)
11
+ Context.new(app, options, &blk)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,73 @@
1
+ module Rack
2
+ module SpeedTracer
3
+
4
+ class Context
5
+ TRACER_PATH = /^\/speedtracer/.freeze
6
+ CONTENT_TYPE = 'application/json;charset=UTF-8'.freeze
7
+
8
+ attr_accessor :db
9
+
10
+ def initialize(app, options = {}, &blk)
11
+ @app = app
12
+ @uuid = UUID.new
13
+
14
+ # TODO: storage strategy...
15
+ # initialize_options with options
16
+ # yield self if block_given?
17
+
18
+ @db = {}
19
+ end
20
+
21
+ def call(env)
22
+ if env['PATH_INFO'].match(TRACER_PATH)
23
+
24
+ resp = Rack::Response.new('', 200)
25
+ resp['Content-Type'] = CONTENT_TYPE
26
+
27
+ case env['REQUEST_METHOD']
28
+ when 'HEAD' then
29
+ # SpeedTracer dispatches HEAD requests to verify the
30
+ # tracer endpoint when it detects the X-TraceUrl
31
+ # header for the first time. After the initial load
32
+ # the verification is cached by the extension.
33
+ #
34
+ # By default, we'll return 200.
35
+
36
+ when 'GET' then
37
+ # GET requests for specific trace are generated by
38
+ # the extension when the user expands the network
39
+ # resource tab. Hence, server-side tracer data is
40
+ # request on-demand, and we need to store it for
41
+ # some time.
42
+
43
+ qs = Rack::Utils.parse_query(env['QUERY_STRING'])
44
+ if qs['id'] && @db[qs['id']]
45
+ resp.write @db[qs['id']]
46
+ else
47
+ # Invalid request or missing request trace id
48
+ resp.status = 404
49
+ end
50
+ else
51
+ # SpeedTracer should only issue GET & HEAD requests
52
+ resp.status = 400
53
+ end
54
+
55
+ return resp.finish
56
+ end
57
+
58
+ env['st.id'] = @uuid.generate
59
+ env['st.tracer'] = Tracer.new(env['st.id'], env['REQUEST_METHOD'], env['REQUEST_URI'])
60
+
61
+ @status, @headers, @response = @app.call(env)
62
+ @db[env['st.id']] = env['st.tracer'].finish
63
+
64
+ # set the TraceUrl header to notify SpeedTracer that
65
+ # serverside meta-data is available for this request
66
+ @headers['X-TraceUrl'] = '/speedtracer?id=' + env['st.id']
67
+
68
+ [@status, @headers, @response]
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,122 @@
1
+ module Rack
2
+ module SpeedTracer
3
+
4
+ class TraceRecord
5
+ def initialize(id)
6
+ @id = id
7
+ @start = Time.now
8
+ @children = []
9
+ end
10
+
11
+ def finish; @finish = Time.now; end
12
+
13
+ private
14
+ # all timestamps in SpeedTracer are in milliseconds
15
+ def range(start, finish)
16
+ {
17
+ 'duration' => ((finish - start) * 1000).to_i,
18
+ 'start' => [start.to_i, start.usec/1000].join(''),
19
+ 'end' => [finish.to_i, finish.usec/1000].join('')
20
+ }
21
+ end
22
+ end
23
+
24
+ class ServerEvent < TraceRecord
25
+ attr_accessor :children
26
+
27
+ def initialize(id, file, line, method, name)
28
+ super(id)
29
+
30
+ @file = file
31
+ @line = line
32
+ @method = method
33
+ @name = name
34
+ end
35
+
36
+ def to_json
37
+ Yajl::Encoder.encode({
38
+ 'range' => range(@start, @finish),
39
+ 'id' => @id,
40
+ 'operation' => {
41
+ 'sourceCodeLocation' => {
42
+ 'className' => @file,
43
+ 'methodName' => @method,
44
+ 'lineNumber' => @line
45
+ },
46
+ 'type' => 'METHOD',
47
+ 'label' => @name
48
+ },
49
+ 'children' => @children
50
+ })
51
+ end
52
+ end
53
+
54
+ class Tracer < TraceRecord
55
+ def initialize(id, method, uri)
56
+ super(id)
57
+
58
+ @method = method
59
+ @uri = uri
60
+ @event_id = 0
61
+ @pstack = []
62
+ end
63
+
64
+ def run(name = '', &blk)
65
+ file, line, method = caller.first.split(':')
66
+ method = method.gsub(/^in|[^\w]+/, '') if method
67
+
68
+ # SpeedTracer allows us to nest events via child relationships,
69
+ # which means that we can use a stack to keep track of the currently
70
+ # executing events to produce a proper execution tree.
71
+ #
72
+ # Example execution graph:
73
+ #
74
+ # root
75
+ # -- event 1
76
+ # ---- event 2
77
+ # -- event 3
78
+ # ----- event 4
79
+ # ----- event 5
80
+ # ------ event 6
81
+ #
82
+
83
+ @event_id += 1
84
+ event = ServerEvent.new(@event_id, file, line, method, name)
85
+ @pstack.push event
86
+
87
+ blk.call # execute the provided code block
88
+ event.finish # finalize current event timers
89
+ @pstack.pop # pop current event from parent stack
90
+
91
+ if parent = @pstack.last
92
+ parent.children.push event
93
+ else
94
+ # no parent, means this is a child of root node
95
+ @children.push event
96
+ end
97
+ end
98
+
99
+ def finish
100
+ super()
101
+
102
+ Yajl::Encoder.encode({
103
+ 'trace' => {
104
+ 'date' => @start.to_i,
105
+ 'application' => 'Rack SpeedTracer',
106
+ 'range' => range(@start, @finish),
107
+ 'id' => @id,
108
+ 'frameStack' => {
109
+ 'range' => range(@start, @finish),
110
+ 'id' => '0',
111
+ 'operation' => {
112
+ 'type' => 'HTTP',
113
+ 'label' => [@method, @uri].join(' ')
114
+ },
115
+ 'children' => @children
116
+ }
117
+ }
118
+ })
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,64 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rack-speedtracer}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ilya Grigorik"]
12
+ s.date = %q{2010-07-19}
13
+ s.description = %q{SpeedTracer middleware for server side debugging}
14
+ s.email = %q{ilya@igvita.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ "README.md",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "examples/runner.png",
23
+ "examples/runner.rb",
24
+ "lib/rack/speedtracer.rb",
25
+ "lib/rack/speedtracer/context.rb",
26
+ "lib/rack/speedtracer/tracer.rb",
27
+ "rack-speedtracer.gemspec",
28
+ "spec/spec_helper.rb",
29
+ "spec/speedtracer_spec.rb",
30
+ "spec/tracer_spec.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/igrigorik/rack-speedtracer}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubyforge_project = %q{rack-speedtracer}
36
+ s.rubygems_version = %q{1.3.6}
37
+ s.summary = %q{SpeedTracer middleware for server side debugging}
38
+ s.test_files = [
39
+ "spec/spec_helper.rb",
40
+ "spec/speedtracer_spec.rb",
41
+ "spec/tracer_spec.rb",
42
+ "examples/runner.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<rack>, [">= 0"])
51
+ s.add_runtime_dependency(%q<uuid>, [">= 0"])
52
+ s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<rack>, [">= 0"])
55
+ s.add_dependency(%q<uuid>, [">= 0"])
56
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<rack>, [">= 0"])
60
+ s.add_dependency(%q<uuid>, [">= 0"])
61
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
62
+ end
63
+ end
64
+
@@ -0,0 +1,46 @@
1
+ $LOAD_PATH.unshift File.dirname(File.dirname(__FILE__)) + '/lib'
2
+
3
+ require 'rubygems'
4
+ require 'rack/speedtracer'
5
+ require 'yajl'
6
+ require 'spec'
7
+ require 'pp'
8
+
9
+ [ STDOUT, STDERR ].each { |io| io.sync = true }
10
+
11
+ def respond_with(status=200, headers={}, body=['Hello World'])
12
+ called = false
13
+ @app = lambda do |env|
14
+ called = true
15
+ response = Rack::Response.new(body, status, headers)
16
+ request = Rack::Request.new(env)
17
+
18
+ yield request, response if block_given?
19
+
20
+ response.finish
21
+ end
22
+
23
+ @app
24
+ end
25
+
26
+ def request(method, uri='/', opts={})
27
+ opts = {
28
+ 'rack.run_once' => true,
29
+ 'rack.errors' => @errors,
30
+ }.merge(opts)
31
+
32
+ @speedtracer ||= Rack::SpeedTracer::Context.new(@app)
33
+ @request = Rack::MockRequest.new(@speedtracer)
34
+
35
+ yield @speedtracer if block_given?
36
+
37
+ @request.request(method.to_s.upcase, uri, opts)
38
+ end
39
+
40
+ def get(uri, env={}, &b)
41
+ request(:get, uri, env, &b)
42
+ end
43
+
44
+ def head(uri, env={}, &b)
45
+ request(:head, uri, env, &b)
46
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::SpeedTracer do
4
+ let(:app) { [200, {'Content-Type' => 'text/plain'}, 'Hello World'] }
5
+
6
+ describe 'middleware' do
7
+ it 'take a backend and returns a middleware component' do
8
+ Rack::SpeedTracer.new(app).should respond_to(:call)
9
+ end
10
+
11
+ it 'take an options Hash' do
12
+ lambda { Rack::Cache.new(app, {}) }.should_not raise_error(ArgumentError)
13
+ end
14
+ end
15
+
16
+ describe 'response' do
17
+ it 'should set the X-TraceUrl header after rendering the response' do
18
+ respond_with(200)
19
+ response = get('/')
20
+
21
+ response.headers.should include 'X-TraceUrl'
22
+ response.headers['X-TraceUrl'].should match(/^\/speedtracer\?id=/)
23
+ end
24
+
25
+ it 'should respond with 200 to HEAD requests to the speedtracer endpoint' do
26
+ respond_with(200)
27
+ response = head('/speedtracer?id=test')
28
+
29
+ response.status.should == 200
30
+ response.headers['Content-Length'].to_i.should == 0
31
+ end
32
+
33
+ it 'should return a stored trace in JSON format' do
34
+ sample_trace = Yajl::Encoder.encode({'trace' => {}})
35
+
36
+ respond_with(200)
37
+ response = get('/speedtracer?id=test') do |st|
38
+ st.db['test'] = sample_trace
39
+ end
40
+
41
+ response.body.should == sample_trace
42
+ end
43
+
44
+ it 'should return 404 on missing trace' do
45
+ response = get('/speedtracer?id=test-missing')
46
+ response.status.should == 404
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::SpeedTracer::Tracer do
4
+
5
+ it 'should accept unique id, method, uri on initialize' do
6
+ lambda { Rack::SpeedTracer::Tracer.new(1, 'GET', '/') }.should_not raise_error
7
+ end
8
+
9
+ describe 'response' do
10
+ let(:tracer) { Rack::SpeedTracer::Tracer.new(1, 'GET', '/test') }
11
+
12
+ it 'should serialize to json on finish' do
13
+ lambda { Yajl::Parser.parse(tracer.finish) }.should_not raise_error
14
+ end
15
+
16
+ it 'should conform to base speedtracer JSON schema' do
17
+ trace = Yajl::Parser.parse(tracer.finish)['trace']
18
+
19
+ # Example base trace:
20
+ # {"date"=>1279403357,
21
+ # "application"=>"Rack SpeedTracer",
22
+ # "id"=>1,
23
+ # "range"=>{"duration"=>0, "end"=>"1279403357651", "start"=>"1279403357651"},
24
+ # "frameStack"=>
25
+ # {"id"=>"0",
26
+ # "range"=>{"duration"=>0, "end"=>"1279403357651", "start"=>"1279403357651"},
27
+ # "operation"=>{"label"=>"GET /test", "type"=>"HTTP"},
28
+ # "children"=>[]}}
29
+
30
+ trace.should include 'date'
31
+ trace.should include 'application'
32
+ trace.should include 'id'
33
+
34
+ trace.should include 'range'
35
+ trace['range'].should be_an_instance_of Hash
36
+
37
+ trace.should include 'frameStack'
38
+ trace['frameStack'].should be_an_instance_of Hash
39
+
40
+ # root node description
41
+ root = trace['frameStack']
42
+ root.should include 'id'
43
+ root['id'].to_i.should == 0
44
+
45
+ root.should include 'range'
46
+ root['range'].should be_an_instance_of Hash
47
+
48
+ root.should include 'operation'
49
+ root['operation'].should be_an_instance_of Hash
50
+ root['operation']['label'].should match('GET /test')
51
+ root['operation']['type'].should match('HTTP')
52
+
53
+ root.should include 'children'
54
+ root['children'].should be_an_instance_of Array
55
+ end
56
+ end
57
+
58
+ describe 'code tracing' do
59
+ let(:tracer) { Rack::SpeedTracer::Tracer.new(1, 'GET', '/test') }
60
+
61
+ it 'should provide a mechanism to trace a code block' do
62
+ lambda { tracer.run { sleep(0.01) }}.should_not raise_error
63
+ end
64
+
65
+ it 'should measure execution time in milliseconds' do
66
+ tracer.run { sleep(0.01) }
67
+ trace = Yajl::Parser.parse(tracer.finish)['trace']
68
+
69
+ trace['range']['duration'].to_i.should == 10
70
+ end
71
+
72
+ it 'should report traced codeblocks' do
73
+ tracer.run { sleep(0.01) }
74
+ trace = Yajl::Parser.parse(tracer.finish)['trace']
75
+
76
+ trace['frameStack']['children'].size.should == 1
77
+
78
+ child = trace['frameStack']['children'].first
79
+ child['id'].to_i.should == 1
80
+ child.should include 'operation'
81
+ child['operation'].should include 'label'
82
+ child.should include 'children'
83
+ end
84
+
85
+ it 'should accept optional label for each trace' do
86
+ tracer.run('label') { sleep(0.01) }
87
+ trace = Yajl::Parser.parse(tracer.finish)['trace']
88
+
89
+ trace['frameStack']['children'].first['operation']['label'].should match('label')
90
+ end
91
+
92
+ it 'should produce nested traces' do
93
+ tracer.run('parent') do
94
+ tracer.run('child') { sleep(0.01) }
95
+ end
96
+
97
+ trace = Yajl::Parser.parse(tracer.finish)['trace']
98
+
99
+ parent = trace['frameStack']['children'].first
100
+ parent['operation']['label'].should match('parent')
101
+ parent['children'].size.should == 1
102
+
103
+ child = parent['children'].first
104
+ child['operation']['label'].should match('child')
105
+ child['id'].to_i.should == 2
106
+ end
107
+ end
108
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-speedtracer
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Ilya Grigorik
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-19 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: uuid
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: yajl-ruby
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ type: :runtime
55
+ version_requirements: *id003
56
+ description: SpeedTracer middleware for server side debugging
57
+ email: ilya@igvita.com
58
+ executables: []
59
+
60
+ extensions: []
61
+
62
+ extra_rdoc_files:
63
+ - README.md
64
+ files:
65
+ - README.md
66
+ - Rakefile
67
+ - VERSION
68
+ - examples/runner.png
69
+ - examples/runner.rb
70
+ - lib/rack/speedtracer.rb
71
+ - lib/rack/speedtracer/context.rb
72
+ - lib/rack/speedtracer/tracer.rb
73
+ - rack-speedtracer.gemspec
74
+ - spec/spec_helper.rb
75
+ - spec/speedtracer_spec.rb
76
+ - spec/tracer_spec.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/igrigorik/rack-speedtracer
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project: rack-speedtracer
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: SpeedTracer middleware for server side debugging
107
+ test_files:
108
+ - spec/spec_helper.rb
109
+ - spec/speedtracer_spec.rb
110
+ - spec/tracer_spec.rb
111
+ - examples/runner.rb