revolutionhealth-metrics 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007 Revolution Health Group LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,71 @@
1
+ == Introduction
2
+
3
+ This gem provides a metrics collecting for controllers, database queries,
4
+ and specific blocks of code or methods. It is designed to be light-weight
5
+ and have minimal impact on production builds while providing preformance
6
+ indicators of the running application.
7
+
8
+ == Disclaimer
9
+
10
+
11
+ This software is released to be used at your own risk.
12
+ For feedback please drop us a line at rails-trunk [ at ] revolution DOT com.
13
+
14
+ Using this plugin should not be your first step in application
15
+ optimization/scaling or even the second one.
16
+
17
+ == Example
18
+
19
+ class SomeClassToTest
20
+ collect_metrics_on :my_method
21
+
22
+ def my_method(blah = nil)
23
+ true
24
+ end
25
+ end
26
+
27
+ for more samples and test cases see: test/metrics_test.rb
28
+
29
+ === Usage
30
+
31
+ The metrics are written to: logs/<environment>_metrics.log
32
+
33
+ Configuration can be updated in: metrics/config/metrics.yml, you may
34
+ copy this file to your RAILS_ROOT/config/metrics.yml and customize for
35
+ your application, the RAILS_ROOT will be checked first.
36
+
37
+
38
+
39
+ === Sample Output
40
+
41
+ [ERROR] [2007-06-21 23:21:19] [trunk] [Metrics]|[76716]|[MysqlAdapter.log]|0.012727|args=["root localhost trunk_test", "CREATE DATABASE `trunk_test`"]
42
+
43
+ [ERROR] [2007-06-21 23:19:56] [trunk] [Metrics]|[35158]|[Request to [Test::SomeControllerWithMetricsId]]|0.001373|action = index|path = /some?
44
+
45
+ [ERROR] [2007-06-21 23:19:56] [trunk] [Metrics]|[33676]|[SomeClassToUseModuleMixin.another_method]|0.000020|args=["also"]
46
+
47
+ === Controlling Output
48
+
49
+ By setting the constant METRICS_LOGGER in your <RAILS_ROOT>/config/environment.rb to either a specific Logger or Log4r instance, otherwise the RAILS_DEFAULT_LOGGER will be used.
50
+
51
+
52
+
53
+
54
+ == Installation
55
+
56
+ sudo gem install revolutionhealth-metrics -s http://gems.github.com
57
+
58
+ == Source
59
+
60
+ http://github.com/revolutionhealth/metrics/tree/master
61
+
62
+ == License
63
+
64
+ metrics is released under the MIT license.
65
+
66
+
67
+ == Support
68
+
69
+ The plugin RubyForge page is http://rubyforge.org/projects/metrics
70
+
71
+
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+
6
+ GEM = "metrics"
7
+ GEM_VERSION = "0.0.9"
8
+ AUTHOR = "Revolution Health"
9
+ EMAIL = "rails-trunk@revolutionhealth.com"
10
+ HOMEPAGE = %q{http://github.com/revolutionhealth/metrics}
11
+ SUMMARY = "metrics allows one to track the performance of particular controllers, database calls, and other methods"
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = GEM
15
+ s.version = GEM_VERSION
16
+ s.platform = Gem::Platform::RUBY
17
+ s.has_rdoc = false
18
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.author = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+
25
+ # Uncomment this to add a dependency
26
+ # s.add_dependency "foo"
27
+
28
+ s.require_path = 'lib'
29
+ s.autorequire = GEM
30
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs,test,config}/**/*") + ['init.rb']
31
+ end
32
+
33
+ Rake::GemPackageTask.new(spec) do |pkg|
34
+ pkg.gem_spec = spec
35
+ end
36
+
37
+ desc "install the gem locally"
38
+ task :install => [:package] do
39
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
40
+ end
41
+
42
+ desc "create a gemspec file"
43
+ task :make_spec do
44
+ File.open("#{GEM}.gemspec", "w") do |file|
45
+ file.puts spec.to_ruby
46
+ end
47
+ end
48
+
49
+ require 'test/unit'
50
+
51
+ task :test do
52
+ runner = Test::Unit::AutoRunner.new(true)
53
+ runner.to_run << 'test'
54
+ runner.pattern = [/_test.rb$/]
55
+ exit if !runner.run
56
+ end
57
+
58
+ task :default => [:test, :package] do
59
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/<%= name %>.rb
@@ -0,0 +1,13 @@
1
+ ---
2
+ production:
3
+ min_real_time_threshold: 1.0
4
+ single_line_output: true
5
+
6
+ test:
7
+ min_real_time_threshold: 2.0
8
+ single_line_output: false
9
+
10
+ development:
11
+ min_real_time_threshold: 0.0
12
+ single_line_output: false
13
+ care_providers/search_controller: 0.0
data/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ require 'metrics'
4
+
@@ -0,0 +1,20 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ class Metrics::Collector
4
+ def begin_metric()
5
+ @metric_begin_measurement = Process.times
6
+ @metric_begin_measurement_time = Time.now
7
+ end
8
+
9
+ def end_metric(metric_label)
10
+ end_metric_measurement = Process.times
11
+ end_metric_measurement_time = Time.now
12
+
13
+ result = Benchmark::Tms.new(end_metric_measurement.utime - @metric_begin_measurement.utime,
14
+ end_metric_measurement.stime - @metric_begin_measurement.stime,
15
+ end_metric_measurement.cutime - @metric_begin_measurement.cutime,
16
+ end_metric_measurement.cstime - @metric_begin_measurement.cstime,
17
+ end_metric_measurement_time.to_f - @metric_begin_measurement_time.to_f,
18
+ metric_label)
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ require 'singleton'
4
+
5
+ module Metrics
6
+ class Config
7
+ include Singleton
8
+
9
+ def initialize
10
+ default_values = { :min_real_time_threshold => 0.1,
11
+ :log_delimiter => "|",
12
+ :enhanced_active_record_metrics => false,
13
+ :single_line_output => false,
14
+ :metrics_tracking_id => true }
15
+
16
+ @cfg = default_values.merge(cfg)
17
+ end
18
+
19
+ def self.[](key)
20
+ Metrics::Config.instance.cfg[key]
21
+ end
22
+
23
+ def self.[]=(key, value)
24
+ Metrics::Config.instance.cfg[key] = value
25
+ end
26
+
27
+
28
+ def cfg
29
+ @cfg ||= load_config
30
+ end
31
+
32
+ private
33
+
34
+ def load_config
35
+ loaded_config = {}
36
+ if defined? ConfigLoader
37
+ loaded_config = ConfigLoader.load_section('metrics.yml')
38
+ else
39
+ config = ""
40
+ config = File.join(RAILS_ROOT, 'config/metrics.yml') if defined?(RAILS_ROOT)
41
+ config = File.join(File.dirname(__FILE__), '../../config/metrics.yml') if not File.exist?(config)
42
+ File.open( config ) { |yf| loaded_config = YAML.load(yf) }
43
+ if defined?(RAILS_ENV)
44
+ loaded_config = loaded_config[RAILS_ENV] || {}
45
+ else
46
+ loaded_config = {}
47
+ end
48
+ end
49
+ loaded_config.symbolize_keys!
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module Metrics
3
+ module Logger
4
+ extend self
5
+
6
+ def enabled?
7
+ METRICS_LOGGER.error?
8
+ end
9
+
10
+ def log(msg)
11
+ METRICS_LOGGER.error(msg)
12
+ end
13
+
14
+ end
15
+ end
data/lib/metrics.rb ADDED
@@ -0,0 +1,128 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+ require 'metrics/config'
3
+ require 'metrics/collector'
4
+ require 'benchmark'
5
+
6
+ if not defined?(METRICS_LOGGER)
7
+ if defined?(RAILS_DEFAULT_LOGGER)
8
+ METRICS_LOGGER = RAILS_DEFAULT_LOGGER
9
+ METRICS_LOGGER.warn("METRICS_LOGGER is using RAILS_DEFAULT_LOGGER") if METRICS_LOGGER.warn?
10
+ else
11
+ require 'logger'
12
+ METRICS_LOGGER = Logger.new(STDOUT)
13
+ end
14
+ end
15
+ require 'metrics/logger'
16
+
17
+ module Metrics
18
+ extend self
19
+
20
+ def collect_metrics(label = nil, *args)
21
+ reset_metrics_id = false
22
+ collector = nil
23
+ if Metrics::Logger.enabled?
24
+ @@_metrics_id ||= nil
25
+ if @@_metrics_id.nil?
26
+ reset_metrics_id = true
27
+ @@_metrics_id = rand(99999)
28
+ end
29
+ collector = Metrics::Collector.new
30
+ collector.begin_metric()
31
+ end
32
+
33
+ result = yield
34
+
35
+ log_metrics(collector.end_metric(label || metric_label), args) if Metrics::Logger.enabled?
36
+ @@_metrics_id = nil if reset_metrics_id
37
+ result
38
+ end
39
+
40
+ protected
41
+ def disable_metrics(disable = true)
42
+ if disable && !respond_to?(:orig_begin_metric)
43
+ alias :orig_end_metric :end_metric
44
+ alias :end_metric :disabled_metric
45
+ alias :orig_begin_metric :begin_metric
46
+ alias :begin_metric :disabled_metric
47
+ elsif !disable && respond_to?(:orig_begin_metric)
48
+ alias :end_metric :orig_end_metric
49
+ alias :begin_metric :orig_begin_metric
50
+ end
51
+ end
52
+
53
+ private
54
+ def begin_metric()
55
+ if Metrics::Logger.enabled?
56
+ @@_metrics_id = rand(99999)
57
+ @collector = Metrics::Collector.new
58
+ @collector.begin_metric() if @collector != nil
59
+ end
60
+ end
61
+
62
+ def end_metric()
63
+ if Metrics::Logger.enabled? and @collector != nil
64
+ result = @collector.end_metric(metric_label)
65
+ log_metrics(result)
66
+ end
67
+ end
68
+
69
+
70
+ METRICS_CAPTION = Benchmark::Tms::CAPTION.delete("\n")
71
+ METRICS_FMTSTR = "%10.6r"
72
+ METRICS_LABEL = "[Metrics]"
73
+
74
+ def log_metrics(result, *args)
75
+ threshold = Metrics::Config[self.class.name.underscore.to_sym] rescue Metrics::Config[:min_real_time_threshold]
76
+ threshold ||= Metrics::Config[:min_real_time_threshold]
77
+
78
+ if result != nil && (result.real > threshold)
79
+ if Metrics::Config[:single_line_output]
80
+ delimiter = Metrics::Config[:log_delimiter]
81
+ output = METRICS_LABEL
82
+ output += delimiter + "[#{@@_metrics_id}]" if Metrics::Config[:metrics_tracking_id]
83
+ output += delimiter + "[#{result.label}]"
84
+ output += delimiter + real_time(result).strip
85
+ output += delimiter + controller_args if respond_to?(:controller_name)
86
+ output += delimiter + "args=#{args[0].inspect}" if (args != nil) and (args.size > 0)
87
+ Metrics::Logger.log(output)
88
+ else
89
+ Metrics::Logger.log("#{METRICS_LABEL} #{result.label}")
90
+ Metrics::Logger.log("#{METRICS_LABEL} Metrics Id=#{@@_metrics_id}") if Metrics::Config[:metrics_tracking_id]
91
+ Metrics::Logger.log("#{METRICS_LABEL} args=#{args[0].inspect}") if (args != nil) and (args.size > 0)
92
+ Metrics::Logger.log("#{METRICS_LABEL} #{METRICS_CAPTION}")
93
+ result_str = result.to_s.delete("\n")
94
+ Metrics::Logger.log("#{METRICS_LABEL} #{result_str}")
95
+ end
96
+ end
97
+ end
98
+
99
+ def real_time(result)
100
+ METRICS_FMTSTR.gsub(/(%[-+\.\d]*)r/){"#{$1}f" % result.real}
101
+ end
102
+
103
+ def metric_label
104
+ if respond_to?(:controller_name)
105
+ action = action_name
106
+ label = "Request to [#{self.class.name}]"
107
+ else
108
+ label = "#{self.class.name}"
109
+ end
110
+ end
111
+
112
+ def controller_args
113
+ "action = #{action_name }" + Metrics::Config[:log_delimiter] + "path = #{request.path}?#{request.env['QUERY_STRING']}"
114
+ end
115
+
116
+ def self.included(klass)
117
+ klass.send(:extend, Metrics)
118
+ end
119
+
120
+ def disabled_metric
121
+ end
122
+ end
123
+
124
+ require 'rails/controller_metrics'
125
+ require 'ruby/metric_extensions'
126
+ require 'rails/activerecord_enhanced_metrics'
127
+ require 'ruby/http_metrics'
128
+
@@ -0,0 +1,27 @@
1
+
2
+ if defined?(RAILS_ROOT)
3
+ class ActiveRecord::ConnectionAdapters::AbstractAdapter
4
+
5
+
6
+ protected
7
+ alias_method :non_metrics_log, :log
8
+ def log(sql, name, &block)
9
+ if @config
10
+ host = @config[:host].sub(/\..*/, '') if @config[:host]
11
+ host = @config[:host] if host.nil? || !host.scan(/^\d+$/).empty?
12
+ connection_info = "#{@config[:username]} #{host} #{@config[:database]}"
13
+ else
14
+ connection_info = "localhost"
15
+ end
16
+ label = "#{self.class.name.sub(/.*\:\:/, '')}.log"
17
+ result = nil
18
+ Metrics.collect_metrics(label, connection_info ||= "no db config", sql) do
19
+ result = non_metrics_log(sql, name, &block)
20
+ end
21
+ result
22
+ end
23
+ end
24
+ end
25
+
26
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
27
+
@@ -0,0 +1,13 @@
1
+
2
+ module Metrics::ActiveRecordMetrics
3
+ def self.append_features(klass)
4
+ super
5
+ klass.collect_metrics_on(:log)
6
+ end
7
+
8
+ end
9
+
10
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Metrics::ActiveRecordMetrics
11
+
12
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
13
+
@@ -0,0 +1,15 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ if defined?(RAILS_ROOT)
4
+ module ActionController
5
+ class Base
6
+ include Metrics
7
+
8
+ prepend_before_filter :begin_metric
9
+ append_after_filter :end_metric
10
+
11
+
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+ require 'net/http'
3
+
4
+ module Net
5
+ class HTTPGenericRequest
6
+ alias_method :__non_metrics_exec, :exec
7
+ def exec(sock, ver, path, &block)
8
+ Metrics.collect_metrics("#{self.class.name}.exec", "HTTP/#{ver}", "path= #{path}") do
9
+ __non_metrics_exec(sock, ver, path, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ class Module
4
+ def collect_metrics_on(*syms)
5
+ syms.flatten.each do |sym|
6
+ interpose = lambda do |sym|
7
+ alias_method "__metrics_#{sym}__".to_sym, sym
8
+ protected "__metrics_#{sym}__".to_sym
9
+ class_eval <<-EOS
10
+ def #{sym}(*args, &block)
11
+ result = nil
12
+ Metrics.collect_metrics("#{self.name}.#{sym}", *args) do
13
+ result = __metrics_#{sym}__(*args, &block)
14
+ end
15
+ result
16
+ end
17
+ EOS
18
+ end
19
+
20
+ if method_defined? sym and (!method_defined?("__metrics_#{sym}__".to_sym))
21
+ class_eval { interpose.call(sym) }
22
+ else
23
+ _metrics_interpose[sym.to_sym] = interpose
24
+ end
25
+ end
26
+
27
+ if not singleton_methods(false).include?('method_added')
28
+ instance_eval do
29
+ def method_added(method_sym)
30
+ if interpose = _metrics_interpose[method_sym]
31
+ _metrics_interpose.delete method_sym
32
+ class_eval { interpose.call(method_sym) }
33
+ end
34
+ super
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def _metrics_interpose
41
+ @metrics_interpose ||= {}
42
+ end
43
+ end
44
+
@@ -0,0 +1,527 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
2
+ RAILS_ENV='test'
3
+ RAILS_ROOT=File.expand_path(File.join(File.dirname(__FILE__), '..'))
4
+ require 'rubygems'
5
+ require 'actionpack'
6
+ require 'action_controller'
7
+ require 'action_controller/test_process'
8
+ require 'active_record'
9
+
10
+ require 'metrics'
11
+ require File.dirname(__FILE__) + '/metrics_test_class'
12
+ require 'resolv'
13
+ require 'ipaddr'
14
+
15
+ class SomeClassToTest
16
+ collect_metrics_on :my_method
17
+
18
+ def my_method(blah = nil)
19
+ print "blah = #{blah}\n" if blah != nil
20
+ true
21
+ end
22
+
23
+ def my_non_metric_method(blah = nil)
24
+ print "blah = #{blah}\n" if blah != nil
25
+ true
26
+ end
27
+ end
28
+
29
+ class SomeClassToTestWithoutCollection
30
+
31
+ def my_method(blah = nil)
32
+ print "blah = #{blah}\n" if blah != nil
33
+ true
34
+ end
35
+
36
+ def my_non_metric_method(blah = nil)
37
+ print "blah = #{blah}\n" if blah != nil
38
+ true
39
+ end
40
+ end
41
+
42
+ module SomeModuleToTest
43
+ collect_metrics_on :the_method
44
+ def the_method(blah)
45
+ print "in the_method(#{blah})\n"
46
+ true
47
+ end
48
+
49
+ def another_method(blah)
50
+ print "in another_method(#{blah})\n"
51
+ true
52
+ end
53
+ end
54
+
55
+ class SomeClassToUseModuleMixin
56
+ include SomeModuleToTest
57
+ collect_metrics_on :another_method
58
+ end
59
+
60
+ class SomeController < ActionController::Base
61
+ def index
62
+ print "!!!!!!!!!!!!!! HERE\n"
63
+ render :text => "hello world"
64
+ end
65
+ end
66
+
67
+ class Test::SomeControllerThreshold < ActionController::Base
68
+ def index
69
+ print "!!!!!!!!!!!!!! HERE\n"
70
+ render :text => "hello world"
71
+ end
72
+ end
73
+
74
+ class Test::SomeControllerWithMetricsId < ActionController::Base
75
+ def index
76
+ Metrics.collect_metrics { print "!!!!!!!!!!!!!! HERE\n" }
77
+ render :text => "hello world"
78
+ end
79
+ end
80
+
81
+ class MockSocket < StringIO
82
+ def readline; "HTTP 200 OK"; end
83
+ def readuntil(a, b); ""; end
84
+ def read_all(a); ""; end
85
+ end
86
+
87
+ class MetricsTest < Test::Unit::TestCase
88
+ def setup
89
+ ActiveRecord::Base.configurations = {'test' => {'adapter' => "sqlite3", "dbfile" => ":memory:"}}
90
+ Metrics::Config[:min_real_time_threshold] = 0.0 # artifically lower the threshold so we catch everything for our tests
91
+ start_logging()
92
+ end
93
+
94
+ def teardown
95
+ stop_logging()
96
+ end
97
+
98
+ def test_http_metrics_log
99
+ http = Net::HTTP.new("www.revolutionhealth.com", "80")
100
+ http_output = MockSocket.new
101
+ http_output.print "empty\nasdf\n\n"
102
+ http_output.rewind
103
+ http.instance_eval { @socket = http_output; @started = true }
104
+
105
+
106
+ http.request_get("/test", { 'accept' => "text/plain"} )
107
+ assert output.string =~ /.*Metrics.*Net::HTTP::Get.exec.*test/
108
+ output.string.gsub!(/.*/, '')
109
+
110
+ http.request_post("/test", "body", { 'accept' => "text/plain"} )
111
+ assert output.string =~ /.*Metrics.*Net::HTTP::Post.exec.*test/
112
+ output.string.gsub!(/.*/, '')
113
+
114
+
115
+ http.send(:post, "/test", "body", { 'accept' => "text/plain"} )
116
+ assert output.string =~ /.*Metrics.*Net::HTTP::Post.exec.*test/
117
+ output.string.gsub!(/.*/, '')
118
+
119
+ end
120
+
121
+ def test_metrics_log_capture
122
+ METRICS_LOGGER.error { "BLAH" }
123
+ assert output.string =~ /.*BLAH\n/
124
+ end
125
+
126
+ def test_metrics_config
127
+ default = Metrics::Config[:min_real_time_threshold]
128
+ Metrics::Config[:min_real_time_threshold] = 0.5
129
+ assert_equal 0.5, Metrics::Config[:min_real_time_threshold]
130
+ assert_equal Metrics::Config[:min_real_time_threshold], Metrics::Config.instance.cfg[:min_real_time_threshold]
131
+ Metrics::Config[:min_real_time_threshold] = default
132
+
133
+ assert_equal "|", Metrics::Config[:log_delimiter]
134
+ end
135
+
136
+ def test_class_threshold
137
+ test_controller = Test::SomeControllerThreshold.new
138
+ test_request = ActionController::TestRequest.new
139
+ test_request.path = '/some'
140
+ test_request.action = 'index'
141
+
142
+ original_threshold = Metrics::Config[:min_real_time_threshold]
143
+ Metrics::Config[:min_real_time_threshold] = 2.0 # adjust it
144
+ begin
145
+ response = test_controller.process_test(test_request)
146
+ ensure
147
+ Metrics::Config[:min_real_time_threshold] = original_threshold
148
+ end
149
+
150
+ assert_equal response.body, "hello world"
151
+ assert_nil output.string =~ /\[Metrics\]/
152
+ output.string.gsub!(/.*/, '')
153
+ end
154
+
155
+
156
+ def test_metrics_id
157
+ test_controller = Test::SomeControllerWithMetricsId.new
158
+ test_request = ActionController::TestRequest.new
159
+ test_request.path = '/some'
160
+ test_request.action = 'index'
161
+ response = test_controller.process_test(test_request)
162
+ assert_equal response.body, "hello world"
163
+
164
+ test1 = output.string.scan(/.*\[Metrics\]\|\[(\d*)\]/).flatten
165
+
166
+ assert_equal 2, test1.size
167
+ assert_equal test1[0], test1[1]
168
+
169
+
170
+ output.string.gsub!(/.*/, '')
171
+ test_controller = SomeController.new
172
+ response = test_controller.process_test(test_request)
173
+ assert_equal response.body, "hello world"
174
+
175
+ test2 = output.string.scan(/.*\[Metrics\]\|\[(\d*)\]/).flatten
176
+ assert_equal 1, test2.size
177
+ assert_not_nil test2[0]
178
+
179
+ assert_not_equal test1[0], test2[0]
180
+
181
+ output.string.gsub!(/.*/, '')
182
+ end
183
+
184
+
185
+ def test_ar_enhanced_metrics
186
+ assert output.string.empty?
187
+ ActiveRecord::Base.establish_connection
188
+ not_nil_checker = nil
189
+
190
+ ActiveRecord::Base.connection.instance_eval <<-EOS
191
+ log("select count(1);", "test") { not_nil_checker = true }
192
+ EOS
193
+ assert_equal false, output.string.empty?
194
+ output.string.gsub!(/.*/, '')
195
+
196
+ ActiveRecord::Base.connection.instance_eval <<-EOS
197
+ log("select count(1);", "test")
198
+ EOS
199
+ assert_equal false, output.string.empty?
200
+
201
+ assert_not_nil not_nil_checker
202
+ output.string.gsub!(/.*/, '')
203
+
204
+ ar_conf = ActiveRecord::Base.configurations['test'].merge({'host' => 'localhost.revolutionhealth.com',
205
+ 'username' => 'none', 'database' => 'test'})
206
+ ar_conf.symbolize_keys!
207
+ ActiveRecord::Base.connection.instance_eval { @config = ar_conf if @config.nil? }
208
+ ActiveRecord::Base.connection.execute("select count(1);")
209
+
210
+ print output.string + "\n\n"
211
+ assert_equal false, output.string.blank?
212
+ config = {'adapter' => "sqlite3",
213
+ 'host' => 'localhost.revolutionhealth.com',
214
+ 'username' => 'none', 'database' => 'test'
215
+ }
216
+ config.symbolize_keys!
217
+
218
+ host = config[:host].sub(/\..*/, '')
219
+ assert_match /.*args\=\[\"#{config[:username]} #{host} #{config[:database]}\"\, \"select count\(1\)\;\"\].*/, output.string
220
+
221
+
222
+ output.string.gsub!(/.*/, '')
223
+
224
+ host_ip = nil
225
+ Resolv.getaddresses(config[:host]).each { |x| host_ip = x if IPAddr.new(x).ipv4? }
226
+
227
+ if host_ip != nil
228
+ config[:host] = host_ip
229
+ ActiveRecord::Base.connection.instance_variable_set("@config", config)
230
+ ActiveRecord::Base.connection.execute("select count(1);")
231
+
232
+ print output.string
233
+ print "\n\n"
234
+ assert_equal false, output.string.blank?
235
+ config = ActiveRecord::Base.connection.instance_variable_get("@config")
236
+
237
+ host = config[:host].sub(/\..*/, '')
238
+ host = config[:host] if not host.scan(/\d+/).empty?
239
+ assert_match /.*args\=\[\"#{config[:username]} #{host} #{config[:database]}\"\, \"select count\(1\)\;\"\].*/, output.string
240
+ end
241
+
242
+ output.string.gsub!(/.*/, '')
243
+
244
+
245
+
246
+ ActiveRecord::Base.connection.instance_eval <<-EOS
247
+ def execute(sql, name = nil, retries = 2) #:nodoc:
248
+ log(sql, name) { sleep(2) }
249
+ rescue ActiveRecord::StatementInvalid => exception
250
+ if exception.message.split(":").first =~ /Packets out of order/
251
+ raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
252
+ else
253
+ raise
254
+ end
255
+ end
256
+ EOS
257
+
258
+ ActiveRecord::Base.connection.execute("SLEEP TEST")
259
+ assert_equal false, output.string.empty?
260
+ end
261
+
262
+ def test_metrics_collection2
263
+ tmp = RHG::MetricsTestClass.new.my_method("hi")
264
+ assert_equal true, tmp
265
+ assert SomeClassToTest.method_defined?(:__metrics_my_method__)
266
+
267
+ test_obj = RHG::MetricsTestClass.new
268
+ tmp2 = test_obj.my_method("hi")
269
+ assert_equal true, tmp2
270
+ assert SomeClassToTest.method_defined?(:__metrics_my_method__)
271
+
272
+ tmp3 = test_obj.my_method("hi")
273
+ assert_equal true, tmp3
274
+ assert SomeClassToTest.method_defined?(:__metrics_my_method__)
275
+ end
276
+
277
+ def test_metrics_collection
278
+ tmp = SomeClassToTest.new.my_method("hi")
279
+ assert_equal true, tmp
280
+ assert SomeClassToTest.method_defined?(:__metrics_my_method__)
281
+ end
282
+
283
+ def test_explicit_collection
284
+ assert_equal "123", collect_result_test()
285
+ assert_equal "321", collect_result_test(false)
286
+ end
287
+
288
+ def test_module_metrics
289
+ tmp = Object.new.extend(SomeModuleToTest)
290
+ result = tmp.the_method("here")
291
+ assert_equal true, result
292
+ assert SomeModuleToTest.method_defined?(:__metrics_the_method__)
293
+
294
+ tmp2 = SomeClassToUseModuleMixin.new
295
+ assert_equal true, tmp2.the_method("here")
296
+ assert_equal true, tmp2.another_method("also")
297
+ assert SomeClassToUseModuleMixin.method_defined?(:__metrics_the_method__)
298
+ assert SomeClassToUseModuleMixin.method_defined?(:__metrics_another_method__)
299
+
300
+ end
301
+
302
+ def test_an_output
303
+ some_class_instance = SomeClassToTest.new
304
+ some_class_instance.my_method
305
+ some_class_instance.my_method("HI")
306
+ collect_result_test()
307
+ collect_result_test2()
308
+
309
+ METRICS_LOGGER.error("--------------- END TEST 1 -------------\n")
310
+
311
+ Metrics::Config[:single_line_output] = true
312
+
313
+ some_class_instance = SomeClassToTest.new
314
+ some_class_instance.my_method
315
+ some_class_instance.my_method("THAR")
316
+ collect_result_test()
317
+ collect_result_test2()
318
+
319
+ test_controller = SomeController.new
320
+ test_request = ActionController::TestRequest.new
321
+ test_request.path = '/some'
322
+ test_request.action = 'index'
323
+ response = test_controller.process_test(test_request)
324
+ #assert response.body == "hello world"
325
+ METRICS_LOGGER.error("--------------- END TEST 2 -------------\n")
326
+
327
+
328
+ print output.string
329
+ print "\n\n"
330
+ assert_equal false, output.string.blank?
331
+
332
+ output.string.gsub!(/.*/, '')
333
+
334
+ old_level = METRICS_LOGGER.level
335
+ METRICS_LOGGER.level = fatal_level
336
+ collect_result_test2()
337
+ assert_equal true, output.string.blank?
338
+
339
+ METRICS_LOGGER.level = old_level
340
+ end
341
+
342
+ def test_empty_config
343
+ orig_rails_env = Object.const_get('RAILS_ENV')
344
+ Object.const_set('RAILS_ENV', 'staging')
345
+ assert_nothing_raised { Metrics::Config.instance.send(:load_config) }
346
+ Object.const_set('RAILS_ENV', orig_rails_env)
347
+ end
348
+
349
+ def test_benchmark
350
+
351
+ Benchmark.bmbm do |x|
352
+ x.report("new with metrics") do
353
+ SomeClassToTest.new
354
+ end
355
+ x.report("new without metrics") do
356
+ SomeClassToTestWithoutCollection.new
357
+ end
358
+
359
+ some_class_instance = SomeClassToTest.new
360
+ x.report("method call with metrics") do
361
+ some_class_instance.my_method
362
+ end
363
+ x.report("method call without metrics") do
364
+ some_class_instance.my_non_metric_method
365
+ end
366
+
367
+ x.report("multiple method calls (1000) with metrics") do
368
+ 1000.times { some_class_instance.my_method }
369
+ end
370
+ x.report("multiple method calls (1000) without metrics") do
371
+ 1000.times { some_class_instance.my_non_metric_method }
372
+ end
373
+
374
+ x.report("args inspector") do
375
+ args_inspector("nothing")
376
+ end
377
+
378
+ x.report("random id 100") do
379
+ 100.times { rand(99999) }
380
+ end
381
+
382
+ x.report("random id 1") do
383
+ rand(99999)
384
+ end
385
+
386
+ end
387
+ end
388
+
389
+ def test_no_logging
390
+ disable_logging = lambda do
391
+ Metrics.module_eval <<-EOS
392
+ def log_metrics(result, args); end
393
+ EOS
394
+ end
395
+
396
+ disable_logging.call()
397
+
398
+ some_class_instance = SomeClassToTest.new
399
+ Benchmark.bmbm do |x|
400
+ x.report("multiple method calls with metrics and no logging") do
401
+ 100.times { some_class_instance.my_method }
402
+ end
403
+ x.report("multiple method calls without metrics and no logging") do
404
+ 100.times { some_class_instance.my_non_metric_method }
405
+ end
406
+ end
407
+ end
408
+
409
+ ITER_TIMES = 10000
410
+
411
+ def test_logging_debug
412
+ test_args = {:test => "to this", :another_key => "and this stuff"}
413
+ default_level = METRICS_LOGGER.level
414
+ METRICS_LOGGER.level = debug_level
415
+
416
+ Benchmark.bmbm do |x|
417
+ x.report("DEBUG MODE - test with debug on and in a block") do
418
+ ITER_TIMES.times { METRICS_LOGGER.debug {"dm 1 - do something #{test_args.inspect}"} }
419
+ end
420
+
421
+ x.report("DEBUG MODE - test with debug on and a string") do
422
+ ITER_TIMES.times { METRICS_LOGGER.debug "dm 2 - do something #{test_args.inspect}" }
423
+ end
424
+
425
+ x.report("DEBUG MODE - test with debug on and a string and with if test") do
426
+ ITER_TIMES.times { METRICS_LOGGER.debug "dm 3 - do something #{test_args.inspect}" if METRICS_LOGGER.debug? }
427
+ end
428
+ end
429
+
430
+ METRICS_LOGGER.level = fatal_level
431
+
432
+ Benchmark.bmbm do |x|
433
+ x.report("FATAL MODE - test with debug on and in a block") do
434
+ ITER_TIMES.times { METRICS_LOGGER.debug {"fm 1 - do something #{test_args.inspect}"} }
435
+ end
436
+
437
+ x.report("FATAL MODE - test with debug on and a string") do
438
+ ITER_TIMES.times { METRICS_LOGGER.debug "fm 2 - do something #{test_args.inspect}" }
439
+ end
440
+
441
+ x.report("FATAL MODE - test with debug on and a string and with if test") do
442
+ ITER_TIMES.times { METRICS_LOGGER.debug "fm 3 - do something #{test_args.inspect}" if METRICS_LOGGER.debug? }
443
+ end
444
+ end
445
+
446
+ METRICS_LOGGER.level = default_level
447
+ end
448
+
449
+
450
+ private
451
+
452
+ def args_inspector(*args)
453
+ args_str = args.inspect
454
+ end
455
+
456
+ def collect_result_test(testing_a = true)
457
+ Metrics.collect_metrics("[acts_as_rhg_rateable] - associate_rating_template") do
458
+ if (testing_a)
459
+ "123"
460
+ else
461
+ "321"
462
+ end
463
+ end
464
+ end
465
+
466
+ def collect_result_test2(testing_a = true)
467
+ Metrics.collect_metrics("[acts_as_rhg_rateable2] - associate_rating_template", testing_a, "something else") do
468
+ if (testing_a)
469
+ "123"
470
+ else
471
+ "321"
472
+ end
473
+ end
474
+ end
475
+
476
+ def fatal_level
477
+ if defined?(Log4r)
478
+ Log4r::FATAL
479
+ else
480
+ Logger::FATAL
481
+ end
482
+ end
483
+
484
+ def debug_level
485
+ if defined?(Log4r)
486
+ Log4r::DEBUG
487
+ else
488
+ Logger::DEBUG
489
+ end
490
+ end
491
+
492
+
493
+ def string_outputter
494
+ @string_outputter
495
+ end
496
+
497
+ def output
498
+ @output
499
+ end
500
+
501
+ def start_logging
502
+ @output = StringIO.new
503
+ if defined?(Log4r)
504
+ @string_outputter = Log4r::IOOutputter.new("metrics_log", output)
505
+ @string_outputter.formatter = METRICS_LOGGER.outputters[0].formatter
506
+ METRICS_LOGGER.add(@string_outputter)
507
+ else
508
+ string_outputdev = Logger::LogDevice.new(@output, :shift_age => 0, :shift_size => 1048576)
509
+ METRICS_LOGGER.instance_variable_set('@logdev', string_outputdev)
510
+ end
511
+ nowhere_log = Logger.new(StringIO.new)
512
+ ActiveRecord::Base.logger = nowhere_log # send AR logging off to no where
513
+ ActionController::Base.logger = nowhere_log # send AR logging off to no where
514
+ end
515
+
516
+ def stop_logging
517
+ if defined?(Log4r)
518
+ @string_outputter.close
519
+ METRICS_LOGGER.remove(@string_outputter)
520
+ @string_outputter = nil
521
+ @output = nil
522
+ end
523
+ end
524
+ end
525
+
526
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
527
+ # This source code may not be disclosed to others, used or reproduced without the written permission of Revolution Health Group.
@@ -0,0 +1,51 @@
1
+ module RHG
2
+
3
+ if defined?(RHG::ServiceConfig)
4
+
5
+ class MetricsTestClass < RHG::Facade::Base
6
+ backend_instance_method :my_method
7
+
8
+ def self.backend
9
+ @backend || reset_backend(Metrics::MetricsBackendClass)
10
+ end
11
+ end
12
+
13
+ class Metrics::MetricsBackendClass
14
+ include RHG::ServiceConfig
15
+ collect_metrics_on :my_method
16
+
17
+ def my_method(blah = nil)
18
+ print "blah = #{blah}\n" if blah != nil
19
+ true
20
+ end
21
+
22
+ def my_non_metric_method(blah = nil)
23
+ print "blah = #{blah}\n" if blah != nil
24
+ true
25
+ end
26
+
27
+ collect_metrics_on :my_method
28
+ end
29
+
30
+ else # if not defined ServiceConfig
31
+
32
+ class MetricsTestClass
33
+ collect_metrics_on :my_method
34
+
35
+ def my_method(blah = nil)
36
+ print "blah = #{blah}\n" if blah != nil
37
+ true
38
+ end
39
+
40
+ def my_non_metric_method(blah = nil)
41
+ print "blah = #{blah}\n" if blah != nil
42
+ true
43
+ end
44
+
45
+ collect_metrics_on :my_method
46
+ end
47
+ end # end if defined?
48
+
49
+ end
50
+ # CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
51
+ # This source code may not be disclosed to others, used or reproduced without the written permission of Revolution Health Group.
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: revolutionhealth-metrics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.9
5
+ platform: ruby
6
+ authors:
7
+ - Revolution Health
8
+ autorequire: metrics
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-06-27 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: metrics allows one to track the performance of particular controllers, database calls, and other methods
17
+ email: rails-trunk@revolutionhealth.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - LICENSE
25
+ - TODO
26
+ files:
27
+ - LICENSE
28
+ - README
29
+ - Rakefile
30
+ - TODO
31
+ - lib/metrics
32
+ - lib/metrics/collector.rb
33
+ - lib/metrics/config.rb
34
+ - lib/metrics/logger.rb
35
+ - lib/metrics.rb
36
+ - lib/rails
37
+ - lib/rails/activerecord_enhanced_metrics.rb
38
+ - lib/rails/activerecord_metrics.rb
39
+ - lib/rails/controller_metrics.rb
40
+ - lib/ruby
41
+ - lib/ruby/http_metrics.rb
42
+ - lib/ruby/metric_extensions.rb
43
+ - test/metrics_test.rb
44
+ - test/metrics_test_class.rb
45
+ - config/metrics.yml
46
+ - init.rb
47
+ has_rdoc: false
48
+ homepage: http://github.com/revolutionhealth/metrics
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.2.0
70
+ signing_key:
71
+ specification_version: 2
72
+ summary: metrics allows one to track the performance of particular controllers, database calls, and other methods
73
+ test_files: []
74
+