time_bandits 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/lib/time_bandits.rb +8 -1
- data/lib/time_bandits/monkey_patches/action_controller_rails2.rb +29 -2
- data/lib/time_bandits/monkey_patches/memcache-client.rb +8 -0
- data/lib/time_bandits/monkey_patches/memcached.rb +37 -8
- data/lib/time_bandits/time_consumers/database.rb +8 -0
- data/lib/time_bandits/time_consumers/database_rails2.rb +8 -0
- data/lib/time_bandits/time_consumers/garbage_collection.rb +19 -0
- data/lib/time_bandits/time_consumers/mem_cache.rb +4 -0
- data/lib/time_bandits/time_consumers/memcached.rb +4 -0
- data/lib/time_bandits/version.rb +1 -1
- metadata +6 -6
data/.gitignore
CHANGED
data/lib/time_bandits.rb
CHANGED
@@ -18,6 +18,7 @@ module TimeBandits
|
|
18
18
|
|
19
19
|
mattr_accessor :time_bandits
|
20
20
|
self.time_bandits = []
|
21
|
+
|
21
22
|
def self.add(bandit)
|
22
23
|
self.time_bandits << bandit unless self.time_bandits.include?(bandit)
|
23
24
|
end
|
@@ -34,6 +35,12 @@ module TimeBandits
|
|
34
35
|
time_bandits.map{|b| b.runtime}.join(", ")
|
35
36
|
end
|
36
37
|
|
38
|
+
def self.metrics
|
39
|
+
metrics = {}
|
40
|
+
time_bandits.each{|b| metrics.merge! b.metrics}
|
41
|
+
metrics
|
42
|
+
end
|
43
|
+
|
37
44
|
def self.benchmark(title="Completed in", logger=Rails.logger)
|
38
45
|
reset
|
39
46
|
result = nil
|
@@ -42,7 +49,7 @@ module TimeBandits
|
|
42
49
|
begin
|
43
50
|
result = yield
|
44
51
|
rescue Exception => e
|
45
|
-
logger.error "Exception: #{e}"
|
52
|
+
logger.error "Exception: #{e}:\n#{e.backtrace[0..5].join("\n")}"
|
46
53
|
end
|
47
54
|
end
|
48
55
|
consumed # needs to be called for DB time consumer
|
@@ -3,7 +3,6 @@
|
|
3
3
|
#
|
4
4
|
# the original rails stack looks like this:
|
5
5
|
#
|
6
|
-
# ApplicationController#process_with_unload_user
|
7
6
|
# ActionController::SessionManagement#process_with_session_management_support
|
8
7
|
# ActionController::Filters#process_with_filters
|
9
8
|
# ActionController::Base#process
|
@@ -17,7 +16,6 @@
|
|
17
16
|
#
|
18
17
|
# with the plugin installed, the stack looks like this:
|
19
18
|
#
|
20
|
-
# ApplicationController#process_with_unload_user
|
21
19
|
# ActionController::SessionManagement#process_with_session_management_support
|
22
20
|
# ActionController::Filters#process_with_filters
|
23
21
|
# ActionController::Base#process
|
@@ -31,6 +29,23 @@
|
|
31
29
|
# =========================================================================================================
|
32
30
|
|
33
31
|
module ActionController #:nodoc:
|
32
|
+
|
33
|
+
class Base
|
34
|
+
# this ugly hack is used to get the started_at and ip information into time bandits metrics
|
35
|
+
def request_origin
|
36
|
+
# this *needs* to be cached!
|
37
|
+
# otherwise you'd get different results if calling it more than once
|
38
|
+
@request_origin ||=
|
39
|
+
begin
|
40
|
+
remote_ip = request.remote_ip
|
41
|
+
t = Time.now
|
42
|
+
started_at = "#{t.to_s(:db)}.#{t.usec}"
|
43
|
+
request.env["time_bandits.metrics"] = {:ip => remote_ip, :started_at => started_at}
|
44
|
+
"#{remote_ip} at #{started_at}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
34
49
|
module TimeBanditry #:nodoc:
|
35
50
|
def self.included(base)
|
36
51
|
base.class_eval do
|
@@ -88,6 +103,7 @@ module ActionController #:nodoc:
|
|
88
103
|
|
89
104
|
logger.info(log_message)
|
90
105
|
response.headers["X-Runtime"] = "#{sprintf("%.0f", seconds * 1000)}ms"
|
106
|
+
merge_metrics(seconds)
|
91
107
|
else
|
92
108
|
perform_action_without_time_bandits
|
93
109
|
end
|
@@ -114,6 +130,7 @@ module ActionController #:nodoc:
|
|
114
130
|
|
115
131
|
logger.info(log_message)
|
116
132
|
response.headers["X-Runtime"] = "#{sprintf("%.0f", seconds * 1000)}ms"
|
133
|
+
merge_metrics(seconds)
|
117
134
|
else
|
118
135
|
rescue_action_without_time_bandits(exception)
|
119
136
|
end
|
@@ -121,6 +138,16 @@ module ActionController #:nodoc:
|
|
121
138
|
|
122
139
|
private
|
123
140
|
|
141
|
+
def merge_metrics(total_time_seconds)
|
142
|
+
basic_request_metrics = {
|
143
|
+
:total_time => total_time_seconds * 1000,
|
144
|
+
:view_time => (@view_runtime||0) * 1000,
|
145
|
+
:code => response.status.to_i,
|
146
|
+
:action => "#{self.class.name}\##{action_name}",
|
147
|
+
}
|
148
|
+
request.env["time_bandits.metrics"].merge!(TimeBandits.metrics).merge!(basic_request_metrics)
|
149
|
+
end
|
150
|
+
|
124
151
|
def view_runtime
|
125
152
|
"View: %.3f" % ((@view_runtime||0) * 1000)
|
126
153
|
end
|
@@ -24,6 +24,14 @@ class MemCache
|
|
24
24
|
sprintf "MC: %.3f(%dr,%dm)", @@cache_latency * 1000, @@cache_touches, @@cache_misses
|
25
25
|
end
|
26
26
|
|
27
|
+
def self.metrics
|
28
|
+
{
|
29
|
+
:memcache_time => @@cache_latency * 1000,
|
30
|
+
:memcache_calls => @@cache_touches,
|
31
|
+
:memcache_misses => @@cache_misses
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
27
35
|
def get_with_benchmark(key, raw = false)
|
28
36
|
val = nil
|
29
37
|
@@cache_latency += Benchmark.realtime{ val=get_without_benchmark(key, raw) }
|
@@ -6,27 +6,38 @@ require 'memcached'
|
|
6
6
|
raise "Memcached needs to be loaded before monkey patching it" unless defined?(Memcached)
|
7
7
|
|
8
8
|
class Memcached
|
9
|
-
@@cache_latency = 0.0
|
10
|
-
@@cache_touches = 0
|
11
|
-
@@cache_misses = 0
|
12
9
|
|
13
10
|
def self.reset_benchmarks
|
14
11
|
@@cache_latency = 0.0
|
15
|
-
@@
|
12
|
+
@@cache_calls = 0
|
16
13
|
@@cache_misses = 0
|
14
|
+
@@cache_reads = 0
|
15
|
+
@@cache_writes = 0
|
17
16
|
end
|
17
|
+
self.reset_benchmarks
|
18
18
|
|
19
19
|
def self.get_benchmarks
|
20
|
-
[@@cache_latency, @@
|
20
|
+
[@@cache_latency, @@cache_calls, @@cache_reads, @@cache_misses, @@cache_writes]
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.cache_runtime
|
24
|
-
sprintf "MC: %.3f(%dr,%dm)", @@cache_latency * 1000, @@
|
24
|
+
sprintf "MC: %.3f(%dr,%dm,%dw,%dc)", @@cache_latency * 1000, @@cache_reads, @@cache_misses, @@cache_writes, @@cache_calls
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.metrics
|
28
|
+
{
|
29
|
+
:memcache_time => @@cache_latency * 1000,
|
30
|
+
:memcache_calls => @@cache_calls,
|
31
|
+
:memcache_misses => @@cache_misses,
|
32
|
+
:memcache_reads => @@cache_reads,
|
33
|
+
:memcache_writes => @@cache_writes
|
34
|
+
}
|
25
35
|
end
|
26
36
|
|
27
37
|
def get_with_benchmark(key, marshal = true)
|
28
|
-
@@
|
38
|
+
@@cache_calls += 1
|
29
39
|
if key.is_a?(Array)
|
40
|
+
@@cache_reads += (num_keys = key.size)
|
30
41
|
results = []
|
31
42
|
@@cache_latency += Benchmark.realtime do
|
32
43
|
begin
|
@@ -34,10 +45,11 @@ class Memcached
|
|
34
45
|
rescue Memcached::NotFound
|
35
46
|
end
|
36
47
|
end
|
37
|
-
@@cache_misses +=
|
48
|
+
@@cache_misses += num_keys - results.size
|
38
49
|
results
|
39
50
|
else
|
40
51
|
val = nil
|
52
|
+
@@cache_reads += 1
|
41
53
|
@@cache_latency += Benchmark.realtime do
|
42
54
|
begin
|
43
55
|
val = get_without_benchmark(key, marshal)
|
@@ -51,5 +63,22 @@ class Memcached
|
|
51
63
|
alias_method :get_without_benchmark, :get
|
52
64
|
alias_method :get, :get_with_benchmark
|
53
65
|
|
66
|
+
def set_with_benchmark(*args)
|
67
|
+
@@cache_calls += 1
|
68
|
+
@@cache_writes += 1
|
69
|
+
result = nil
|
70
|
+
exception = nil
|
71
|
+
@@cache_latency += Benchmark.realtime do
|
72
|
+
begin
|
73
|
+
set_without_benchmark(*args)
|
74
|
+
rescue Exception => exception
|
75
|
+
end
|
76
|
+
end
|
77
|
+
raise exception if exception
|
78
|
+
result
|
79
|
+
end
|
80
|
+
alias_method :set_without_benchmark, :set
|
81
|
+
alias_method :set, :set_with_benchmark
|
82
|
+
|
54
83
|
end
|
55
84
|
|
@@ -36,6 +36,14 @@ module TimeBandits
|
|
36
36
|
sprintf "ActiveRecord: %.3fms(%dq,%dh)", *info
|
37
37
|
end
|
38
38
|
|
39
|
+
def metrics
|
40
|
+
{
|
41
|
+
:db_calls => @call_count,
|
42
|
+
:db_sql_query_cache_hits => @query_cache_hits,
|
43
|
+
:db_time => @consumed * 1000
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
39
47
|
private
|
40
48
|
|
41
49
|
def reset_stats
|
@@ -36,6 +36,14 @@ module TimeBandits
|
|
36
36
|
sprintf "DB: %.3f(%d,%d)", @consumed * 1000, @call_count, @query_cache_hits
|
37
37
|
end
|
38
38
|
|
39
|
+
def metrics
|
40
|
+
{
|
41
|
+
:db_calls => @call_count,
|
42
|
+
:db_sql_query_cache_hits => @query_cache_hits,
|
43
|
+
:db_time => @consumed * 1000
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
39
47
|
private
|
40
48
|
def all_connections
|
41
49
|
ActiveRecord::Base.connection_handler.connection_pools.values.map{|pool| pool.connections}.flatten
|
@@ -87,12 +87,31 @@ module TimeBandits
|
|
87
87
|
GCFORMAT % [consumed_gc_time * 1000, collections, heap_growth, heap_slots, allocated_objects, allocated_size, live_data_set_size]
|
88
88
|
end
|
89
89
|
|
90
|
+
def metrics
|
91
|
+
{
|
92
|
+
:gc_time => consumed_gc_time * 1000,
|
93
|
+
:gc_calls => collections,
|
94
|
+
:heap_growth => heap_growth,
|
95
|
+
:heap_size => GC.heap_slots,
|
96
|
+
:allocated_objects => allocated_objects,
|
97
|
+
:allocated_bytes => allocated_size,
|
98
|
+
:live_data_set_size => live_data_set_size
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
90
102
|
else
|
91
103
|
|
92
104
|
def runtime
|
93
105
|
"GC: %.3f(%d)" % [consumed_gc_time * 1000, collections]
|
94
106
|
end
|
95
107
|
|
108
|
+
def metrics
|
109
|
+
{
|
110
|
+
:gc_time => consumed_gc_time * 1000,
|
111
|
+
:gc_calls => collections
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
96
115
|
end
|
97
116
|
end
|
98
117
|
end
|
data/lib/time_bandits/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_bandits
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.9
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Stefan Kaes
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-28 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -99,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements: []
|
100
100
|
|
101
101
|
rubyforge_project:
|
102
|
-
rubygems_version: 1.
|
102
|
+
rubygems_version: 1.6.2
|
103
103
|
signing_key:
|
104
104
|
specification_version: 3
|
105
105
|
summary: Custom performance logging for Rails
|