time_bandits 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ rdoc
2
+ pkg/*
3
+ *.gem
4
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in time_bandits.gemspec
4
+ gemspec
@@ -0,0 +1,98 @@
1
+ = Time Bandits
2
+
3
+ == About
4
+
5
+ Time Bandits is a plugin which enhances Rails' controller/view/db benchmark logging.
6
+
7
+ == Usage
8
+
9
+ Without configuration, the standard Rails 'Completed line' will change
10
+ from its default format
11
+
12
+ Completed in 56ms (View: 28, DB: 5) | 200 OK [http://127.0.0.1/jobs/info]
13
+
14
+ to:
15
+
16
+ Completed in 56.278ms (View: 28.488, DB: 5.111(2,0)) | 200 OK [http://127.0.0.1/jobs/info]
17
+
18
+ Here "DB: 5.111(2,0)" means that 2 DB queries were executed and there were 0 SQL query cache hits.
19
+
20
+ However, non-trivial applications also rather often use external services, which consume time that adds
21
+ to your total response time, and sometimes these external services are not under your control. In these
22
+ cases, it's very helpful to have an entry in your log file that records the time spent in the exterrnal
23
+ service (so that you can prove that it wasn't your rails app that slowed down during your slashdotting,
24
+ for example ;-).
25
+
26
+ Additional TimeConsumers can be added to the log using the "Timebandits.add" method.
27
+
28
+ Example:
29
+
30
+ TimeBandits.add TimeBandits::TimeConsumers::Memcached
31
+ TimeBandits.add TimeBandits::TimeConsumers::GarbageCollection.instance if GC.respond_to? :enable_stats
32
+
33
+ Here we've added two additional consumers, which are already provided with the plugin. (Note that GC
34
+ information requires a patched ruby, (e.g. http://github.com/skaes/matzruby, branch ruby187pl202patched
35
+ or Ruby Enterprise Edition).
36
+
37
+ With these two new time consumers, the log line changes to
38
+
39
+ Completed in 680.378ms (View: 28.488, DB: 5.111(2,0), MC: 5.382(6r,0m), GC: 120.100(1), HP: 0(2000000,546468,18682541,934967)) | 200 OK [http://127.0.0.1/jobs/info]
40
+
41
+ "MC: 5.382(6r,0m)" means that 6 memcache reads were performed and all keys were found in the cache (0 misses).
42
+
43
+ "GC: 120.100(1)" tells us that 1 garbage collection was triggered during the request, taking 120.100 milliseconds.
44
+
45
+ "HP: 0(2000000,546468,18682541,934967)" shows statistics on heap usage. The format is g(s,a,m,l), where
46
+
47
+ g: heap growth during the request (#slots)
48
+ s: size of the heap after request processing was completed (#slots)
49
+ a: number of object allocations during the request (#slots)
50
+ m: number of bytes allocated by the ruby x_malloc call (#bytes)
51
+ l: live data set size after last GC (#slots)
52
+
53
+ It's pretty easy to write additional time consumers; please refer to the source code.
54
+
55
+
56
+ == Prerequisites
57
+
58
+ Rails 2.3.2, 2.3.3 or 2.3.4 The plugin will raise an error if you try
59
+ to use it with a different version.
60
+
61
+ A ruby with the railsbench GC patches applied, if you want to include
62
+ GC and heap size information in the completed line. This is very
63
+ useful, especially if you want to analyze your rails logs using logjam
64
+ (see http://github.com/alpinegizmo/logjam/).
65
+
66
+
67
+ == History
68
+
69
+ This plugin started from the code of the 'custom_benchmark' plugin
70
+ written by tylerkovacs. However, we changed so much of the code that
71
+ is is practically a full rewrite, hence we changed the name.
72
+
73
+
74
+ == License
75
+
76
+ Copyright (c) 2009 Stefan Kaes <skaes@railsexpress.de>
77
+
78
+ Some portions Copyright (c) 2008 tylerkovacs
79
+
80
+ Permission is hereby granted, free of charge, to any person obtaining
81
+ a copy of this software and associated documentation files (the
82
+ "Software"), to deal in the Software without restriction, including
83
+ without limitation the rights to use, copy, modify, merge, publish,
84
+ distribute, sublicense, and/or sell copies of the Software, and to
85
+ permit persons to whom the Software is furnished to do so, subject to
86
+ the following conditions:
87
+
88
+ The above copyright notice and this permission notice shall be
89
+ included in all copies or substantial portions of the Software.
90
+
91
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
92
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
93
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
94
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
95
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
96
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
97
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
98
+
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,50 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module TimeBandits
4
+
5
+ module TimeConsumers
6
+ autoload :Database, 'time_bandits/time_consumers/database'
7
+ autoload :GarbageCollection, 'time_bandits/time_consumers/garbage_collection'
8
+ autoload :JMX, 'time_bandits/time_consumers/jmx'
9
+ autoload :MemCache, 'time_bandits/time_consumers/mem_cache'
10
+ autoload :Memcached, 'time_bandits/time_consumers/memcached'
11
+ end
12
+
13
+ require 'time_bandits/railtie' if defined?(Rails)
14
+
15
+ mattr_accessor :time_bandits
16
+ self.time_bandits = []
17
+ def self.add(bandit)
18
+ self.time_bandits << bandit unless self.time_bandits.include?(bandit)
19
+ end
20
+
21
+ def self.reset
22
+ time_bandits.each{|b| b.reset}
23
+ end
24
+
25
+ def self.consumed
26
+ time_bandits.map{|b| b.consumed}.sum
27
+ end
28
+
29
+ def self.runtime
30
+ time_bandits.map{|b| b.runtime}.join(", ")
31
+ end
32
+
33
+ def self.benchmark(title="Completed in", logger=Rails.logger)
34
+ reset
35
+ result = nil
36
+ e = nil
37
+ seconds = Benchmark.realtime do
38
+ begin
39
+ result = yield
40
+ rescue Exception => e
41
+ logger.error "Exception: #{e}"
42
+ end
43
+ end
44
+ consumed # needs to be called for DB time consumer
45
+ rc = e ? "500 Internal Server Error" : "200 OK"
46
+ logger.info "#{title} #{sprintf("%.3f", seconds * 1000)}ms (#{runtime}) | #{rc}"
47
+ raise e if e
48
+ result
49
+ end
50
+ end
@@ -0,0 +1,85 @@
1
+ require 'action_controller/metal/instrumentation'
2
+ require 'action_controller/log_subscriber'
3
+
4
+ module ActionController #:nodoc:
5
+
6
+ module Instrumentation
7
+
8
+ # patch to ensure that the completed line is always written to the log
9
+ def process_action(action, *args)
10
+ TimeBandits.reset
11
+
12
+ raw_payload = {
13
+ :controller => self.class.name,
14
+ :action => self.action_name,
15
+ :params => request.filtered_parameters,
16
+ :formats => request.formats.map(&:to_sym),
17
+ :method => request.method,
18
+ :path => (request.fullpath rescue "unknown")
19
+ }
20
+
21
+ ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
22
+
23
+ exception = nil
24
+ result = ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
25
+ begin
26
+ super
27
+ rescue Exception => exception
28
+ response.status = 500
29
+ nil
30
+ ensure
31
+ payload[:status] = response.status
32
+ append_info_to_payload(payload)
33
+ end
34
+ end
35
+ raise exception if exception
36
+ result
37
+ end
38
+
39
+ # patch to ensure that render times are always recorded in the log
40
+ def render(*args)
41
+ render_output = nil
42
+ exception = nil
43
+ self.view_runtime = cleanup_view_runtime do
44
+ Benchmark.ms do
45
+ begin
46
+ render_output = super
47
+ rescue Exception => exception
48
+ end
49
+ end
50
+ end
51
+ raise exception if exception
52
+ render_output
53
+ end
54
+
55
+ def cleanup_view_runtime #:nodoc:
56
+ consumed_before_rendering = TimeBandits.consumed
57
+ runtime = yield
58
+ consumed_during_rendering = TimeBandits.consumed - consumed_before_rendering
59
+ runtime - consumed_during_rendering
60
+ end
61
+ end
62
+
63
+ class LogSubscriber
64
+ def process_action(event)
65
+ payload = event.payload
66
+ additions = ActionController::Base.log_process_action(payload)
67
+ Thread.current[:time_bandits_completed_info] = [event.duration, additions]
68
+ end
69
+ end
70
+
71
+ module TimeBanditry #:nodoc:
72
+ extend ActiveSupport::Concern
73
+
74
+ module ClassMethods
75
+ def log_process_action(payload) #:nodoc:
76
+ messages = super
77
+ TimeBandits.time_bandits.each do |bandit|
78
+ messages << bandit.runtime
79
+ end
80
+ messages
81
+ end
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,85 @@
1
+ # this file monkey patches class ActiveRecord::ConnectionAdapters::AbstractAdapter
2
+ # and the module module ActiveRecord::ConnectionAdapters::QueryCache
3
+ # to count the number of sql statements being executed.
4
+ # it needs to be adapted to each new rails version
5
+
6
+ raise "AR abstract adapter monkey patch for custom benchmarking is not compatible with your rails version" unless %w(2.3.2 2.3.3 2.3.4 2.3.8 2.3.9 2.3.10).include?(Rails::VERSION::STRING)
7
+
8
+ module ActiveRecord
9
+ module ConnectionAdapters
10
+ class ConnectionPool
11
+ attr_reader :connections
12
+ end
13
+
14
+ class AbstractAdapter
15
+ attr_accessor :call_count, :query_cache_hits
16
+
17
+ def initialize(connection, logger = nil) #:nodoc:
18
+ @connection, @logger = connection, logger
19
+ @runtime = 0
20
+ @call_count = 0
21
+ @last_verification = 0
22
+ @query_cache_enabled = false
23
+ @query_cache_hits = 0
24
+ end
25
+
26
+ def reset_call_count
27
+ calls = @call_count
28
+ @call_count = 0
29
+ calls
30
+ end
31
+
32
+ def reset_query_cache_hits
33
+ hits = @query_cache_hits
34
+ @query_cache_hits = 0
35
+ hits
36
+ end
37
+
38
+ protected
39
+ def log(sql, name)
40
+ if block_given?
41
+ result = nil
42
+ seconds = Benchmark.realtime { result = yield }
43
+ @runtime += seconds
44
+ @call_count += 1
45
+ log_info(sql, name, seconds * 1000)
46
+ result
47
+ else
48
+ log_info(sql, name, 0)
49
+ nil
50
+ end
51
+ rescue Exception => e
52
+ # Log message and raise exception.
53
+ # Set last_verification to 0, so that connection gets verified
54
+ # upon reentering the request loop
55
+ @last_verification = 0
56
+ message = "#{e.class.name}: #{e.message}: #{sql}"
57
+ log_info(message, name, 0)
58
+ raise ActiveRecord::StatementInvalid, message
59
+ end
60
+ end
61
+
62
+ module QueryCache
63
+ private
64
+ def cache_sql(sql)
65
+ result =
66
+ if @query_cache.has_key?(sql)
67
+ @query_cache_hits += 1
68
+ log_info(sql, "CACHE", 0.0)
69
+ @query_cache[sql]
70
+ else
71
+ @query_cache[sql] = yield
72
+ end
73
+
74
+ if Array === result
75
+ result.collect { |row| row.dup }
76
+ else
77
+ result.duplicable? ? result.dup : result
78
+ end
79
+ rescue TypeError
80
+ result
81
+ end
82
+ end
83
+ end
84
+ end
85
+
@@ -0,0 +1,48 @@
1
+ # Add this line to your ApplicationController (app/controllers/application.rb)
2
+ # to enable logging for memcache-client:
3
+ # time_bandit MemCache
4
+
5
+ require 'memcache'
6
+ raise "MemCache needs to be loaded before monkey patching it" unless defined?(MemCache)
7
+
8
+ class MemCache
9
+ @@cache_latency = 0.0
10
+ @@cache_touches = 0
11
+ @@cache_misses = 0
12
+
13
+ def self.reset_benchmarks
14
+ @@cache_latency = 0.0
15
+ @@cache_touches = 0
16
+ @@cache_misses = 0
17
+ end
18
+
19
+ def self.get_benchmarks
20
+ [@@cache_latency, @@cache_touches, @@cache_misses]
21
+ end
22
+
23
+ def self.cache_runtime
24
+ sprintf "MC: %.3f(%dr,%dm)", @@cache_latency * 1000, @@cache_touches, @@cache_misses
25
+ end
26
+
27
+ def get_with_benchmark(key, raw = false)
28
+ val = nil
29
+ @@cache_latency += Benchmark.realtime{ val=get_without_benchmark(key, raw) }
30
+ @@cache_touches += 1
31
+ @@cache_misses += 1 if val.nil?
32
+ val
33
+ end
34
+ alias_method :get_without_benchmark, :get
35
+ alias_method :get, :get_with_benchmark
36
+
37
+ def get_multi_with_benchmark(*keys)
38
+ results = nil
39
+ @@cache_latency += Benchmark.realtime{ results=get_multi_without_benchmark(*keys) }
40
+ @@cache_touches += 1
41
+ @@cache_misses += keys.size - results.size
42
+ results
43
+ end
44
+ alias_method :get_multi_without_benchmark, :get_multi
45
+ alias_method :get_multi, :get_multi_with_benchmark
46
+
47
+ end
48
+
@@ -0,0 +1,55 @@
1
+ # Add this line to your ApplicationController (app/controllers/application_controller.rb)
2
+ # to enable logging for memcached:
3
+ # time_bandit TimeBandits::TimeConsumers::Memcached
4
+
5
+ require 'memcached'
6
+ raise "Memcached needs to be loaded before monkey patching it" unless defined?(Memcached)
7
+
8
+ class Memcached
9
+ @@cache_latency = 0.0
10
+ @@cache_touches = 0
11
+ @@cache_misses = 0
12
+
13
+ def self.reset_benchmarks
14
+ @@cache_latency = 0.0
15
+ @@cache_touches = 0
16
+ @@cache_misses = 0
17
+ end
18
+
19
+ def self.get_benchmarks
20
+ [@@cache_latency, @@cache_touches, @@cache_misses]
21
+ end
22
+
23
+ def self.cache_runtime
24
+ sprintf "MC: %.3f(%dr,%dm)", @@cache_latency * 1000, @@cache_touches, @@cache_misses
25
+ end
26
+
27
+ def get_with_benchmark(key, marshal = true)
28
+ @@cache_touches += 1
29
+ if key.is_a?(Array)
30
+ results = []
31
+ @@cache_latency += Benchmark.realtime do
32
+ begin
33
+ results = get_without_benchmark(key, marshal)
34
+ rescue Memcached::NotFound
35
+ end
36
+ end
37
+ @@cache_misses += key.size - results.size
38
+ results
39
+ else
40
+ val = nil
41
+ @@cache_latency += Benchmark.realtime do
42
+ begin
43
+ val = get_without_benchmark(key, marshal)
44
+ rescue Memcached::NotFound
45
+ end
46
+ end
47
+ @@cache_misses += 1 if val.nil?
48
+ val
49
+ end
50
+ end
51
+ alias_method :get_without_benchmark, :get
52
+ alias_method :get, :get_with_benchmark
53
+
54
+ end
55
+
@@ -0,0 +1,36 @@
1
+ require 'rails/rack/logger'
2
+
3
+ module Rails
4
+ module Rack
5
+ class Logger
6
+
7
+ def call(env)
8
+ Thread.current[:time_bandits_completed_info] = nil
9
+ start_time = before_dispatch(env)
10
+ result = @app.call(env)
11
+ ensure
12
+ run_time = Time.now - start_time
13
+ status = result.first
14
+ duration, additions = Thread.current[:time_bandits_completed_info]
15
+ (additions ||= []).insert(0, "Controller: %.1fms" % duration)
16
+
17
+ message = "Completed #{status} #{::Rack::Utils::HTTP_STATUS_CODES[status]} in %.1fms (#{additions.join(' | ')})" % (run_time*1000)
18
+ info message
19
+
20
+ after_dispatch(env)
21
+ end
22
+
23
+ protected
24
+ def before_dispatch(env)
25
+ start_time = Time.now
26
+ request = ActionDispatch::Request.new(env)
27
+ path = request.fullpath
28
+
29
+ info "\n\nStarted #{request.request_method} \"#{path}\" " \
30
+ "for #{request.ip} at #{start_time.to_default_s}"
31
+ start_time
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ module TimeBandits
2
+ class Railtie < Rails::Railtie
3
+
4
+ initializer "time_bandits" do
5
+ ActiveSupport.on_load(:action_controller) do
6
+ require 'time_bandits/monkey_patches/rails_rack_logger'
7
+ require 'time_bandits/monkey_patches/action_controller'
8
+ include ActionController::TimeBanditry
9
+ end
10
+
11
+ ActiveSupport.on_load(:active_record) do
12
+ require 'time_bandits/monkey_patches/activerecord_adapter'
13
+ TimeBandits.add TimeBandits::TimeConsumers::Database.instance
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,55 @@
1
+ # this consumer gets installed automatically by the plugin
2
+ # if this were not so
3
+ #
4
+ # time_bandit TimeBandits::TimeConsumers::Database.new
5
+ #
6
+ # would do the job
7
+
8
+ module TimeBandits
9
+ module TimeConsumers
10
+ # provide a time consumer interface to ActiveRecord for perform_action_with_benchmark and render_with_benchmark
11
+ class Database
12
+ def initialize
13
+ @consumed = 0.0
14
+ @call_count = 0
15
+ @query_cache_hits = 0
16
+ end
17
+ private :initialize
18
+
19
+ def self.instance
20
+ @instance ||= new
21
+ end
22
+
23
+ def reset
24
+ reset_stats
25
+ @call_count = 0
26
+ @consumed = 0.0
27
+ @query_cache_hits = 0
28
+ end
29
+
30
+ def consumed
31
+ hits, calls, time = reset_stats
32
+ @query_cache_hits += hits
33
+ @call_count += calls
34
+ @consumed += time
35
+ end
36
+
37
+ def runtime
38
+ sprintf "DB: %.3f(%d,%d)", @consumed * 1000, @call_count, @query_cache_hits
39
+ end
40
+
41
+ private
42
+ def all_connections
43
+ ActiveRecord::Base.connection_handler.connection_pools.values.map{|pool| pool.connections}.flatten
44
+ end
45
+
46
+ def reset_stats
47
+ connections = all_connections
48
+ hits = connections.map{|c| c.reset_query_cache_hits}.sum
49
+ calls = connections.map{|c| c.reset_call_count}.sum
50
+ time = connections.map{|c| c.reset_runtime}.sum
51
+ [hits, calls, time]
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,94 @@
1
+ # a time consumer implementation for garbage collection
2
+ module TimeBandits
3
+ module TimeConsumers
4
+ class GarbageCollection
5
+ @@heap_dumps_enabled = false
6
+ def self.heap_dumps_enabled=(v)
7
+ @@heap_dumps_enabled = v
8
+ end
9
+
10
+ def initialize
11
+ GC.enable_stats
12
+ reset
13
+ end
14
+ private :initialize
15
+
16
+ def self.instance
17
+ @instance ||= new
18
+ end
19
+
20
+ if GC.respond_to? :heap_slots
21
+
22
+ def reset
23
+ @consumed = GC.time
24
+ @collections = GC.collections
25
+ @allocated_objects = ObjectSpace.allocated_objects
26
+ @allocated_size = GC.allocated_size
27
+ @heap_slots = GC.heap_slots
28
+ end
29
+
30
+ else
31
+
32
+ def reset
33
+ @consumed = GC.time
34
+ @collections = GC.collections
35
+ end
36
+
37
+ end
38
+
39
+ def consumed
40
+ 0.0
41
+ end
42
+
43
+ def consumed_gc_time
44
+ (GC.time - @consumed).to_f / 1_000_000
45
+ end
46
+
47
+ def collections
48
+ GC.collections - @collections
49
+ end
50
+
51
+ if GC.respond_to? :heap_slots
52
+
53
+ def allocated_objects
54
+ ObjectSpace.allocated_objects - @allocated_objects
55
+ end
56
+
57
+ def allocated_size
58
+ GC.allocated_size - @allocated_size
59
+ end
60
+
61
+ def heap_growth
62
+ GC.heap_slots - @heap_slots
63
+ end
64
+
65
+ if GC.respond_to? :heap_slots_live_after_last_gc
66
+ def live_data_set_size
67
+ GC.heap_slots_live_after_last_gc
68
+ end
69
+ else
70
+ def live_data_set_size
71
+ 0
72
+ end
73
+ end
74
+
75
+ def runtime
76
+ heap_slots = GC.heap_slots
77
+ heap_growth = self.heap_growth
78
+ allocated_objects = self.allocated_objects
79
+ allocated_size = self.allocated_size
80
+ GCHacks.heap_dump if heap_growth > 0 && @@heap_dumps_enabled
81
+ "GC: %.3f(%d) | HP: %d(%d,%d,%d,%d)" %
82
+ [consumed_gc_time * 1000, collections, heap_growth, heap_slots, allocated_objects, allocated_size, live_data_set_size]
83
+ end
84
+
85
+ else
86
+
87
+ def runtime
88
+ "GC: %.3f(%d)" % [consumed_gc_time * 1000, collections]
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,77 @@
1
+ # a time consumer implementation for jruby, using jxm
2
+ #
3
+ # the gc counts and times reported are summed over all the garbage collectors
4
+ # heap_growth reflects changes in the committed size of the java heap
5
+ # heap_size is the committed size of the java heap
6
+ # allocated_size reflects changes in the active (used) part of the java heap
7
+ # java non-heap memory is not reported
8
+
9
+ module TimeBandits
10
+ module TimeConsumers
11
+ class JMX
12
+ def initialize
13
+ @server = ::JMX::MBeanServer.new
14
+ @memory_bean = @server["java.lang:type=Memory"]
15
+ @collectors = @server.query_names "java.lang:type=GarbageCollector,*"
16
+ reset
17
+ end
18
+ private :initialize
19
+
20
+ def self.instance
21
+ @instance ||= new
22
+ end
23
+
24
+ def consumed
25
+ 0.0
26
+ end
27
+
28
+ def gc_time
29
+ @collectors.to_array.map {|gc| @server[gc].collection_time}.sum
30
+ end
31
+
32
+ def gc_collections
33
+ @collectors.to_array.map {|gc| @server[gc].collection_count}.sum
34
+ end
35
+
36
+ def heap_size
37
+ @memory_bean.heap_memory_usage.committed
38
+ end
39
+
40
+ def heap_usage
41
+ @memory_bean.heap_memory_usage.used
42
+ end
43
+
44
+ def reset
45
+ @consumed = gc_time
46
+ @collections = gc_collections
47
+ @heap_committed = heap_size
48
+ @heap_used = heap_usage
49
+ end
50
+
51
+ def collections_delta
52
+ gc_collections - @collections
53
+ end
54
+
55
+ def gc_time_delta
56
+ (gc_time - @consumed).to_f
57
+ end
58
+
59
+ def heap_growth
60
+ heap_size - @heap_committed
61
+ end
62
+
63
+ def usage_growth
64
+ heap_usage - @heap_used
65
+ end
66
+
67
+ def allocated_objects
68
+ 0
69
+ end
70
+
71
+ def runtime
72
+ "GC: %.3f(%d), HP: %d(%d,%d,%d)" % [gc_time_delta, collections_delta, heap_growth, heap_size, allocated_objects, usage_growth]
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,25 @@
1
+ # a time consumer implementation for memchache
2
+ # install into application_controller.rb with the line
3
+ #
4
+ # time_bandit TimeBandits::TimeConsumers::MemCache
5
+ #
6
+ require 'time_bandits/monkey_patches/memcache-client'
7
+ module TimeBandits
8
+ module TimeConsumers
9
+ class MemCache
10
+ class << self
11
+ def reset
12
+ ::MemCache.reset_benchmarks
13
+ end
14
+
15
+ def consumed
16
+ ::MemCache.get_benchmarks.first
17
+ end
18
+
19
+ def runtime
20
+ ::MemCache.cache_runtime
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # a time consumer implementation for memchached
2
+ # install into application_controller.rb with the line
3
+ #
4
+ # time_bandit TimeBandits::TimeConsumers::Memcached
5
+ #
6
+ require 'time_bandits/monkey_patches/memcached'
7
+ module TimeBandits
8
+ module TimeConsumers
9
+ class Memcached
10
+ class << self
11
+ def reset
12
+ ::Memcached.reset_benchmarks
13
+ end
14
+
15
+ def consumed
16
+ ::Memcached.get_benchmarks.first
17
+ end
18
+
19
+ def runtime
20
+ ::Memcached.cache_runtime
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module TimeBandits
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "time_bandits/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "time_bandits"
7
+ s.version = TimeBandits::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Stefan Kaes"]
10
+ s.email = ["skaes@railsexpress.de"]
11
+ s.homepage = "https://github.com/skaes/time_bandits"
12
+ s.summary = %q{Custom performance logging for Rails}
13
+ s.description = %q{Enables customizable performance logging for Rails applications}
14
+
15
+ s.rubyforge_project = "time_bandits"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency("activesupport", ["~> 3.0"])
23
+ end
24
+
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: time_bandits
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Stefan Kaes
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-29 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ version: "3.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: Enables customizable performance logging for Rails applications
37
+ email:
38
+ - skaes@railsexpress.de
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - Gemfile
48
+ - README.rdoc
49
+ - Rakefile
50
+ - lib/time_bandits.rb
51
+ - lib/time_bandits/monkey_patches/action_controller.rb
52
+ - lib/time_bandits/monkey_patches/activerecord_adapter.rb
53
+ - lib/time_bandits/monkey_patches/memcache-client.rb
54
+ - lib/time_bandits/monkey_patches/memcached.rb
55
+ - lib/time_bandits/monkey_patches/rails_rack_logger.rb
56
+ - lib/time_bandits/railtie.rb
57
+ - lib/time_bandits/time_consumers/database.rb
58
+ - lib/time_bandits/time_consumers/garbage_collection.rb
59
+ - lib/time_bandits/time_consumers/jmx.rb
60
+ - lib/time_bandits/time_consumers/mem_cache.rb
61
+ - lib/time_bandits/time_consumers/memcached.rb
62
+ - lib/time_bandits/version.rb
63
+ - time_bandits.gemspec
64
+ has_rdoc: true
65
+ homepage: https://github.com/skaes/time_bandits
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project: time_bandits
94
+ rubygems_version: 1.3.7
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Custom performance logging for Rails
98
+ test_files: []
99
+