rack-mini-profiler 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack-mini-profiler might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/lib/html/includes.css +15 -4
- data/lib/html/includes.js +93 -58
- data/lib/html/includes.less +21 -5
- data/lib/html/includes.tmpl +49 -49
- data/lib/html/list.tmpl +8 -8
- data/lib/mini_profiler/asset_version.rb +5 -0
- data/lib/mini_profiler/client_settings.rb +3 -3
- data/lib/mini_profiler/config.rb +11 -11
- data/lib/mini_profiler/gc_profiler.rb +10 -10
- data/lib/mini_profiler/profiler.rb +49 -71
- data/lib/mini_profiler/profiling_methods.rb +15 -17
- data/lib/mini_profiler/storage/file_store.rb +4 -4
- data/lib/mini_profiler/storage/memcache_store.rb +5 -7
- data/lib/mini_profiler/storage/memory_store.rb +56 -27
- data/lib/mini_profiler/storage/redis_store.rb +19 -11
- data/lib/mini_profiler/timer_struct/base.rb +33 -0
- data/lib/mini_profiler/timer_struct/client.rb +89 -0
- data/lib/mini_profiler/timer_struct/custom.rb +22 -0
- data/lib/mini_profiler/timer_struct/page.rb +62 -0
- data/lib/mini_profiler/timer_struct/request.rb +126 -0
- data/lib/mini_profiler/timer_struct/sql.rb +59 -0
- data/lib/mini_profiler/version.rb +2 -2
- data/lib/patches/db/activerecord.rb +42 -0
- data/lib/patches/db/moped.rb +12 -0
- data/lib/patches/db/mysql2.rb +30 -0
- data/lib/patches/db/pg.rb +104 -0
- data/lib/patches/db/plucky.rb +47 -0
- data/lib/patches/db/rsolr.rb +24 -0
- data/lib/patches/db/sequel.rb +10 -0
- data/lib/patches/sql_patches.rb +17 -255
- data/lib/rack-mini-profiler.rb +28 -0
- data/rack-mini-profiler.gemspec +6 -2
- metadata +16 -8
- data/lib/mini_profiler/client_timer_struct.rb +0 -78
- data/lib/mini_profiler/custom_timer_struct.rb +0 -22
- data/lib/mini_profiler/page_timer_struct.rb +0 -58
- data/lib/mini_profiler/request_timer_struct.rb +0 -115
- data/lib/mini_profiler/sql_timer_struct.rb +0 -58
- data/lib/mini_profiler/timer_struct.rb +0 -33
@@ -39,9 +39,9 @@ module Rack
|
|
39
39
|
@expires_in_seconds = args[:expires_in] || EXPIRES_IN_SECONDS
|
40
40
|
raise ArgumentError.new :path unless @path
|
41
41
|
@timer_struct_cache = FileCache.new(@path, "mp_timers")
|
42
|
-
@timer_struct_lock
|
43
|
-
@user_view_cache
|
44
|
-
@user_view_lock
|
42
|
+
@timer_struct_lock = Mutex.new
|
43
|
+
@user_view_cache = FileCache.new(@path, "mp_views")
|
44
|
+
@user_view_lock = Mutex.new
|
45
45
|
|
46
46
|
me = self
|
47
47
|
t = CacheCleanupThread.new do
|
@@ -77,7 +77,7 @@ module Rack
|
|
77
77
|
|
78
78
|
def save(page_struct)
|
79
79
|
@timer_struct_lock.synchronize {
|
80
|
-
@timer_struct_cache[page_struct[
|
80
|
+
@timer_struct_cache[page_struct[:id]] = page_struct
|
81
81
|
}
|
82
82
|
end
|
83
83
|
|
@@ -3,25 +3,23 @@ module Rack
|
|
3
3
|
class MemcacheStore < AbstractStore
|
4
4
|
|
5
5
|
EXPIRES_IN_SECONDS = 60 * 60 * 24
|
6
|
-
MAX_RETRIES
|
6
|
+
MAX_RETRIES = 10
|
7
7
|
|
8
8
|
def initialize(args = nil)
|
9
9
|
require 'dalli' unless defined? Dalli
|
10
10
|
args ||= {}
|
11
|
-
@prefix
|
12
|
-
@client
|
11
|
+
@prefix = args[:prefix] || "MPMemcacheStore"
|
12
|
+
@client = args[:client] || Dalli::Client.new
|
13
13
|
@expires_in_seconds = args[:expires_in] || EXPIRES_IN_SECONDS
|
14
14
|
end
|
15
15
|
|
16
16
|
def save(page_struct)
|
17
|
-
@client.set("#{@prefix}#{page_struct[
|
17
|
+
@client.set("#{@prefix}#{page_struct[:id]}", Marshal::dump(page_struct), @expires_in_seconds)
|
18
18
|
end
|
19
19
|
|
20
20
|
def load(id)
|
21
21
|
raw = @client.get("#{@prefix}#{id}")
|
22
|
-
if raw
|
23
|
-
Marshal::load raw
|
24
|
-
end
|
22
|
+
Marshal::load(raw) if raw
|
25
23
|
end
|
26
24
|
|
27
25
|
def set_unviewed(user, id)
|
@@ -4,48 +4,77 @@ module Rack
|
|
4
4
|
|
5
5
|
# Sub-class thread so we have a named thread (useful for debugging in Thread.list).
|
6
6
|
class CacheCleanupThread < Thread
|
7
|
+
|
8
|
+
def initialize(interval, cycle, store)
|
9
|
+
super
|
10
|
+
@store = store
|
11
|
+
@interval = interval
|
12
|
+
@cycle = cycle
|
13
|
+
@cycle_count = 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def should_cleanup?
|
17
|
+
@cycle_count * @interval >= @cycle
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# We don't want to hit the filesystem every 10s to clean up the cache so we need to do a bit of
|
22
|
+
# accounting to avoid sleeping that entire time. We don't want to sleep for the entire period because
|
23
|
+
# it means the thread will stay live in hot deployment scenarios, keeping a potentially large memory
|
24
|
+
# graph from being garbage collected upon undeploy.
|
25
|
+
def sleepy_run
|
26
|
+
cleanup if should_cleanup?
|
27
|
+
sleep(@interval)
|
28
|
+
increment_cycle
|
29
|
+
end
|
30
|
+
|
31
|
+
def cleanup
|
32
|
+
@store.cleanup_cache
|
33
|
+
@cycle_count = 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def cycle_count
|
37
|
+
@cycle_count
|
38
|
+
end
|
39
|
+
|
40
|
+
def increment_cycle
|
41
|
+
@cycle_count += 1
|
42
|
+
end
|
7
43
|
end
|
8
44
|
|
9
45
|
EXPIRES_IN_SECONDS = 60 * 60 * 24
|
46
|
+
CLEANUP_INTERVAL = 10
|
47
|
+
CLEANUP_CYCLE = 3600
|
10
48
|
|
11
49
|
def initialize(args = nil)
|
12
50
|
args ||= {}
|
13
|
-
@expires_in_seconds = args
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@user_view_cache = {}
|
51
|
+
@expires_in_seconds = args.fetch(:expires_in) { EXPIRES_IN_SECONDS }
|
52
|
+
initialize_locks
|
53
|
+
initialize_cleanup_thread(args)
|
54
|
+
end
|
18
55
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
56
|
+
def initialize_locks
|
57
|
+
@timer_struct_lock = Mutex.new
|
58
|
+
@user_view_lock = Mutex.new
|
59
|
+
@timer_struct_cache = {}
|
60
|
+
@user_view_cache = {}
|
61
|
+
end
|
25
62
|
|
63
|
+
#FIXME: use weak ref, trouble it may be broken in 1.9 so need to use the 'ref' gem
|
64
|
+
def initialize_cleanup_thread(args={})
|
65
|
+
cleanup_interval = args.fetch(:cleanup_interval) { CLEANUP_INTERVAL }
|
66
|
+
cleanup_cycle = args.fetch(:cleanup_cycle) { CLEANUP_CYCLE }
|
67
|
+
t = CacheCleanupThread.new(cleanup_interval, cleanup_cycle, self) do |t|
|
26
68
|
until Thread.current[:should_exit] do
|
27
|
-
|
28
|
-
# accounting to avoid sleeping that entire time. We don't want to sleep for the entire period because
|
29
|
-
# it means the thread will stay live in hot deployment scenarios, keeping a potentially large memory
|
30
|
-
# graph from being garbage collected upon undeploy.
|
31
|
-
if cycle_count * interval >= cleanup_cache_cycle
|
32
|
-
cycle_count = 1
|
33
|
-
me.cleanup_cache
|
34
|
-
end
|
35
|
-
|
36
|
-
sleep(interval)
|
37
|
-
cycle_count += 1
|
69
|
+
self.sleepy_run
|
38
70
|
end
|
39
71
|
end
|
40
|
-
|
41
72
|
at_exit { t[:should_exit] = true }
|
42
|
-
|
43
|
-
t
|
44
73
|
end
|
45
74
|
|
46
75
|
def save(page_struct)
|
47
76
|
@timer_struct_lock.synchronize {
|
48
|
-
@timer_struct_cache[page_struct[
|
77
|
+
@timer_struct_cache[page_struct[:id]] = page_struct
|
49
78
|
}
|
50
79
|
end
|
51
80
|
|
@@ -78,7 +107,7 @@ module Rack
|
|
78
107
|
def cleanup_cache
|
79
108
|
expire_older_than = ((Time.now.to_f - @expires_in_seconds) * 1000).to_i
|
80
109
|
@timer_struct_lock.synchronize {
|
81
|
-
@timer_struct_cache.delete_if { |k, v| v[
|
110
|
+
@timer_struct_cache.delete_if { |k, v| v[:started] < expire_older_than }
|
82
111
|
}
|
83
112
|
end
|
84
113
|
end
|
@@ -5,25 +5,32 @@ module Rack
|
|
5
5
|
EXPIRES_IN_SECONDS = 60 * 60 * 24
|
6
6
|
|
7
7
|
def initialize(args = nil)
|
8
|
-
@args
|
9
|
-
@prefix
|
10
|
-
@redis_connection
|
8
|
+
@args = args || {}
|
9
|
+
@prefix = @args.delete(:prefix) || 'MPRedisStore'
|
10
|
+
@redis_connection = @args.delete(:connection)
|
11
11
|
@expires_in_seconds = @args.delete(:expires_in) || EXPIRES_IN_SECONDS
|
12
12
|
end
|
13
13
|
|
14
14
|
def save(page_struct)
|
15
|
-
redis.setex "#{@prefix}#{page_struct[
|
15
|
+
redis.setex "#{@prefix}#{page_struct[:id]}", @expires_in_seconds, Marshal::dump(page_struct)
|
16
16
|
end
|
17
17
|
|
18
18
|
def load(id)
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
key = "#{@prefix}#{id}"
|
20
|
+
raw = redis.get key
|
21
|
+
begin
|
22
|
+
Marshal::load(raw) if raw
|
23
|
+
rescue
|
24
|
+
# bad format, junk old data
|
25
|
+
redis.del key
|
26
|
+
nil
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
25
30
|
def set_unviewed(user, id)
|
26
|
-
|
31
|
+
key = "#{@prefix}-#{user}-v"
|
32
|
+
redis.sadd key, id
|
33
|
+
redis.expire key, @expires_in_seconds
|
27
34
|
end
|
28
35
|
|
29
36
|
def set_viewed(user, id)
|
@@ -44,9 +51,10 @@ unviewed_ids: #{get_unviewed_ids(user)}
|
|
44
51
|
private
|
45
52
|
|
46
53
|
def redis
|
47
|
-
|
48
|
-
|
49
|
-
|
54
|
+
@redis_connection ||= begin
|
55
|
+
require 'redis' unless defined? Redis
|
56
|
+
Redis.new(@args)
|
57
|
+
end
|
50
58
|
end
|
51
59
|
|
52
60
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Rack
|
2
|
+
class MiniProfiler
|
3
|
+
module TimerStruct
|
4
|
+
# A base class for timing structures
|
5
|
+
class Base
|
6
|
+
|
7
|
+
def initialize(attrs={})
|
8
|
+
@attributes = attrs
|
9
|
+
end
|
10
|
+
|
11
|
+
def attributes
|
12
|
+
@attributes ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](name)
|
16
|
+
attributes[name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def []=(name, val)
|
20
|
+
attributes[name] = val
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json(*a)
|
25
|
+
# this does could take in an option hash, but the only interesting there is max_nesting.
|
26
|
+
# if this becomes an option we could increase
|
27
|
+
::JSON.generate( @attributes, :max_nesting => 100 )
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Rack
|
2
|
+
class MiniProfiler
|
3
|
+
module TimerStruct
|
4
|
+
|
5
|
+
# This class holds the client timings
|
6
|
+
class Client < TimerStruct::Base
|
7
|
+
|
8
|
+
def self.init_instrumentation
|
9
|
+
%Q{
|
10
|
+
<script type="text/javascript">
|
11
|
+
mPt=function(){var t=[];return{t:t,probe:function(n){t.push({d:new Date(),n:n})}}}()
|
12
|
+
</script>
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
# used by Railtie to instrument asset_tag for JS / CSS
|
17
|
+
def self.instrument(name, orig)
|
18
|
+
probe = "<script>mPt.probe('#{name}')</script>"
|
19
|
+
wrapped = probe
|
20
|
+
wrapped << orig
|
21
|
+
wrapped << probe
|
22
|
+
wrapped
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def initialize(env={})
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def redirect_count
|
31
|
+
self[:redirect_count]
|
32
|
+
end
|
33
|
+
|
34
|
+
def timings
|
35
|
+
self[:timings]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.init_from_form_data(env, page_struct)
|
39
|
+
timings = []
|
40
|
+
clientTimes, clientPerf, baseTime = nil
|
41
|
+
form = env['rack.request.form_hash']
|
42
|
+
|
43
|
+
clientPerf = form['clientPerformance'] if form
|
44
|
+
clientTimes = clientPerf['timing'] if clientPerf
|
45
|
+
baseTime = clientTimes['navigationStart'].to_i if clientTimes
|
46
|
+
return unless clientTimes && baseTime
|
47
|
+
|
48
|
+
probes = form['clientProbes']
|
49
|
+
translated = {}
|
50
|
+
if probes && !["null", ""].include?(probes)
|
51
|
+
probes.each do |id, val|
|
52
|
+
name = val["n"]
|
53
|
+
translated[name] ||= {}
|
54
|
+
if translated[name][:start]
|
55
|
+
translated[name][:finish] = val["d"]
|
56
|
+
else
|
57
|
+
translated[name][:start] = val["d"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
translated.each do |name, data|
|
63
|
+
h = {"Name" => name, "Start" => data[:start].to_i - baseTime}
|
64
|
+
h["Duration"] = data[:finish].to_i - data[:start].to_i if data[:finish]
|
65
|
+
timings.push(h)
|
66
|
+
end
|
67
|
+
|
68
|
+
clientTimes.keys.find_all{|k| k =~ /Start$/ }.each do |k|
|
69
|
+
start = clientTimes[k].to_i - baseTime
|
70
|
+
finish = clientTimes[k.sub(/Start$/, "End")].to_i - baseTime
|
71
|
+
duration = 0
|
72
|
+
duration = finish - start if finish > start
|
73
|
+
name = k.sub(/Start$/, "").split(/(?=[A-Z])/).map{|s| s.capitalize}.join(' ')
|
74
|
+
timings.push({"Name" => name, "Start" => start, "Duration" => duration}) if start >= 0
|
75
|
+
end
|
76
|
+
|
77
|
+
clientTimes.keys.find_all{|k| !(k =~ /(End|Start)$/)}.each do |k|
|
78
|
+
timings.push("Name" => k, "Start" => clientTimes[k].to_i - baseTime, "Duration" => -1)
|
79
|
+
end
|
80
|
+
|
81
|
+
TimerStruct::Client.new.tap do |rval|
|
82
|
+
rval[:redirect_count] = env['rack.request.form_hash']['clientPerformance']['navigation']['redirect_count']
|
83
|
+
rval[:timings] = timings
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Rack
|
2
|
+
class MiniProfiler
|
3
|
+
module TimerStruct
|
4
|
+
# Timing system for a custom timers such as cache, redis, RPC, external API
|
5
|
+
# calls, etc.
|
6
|
+
class Custom < TimerStruct::Base
|
7
|
+
def initialize(type, duration_ms, page, parent)
|
8
|
+
@parent = parent
|
9
|
+
@page = page
|
10
|
+
@type = type
|
11
|
+
start_millis = ((Time.now.to_f * 1000).to_i - page[:started]) - duration_ms
|
12
|
+
super(
|
13
|
+
:type => type,
|
14
|
+
:start_milliseconds => start_millis,
|
15
|
+
:duration_milliseconds => duration_ms,
|
16
|
+
:parent_timing_id => nil
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Rack
|
2
|
+
class MiniProfiler
|
3
|
+
module TimerStruct
|
4
|
+
|
5
|
+
# TimerStruct::Page
|
6
|
+
# Root: TimerStruct::Request
|
7
|
+
# :has_many TimerStruct::Request children
|
8
|
+
# :has_many TimerStruct::Sql children
|
9
|
+
# :has_many TimerStruct::Custom children
|
10
|
+
class Page < TimerStruct::Base
|
11
|
+
def initialize(env)
|
12
|
+
timer_id = MiniProfiler.generate_id
|
13
|
+
page_name = env['PATH_INFO']
|
14
|
+
started_at = (Time.now.to_f * 1000).to_i
|
15
|
+
machine_name = env['SERVER_NAME']
|
16
|
+
super(
|
17
|
+
:id => timer_id,
|
18
|
+
:name => page_name,
|
19
|
+
:started => started_at,
|
20
|
+
:machine_name => machine_name,
|
21
|
+
:level => 0,
|
22
|
+
:user => "unknown user",
|
23
|
+
:has_user_viewed => false,
|
24
|
+
:client_timings => nil,
|
25
|
+
:duration_milliseconds => 0,
|
26
|
+
:has_trivial_timings => true,
|
27
|
+
:has_all_trivial_timings => false,
|
28
|
+
:trivial_duration_threshold_milliseconds => 2,
|
29
|
+
:head => nil,
|
30
|
+
:duration_milliseconds_in_sql => 0,
|
31
|
+
:has_sql_timings => true,
|
32
|
+
:has_duplicate_sql_timings => false,
|
33
|
+
:executed_readers => 0,
|
34
|
+
:executed_scalars => 0,
|
35
|
+
:executed_non_queries => 0,
|
36
|
+
:custom_timing_names => [],
|
37
|
+
:custom_timing_stats => {}
|
38
|
+
)
|
39
|
+
name = "#{env['REQUEST_METHOD']} http://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{env['SCRIPT_NAME']}#{env['PATH_INFO']}"
|
40
|
+
self[:root] = TimerStruct::Request.createRoot(name, self)
|
41
|
+
end
|
42
|
+
|
43
|
+
def duration_ms
|
44
|
+
@attributes[:root][:duration_milliseconds]
|
45
|
+
end
|
46
|
+
|
47
|
+
def root
|
48
|
+
@attributes[:root]
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_json(*a)
|
52
|
+
attribs = @attributes.merge(
|
53
|
+
:started => '/Date(%d)/' % @attributes[:started],
|
54
|
+
:duration_milliseconds => @attributes[:root][:duration_milliseconds],
|
55
|
+
:custom_timing_names => @attributes[:custom_timing_stats].keys.sort
|
56
|
+
)
|
57
|
+
::JSON.generate(attribs, :max_nesting => 100)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Rack
|
2
|
+
class MiniProfiler
|
3
|
+
module TimerStruct
|
4
|
+
class Request < TimerStruct::Base
|
5
|
+
|
6
|
+
def self.createRoot(name, page)
|
7
|
+
TimerStruct::Request.new(name, page, nil).tap do |timer|
|
8
|
+
timer[:is_root] = true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :children_duration
|
13
|
+
|
14
|
+
def initialize(name, page, parent)
|
15
|
+
start_millis = (Time.now.to_f * 1000).to_i - page[:started]
|
16
|
+
depth = parent ? parent.depth + 1 : 0
|
17
|
+
super(
|
18
|
+
:id => MiniProfiler.generate_id,
|
19
|
+
:name => name,
|
20
|
+
:duration_milliseconds => 0,
|
21
|
+
:duration_without_children_milliseconds => 0,
|
22
|
+
:start_milliseconds => start_millis,
|
23
|
+
:parent_timing_id => nil,
|
24
|
+
:children => [],
|
25
|
+
:has_children => false,
|
26
|
+
:key_values => nil,
|
27
|
+
:has_sql_timings => false,
|
28
|
+
:has_duplicate_sql_timings => false,
|
29
|
+
:trivial_duration_threshold_milliseconds => 2,
|
30
|
+
:sql_timings => [],
|
31
|
+
:sql_timings_duration_milliseconds => 0,
|
32
|
+
:is_trivial => false,
|
33
|
+
:is_root => false,
|
34
|
+
:depth => depth,
|
35
|
+
:executed_readers => 0,
|
36
|
+
:executed_scalars => 0,
|
37
|
+
:executed_non_queries => 0,
|
38
|
+
:custom_timing_stats => {},
|
39
|
+
:custom_timings => {}
|
40
|
+
)
|
41
|
+
@children_duration = 0
|
42
|
+
@start = Time.now
|
43
|
+
@parent = parent
|
44
|
+
@page = page
|
45
|
+
end
|
46
|
+
|
47
|
+
def duration_ms
|
48
|
+
self[:duration_milliseconds]
|
49
|
+
end
|
50
|
+
|
51
|
+
def start_ms
|
52
|
+
self[:start_milliseconds]
|
53
|
+
end
|
54
|
+
|
55
|
+
def start
|
56
|
+
@start
|
57
|
+
end
|
58
|
+
|
59
|
+
def depth
|
60
|
+
self[:depth]
|
61
|
+
end
|
62
|
+
|
63
|
+
def children
|
64
|
+
self[:children]
|
65
|
+
end
|
66
|
+
|
67
|
+
def custom_timings
|
68
|
+
self[:custom_timings]
|
69
|
+
end
|
70
|
+
|
71
|
+
def sql_timings
|
72
|
+
self[:sql_timings]
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_child(name)
|
76
|
+
TimerStruct::Request.new(name, @page, self).tap do |timer|
|
77
|
+
self[:children].push(timer)
|
78
|
+
self[:has_children] = true
|
79
|
+
timer[:parent_timing_id] = self[:id]
|
80
|
+
timer[:depth] = self[:depth] + 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_sql(query, elapsed_ms, page, skip_backtrace = false, full_backtrace = false)
|
85
|
+
TimerStruct::Sql.new(query, elapsed_ms, page, self , skip_backtrace, full_backtrace).tap do |timer|
|
86
|
+
self[:sql_timings].push(timer)
|
87
|
+
timer[:parent_timing_id] = self[:id]
|
88
|
+
self[:has_sql_timings] = true
|
89
|
+
self[:sql_timings_duration_milliseconds] += elapsed_ms
|
90
|
+
page[:duration_milliseconds_in_sql] += elapsed_ms
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_custom(type, elapsed_ms, page)
|
95
|
+
TimerStruct::Custom.new(type, elapsed_ms, page, self).tap do |timer|
|
96
|
+
timer[:parent_timing_id] = self[:id]
|
97
|
+
|
98
|
+
self[:custom_timings][type] ||= []
|
99
|
+
self[:custom_timings][type].push(timer)
|
100
|
+
|
101
|
+
self[:custom_timing_stats][type] ||= {:count => 0, :duration => 0.0}
|
102
|
+
self[:custom_timing_stats][type][:count] += 1
|
103
|
+
self[:custom_timing_stats][type][:duration] += elapsed_ms
|
104
|
+
|
105
|
+
page[:custom_timing_stats][type] ||= {:count => 0, :duration => 0.0}
|
106
|
+
page[:custom_timing_stats][type][:count] += 1
|
107
|
+
page[:custom_timing_stats][type][:duration] += elapsed_ms
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def record_time(milliseconds = nil)
|
112
|
+
milliseconds ||= (Time.now - @start) * 1000
|
113
|
+
self[:duration_milliseconds] = milliseconds
|
114
|
+
self[:is_trivial] = true if milliseconds < self[:trivial_duration_threshold_milliseconds]
|
115
|
+
self[:duration_without_children_milliseconds] = milliseconds - @children_duration
|
116
|
+
|
117
|
+
if @parent
|
118
|
+
@parent.children_duration += milliseconds
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|