request-log-analyzer 1.4.0 → 1.4.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008 Willem van Bergen / Bart ten Brinke
1
+ Copyright (c) 2008-2009 Willem van Bergen & Bart ten Brinke
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,42 +1,37 @@
1
1
  = Request-log-analyzer
2
2
 
3
- This is a simple command line tool to analyze request log files of both Rails and
4
- Merb to produce a performance report. Its purpose is to find what actions are best candidates for optimization.
3
+ This is a simple command line tool to analyze request log files in various formats to produce a performance report. Its purpose is to find what actions are best candidates for optimization.
5
4
 
6
- * Analyzes Rails log files (all versions), Merb logs, or any other log format you specify
7
- * Combines multiple files and decompresses compressed files (handy if you are using logrotate)
8
- * Uses several metrics, including cumulative request time, average request time, process blockers, database and rendering time, HTTP methods and statuses, Rails action cache statistics, etc.) (Sample output: http://wiki.github.com/wvanbergen/request-log-analyzer/sample-output)
9
- * Low memory footprint and reasonably fast (server-safe)
5
+ * Analyzes Rails request logs, Merb request logs, Apache access logs and more, or parses any other log format you specify.
6
+ * Combines multiple files and decompresses compressed files, which comes in handy if you are using logrotate.
7
+ * Uses several metrics, including cumulative request time, mean request time, process blockers, database and rendering time, HTTP methods and statuses, Rails action cache statistics, etc.) (Sample output: http://wiki.github.com/wvanbergen/request-log-analyzer/sample-output)
8
+ * Low memory footprint and reasonably fast, so it is safe to run on a production server.
10
9
  * MIT licensed
11
10
 
12
- Request log analyzer was designed and built by Willem van Bergen and Bart ten Brinke.
11
+ See the project wiki at http://wiki.github.com/wvanbergen/request-log-analyzer for documentation and additional information.
13
12
 
14
- == Installation
13
+ == Installation & basic usage
15
14
 
16
- Install request-log-analyzer as a Ruby gem:
15
+ Install request-log-analyzer as a Ruby gem (you might need to run this command
16
+ as root by prepending +sudo+ to it):
17
17
 
18
- $ sudo gem install request-log-analyzer
18
+ $ gem install request-log-analyzer
19
19
 
20
- Alternatively, use the gem from the GitHub gem server:
21
-
22
- $ sudo gem install wvanbergen-request-log-analyzer --source http://gems.github.com
23
-
24
- To get the best results out of request-log-analyzer, make sure to
25
- set up logging correctly: http://wiki.github.com/wvanbergen/request-log-analyzer/configure-logging
26
- for your application.
27
-
28
- == Usage
29
-
30
- To analyze a log file and produce a performance report, run request-log-analyzer like this:
20
+ To analyze a Rails log file and produce a performance report, run
21
+ request-log-analyzer like this:
31
22
 
32
23
  $ request-log-analyzer log/production.log
33
24
 
34
- For more details and available command line options, see the project's wiki: http://wiki.github.com/wvanbergen/request-log-analyzer/basic-usage
25
+ For more details, other file formats, and available command line options, see the project's wiki at http://wiki.github.com/wvanbergen/request-log-analyzer
35
26
 
36
27
  == Additional information
37
28
 
38
- Do you have a rails application that is not performing as it should?
39
- If you need an expert to analyze your application, feel free to contact either Willem van Bergen (willem@railsdoctors.com) or Bart ten Brinke (bart@railsdoctors.com).
29
+ Request-log-analyzer was designed and built by Willem van Bergen and Bart ten
30
+ Brinke.
31
+
32
+ Do you have a rails application that is not performing as it should? If you need
33
+ an expert to analyze your application, feel free to contact either Willem van
34
+ Bergen (willem@railsdoctors.com) or Bart ten Brinke (bart@railsdoctors.com).
40
35
 
41
36
  * Project wiki at GitHub: http://wiki.github.com/wvanbergen/request-log-analyzer
42
37
  * railsdoctors homepage: http://railsdoctors.com
@@ -11,7 +11,7 @@ module RequestLogAnalyzer
11
11
 
12
12
  # The current version of request-log-analyzer.
13
13
  # Do not change the value by hand; it will be updated automatically by the gem release script.
14
- VERSION = "1.4.0"
14
+ VERSION = "1.4.0.1"
15
15
 
16
16
  # Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
17
17
  # <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
@@ -90,7 +90,7 @@ module RequestLogAnalyzer::Aggregator
90
90
  # Call finalize on all trackers. Saves a YAML dump if this is set in the options.
91
91
  def finalize
92
92
  @trackers.each { |tracker| tracker.finalize }
93
- save_results_dump(options[:dump]) if options[:dump]
93
+ save_results_dump(options[:yaml]) if options[:yaml]
94
94
  end
95
95
 
96
96
  # Saves the results of all the trackers in YAML format to a file.
@@ -30,7 +30,7 @@ module RequestLogAnalyzer
30
30
  options[:database] = arguments[:database]
31
31
  options[:reset_database] = arguments[:reset_database]
32
32
  options[:debug] = arguments[:debug]
33
- options[:dump] = arguments[:dump]
33
+ options[:yaml] = arguments[:dump]
34
34
  options[:parse_strategy] = arguments[:parse_strategy]
35
35
  options[:no_progress] = arguments[:no_progress]
36
36
  options[:format] = arguments[:format]
@@ -80,9 +80,9 @@ module RequestLogAnalyzer
80
80
  # * <tt>:database</tt> Database file
81
81
  # * <tt>:reset_database</tt>
82
82
  # * <tt>:debug</tt> Enables echo aggregator.
83
- # * <tt>:dump</tt>
83
+ # * <tt>:yaml</tt> Output to YAML
84
84
  # * <tt>:parse_strategy</tt>
85
- # * <tt>:no_progress</tt>
85
+ # * <tt>:no_progress</tt> Do not display the progress bar
86
86
  # * <tt>:output</tt> :fixed_width, :html or Output class. Defaults to fixed width.
87
87
  # * <tt>:file</tt> Filestring or File or StringIO
88
88
  # * <tt>:format</tt> :rails, {:apache => 'FORMATSTRING'}, :merb, etcetera or Format Class. Defaults to :rails.
@@ -100,7 +100,7 @@ module RequestLogAnalyzer
100
100
  # Refactor :database => options[:database], :dump => options[:dump] away from contoller intialization.
101
101
  def self.build(options)
102
102
  # Defaults
103
- options[:output] ||= :fixed_width
103
+ options[:output] ||= 'fixed_width'
104
104
  options[:format] ||= :rails
105
105
  options[:aggregator] ||= [:summarizer]
106
106
  options[:report_width] ||= 80
@@ -108,6 +108,12 @@ module RequestLogAnalyzer
108
108
  options[:report_sort] ||= 'sum,mean'
109
109
  options[:boring] ||= false
110
110
 
111
+ # Backwards compatibility
112
+ if options[:dump] && options[:yaml].blank?
113
+ warn "[DEPRECATION] `:dump` is deprecated. Please use `:yaml` instead."
114
+ options[:yaml] = options[:dump]
115
+ end
116
+
111
117
  # Set the output class
112
118
  output_args = {}
113
119
  output_object = nil
@@ -145,8 +151,9 @@ module RequestLogAnalyzer
145
151
  controller = Controller.new( RequestLogAnalyzer::Source::LogParser.new(file_format, :source_files => options[:source_files]),
146
152
  { :output => output_instance,
147
153
  :database => options[:database], # FUGLY!
148
- :dump => options[:dump],
149
- :reset_database => options[:reset_database]})
154
+ :yaml => options[:yaml],
155
+ :reset_database => options[:reset_database],
156
+ :no_progress => options[:no_progress]})
150
157
 
151
158
  # register filters
152
159
  if options[:after] || options[:before]
@@ -188,7 +195,7 @@ module RequestLogAnalyzer
188
195
  # <tt>format</tt> Logfile format. Defaults to :rails
189
196
  # Options are passd on to the LogParser.
190
197
  # * <tt>:database</tt> Database the controller should use.
191
- # * <tt>:dump</tt> Yaml Dump the contrller should use.
198
+ # * <tt>:yaml</tt> Yaml Dump the contrller should use.
192
199
  # * <tt>:output</tt> All report outputs get << through this output.
193
200
  # * <tt>:no_progress</tt> No progress bar
194
201
  def initialize(source, options = {})
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.name = "request-log-analyzer"
3
3
 
4
4
  # Do not set the version and date field manually, this is done by the release script
5
- s.version = "1.4.0"
6
- s.date = "2009-09-30"
5
+ s.version = "1.4.0.1"
6
+ s.date = "2009-10-03"
7
7
 
8
8
  s.rubyforge_project = 'r-l-a'
9
9
 
@@ -35,6 +35,6 @@ Gem::Specification.new do |s|
35
35
 
36
36
  # The files and test_files directives are set automatically by the release script.
37
37
  # Do not change them by hand, but make sure to add the files to the git repository.
38
- s.files = %w(spec/unit/filter/anonymize_filter_spec.rb spec/fixtures/rails_22_cached.log lib/request_log_analyzer/line_definition.rb lib/request_log_analyzer/output/html.rb lib/request_log_analyzer/controller.rb spec/lib/macros.rb lib/request_log_analyzer/file_format/rails_development.rb spec/fixtures/apache_combined.log spec/fixtures/apache_common.log spec/fixtures/merb_prefixed.log lib/request_log_analyzer/file_format/amazon_s3.rb tasks/request_log_analyzer.rake spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/apache_format_spec.rb spec/integration/command_line_usage_spec.rb lib/request_log_analyzer/database.rb spec/fixtures/decompression.log.bz2 spec/fixtures/rails_unordered.log lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/filter.rb bin/request-log-analyzer request-log-analyzer.gemspec DESIGN.rdoc spec/unit/filter/timespan_filter_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/lib/matchers.rb lib/request_log_analyzer/filter/field.rb lib/request_log_analyzer/tracker/frequency.rb spec/fixtures/decompression.log.gz spec/fixtures/decompression.log spec/lib/testing_format.rb spec/fixtures/test_order.log spec/fixtures/rails.db lib/request_log_analyzer/output/fixed_width.rb lib/request_log_analyzer/filter/anonymize.rb lib/request_log_analyzer/tracker/timespan.rb lib/request_log_analyzer/database/base.rb lib/request_log_analyzer/aggregator.rb spec/unit/request_spec.rb lib/cli/progressbar.rb lib/request_log_analyzer/mailer.rb README.rdoc lib/request_log_analyzer/database/warning.rb spec/fixtures/merb.log lib/request_log_analyzer/tracker/hourly_spread.rb .gitignore spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb lib/request_log_analyzer/aggregator/echo.rb spec/unit/mailer_spec.rb spec/unit/controller/log_processor_spec.rb spec/spec_helper.rb lib/request_log_analyzer.rb spec/database.yml Rakefile lib/request_log_analyzer/database/connection.rb spec/unit/filter/filter_spec.rb spec/fixtures/test_language_combined.log lib/request_log_analyzer/aggregator/database_inserter.rb lib/request_log_analyzer/aggregator/summarizer.rb lib/request_log_analyzer/file_format/rack.rb lib/request_log_analyzer/database/source.rb lib/request_log_analyzer/file_format/rails.rb spec/fixtures/decompression.tar.gz spec/unit/tracker/traffic_tracker_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/database/base_class_spec.rb lib/request_log_analyzer/filter/timespan.rb lib/request_log_analyzer/source/log_parser.rb spec/fixtures/decompression.tgz spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/fixtures/header_and_footer.log lib/cli/tools.rb lib/request_log_analyzer/file_format/merb.rb spec/fixtures/multiple_files_1.log spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/line_definition_spec.rb lib/request_log_analyzer/source.rb lib/request_log_analyzer/request.rb lib/cli/database_console.rb spec/unit/database/connection_spec.rb spec/unit/controller/controller_spec.rb spec/lib/mocks.rb spec/lib/helpers.rb spec/fixtures/rails_1x.log lib/cli/database_console_init.rb lib/request_log_analyzer/output.rb lib/request_log_analyzer/file_format/apache.rb spec/fixtures/decompression.log.zip spec/unit/source/log_parser_spec.rb spec/fixtures/test_file_format.log tasks/github-gem.rake spec/unit/database/database_spec.rb lib/request_log_analyzer/tracker/duration.rb lib/request_log_analyzer/tracker/traffic.rb lib/request_log_analyzer/file_format.rb spec/unit/aggregator/summarizer_spec.rb spec/fixtures/syslog_1x.log spec/fixtures/rails_22.log lib/request_log_analyzer/database/request.rb spec/fixtures/multiple_files_2.log LICENSE lib/request_log_analyzer/source/database_loader.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb lib/cli/command_line_arguments.rb)
39
- s.test_files = %w(spec/unit/filter/anonymize_filter_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/apache_format_spec.rb spec/integration/command_line_usage_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/request_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/mailer_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/filter_spec.rb spec/unit/tracker/traffic_tracker_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/database/base_class_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/database/connection_spec.rb spec/unit/controller/controller_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/database/database_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb)
38
+ s.files = %w(spec/unit/filter/anonymize_filter_spec.rb spec/fixtures/rails_22_cached.log lib/request_log_analyzer/line_definition.rb lib/request_log_analyzer/output/html.rb lib/request_log_analyzer/controller.rb spec/lib/macros.rb lib/request_log_analyzer/file_format/rails_development.rb spec/fixtures/apache_combined.log spec/fixtures/apache_common.log spec/fixtures/merb_prefixed.log lib/request_log_analyzer/file_format/amazon_s3.rb tasks/request_log_analyzer.rake spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/apache_format_spec.rb spec/integration/command_line_usage_spec.rb lib/request_log_analyzer/database.rb spec/fixtures/decompression.log.bz2 spec/fixtures/rails_unordered.log lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/filter.rb bin/request-log-analyzer request-log-analyzer.gemspec DESIGN.rdoc spec/unit/filter/timespan_filter_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/lib/matchers.rb lib/request_log_analyzer/filter/field.rb lib/request_log_analyzer/tracker/frequency.rb spec/fixtures/decompression.log.gz spec/fixtures/decompression.log spec/lib/testing_format.rb spec/fixtures/test_order.log spec/fixtures/rails.db lib/request_log_analyzer/output/fixed_width.rb lib/request_log_analyzer/filter/anonymize.rb lib/request_log_analyzer/tracker/timespan.rb lib/request_log_analyzer/database/base.rb lib/request_log_analyzer/aggregator.rb spec/unit/request_spec.rb lib/cli/progressbar.rb lib/request_log_analyzer/mailer.rb README.rdoc lib/request_log_analyzer/database/warning.rb spec/fixtures/merb.log lib/request_log_analyzer/tracker/hourly_spread.rb .gitignore spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/integration/scout_spec.rb lib/request_log_analyzer/aggregator/echo.rb spec/unit/mailer_spec.rb spec/unit/controller/log_processor_spec.rb spec/spec_helper.rb lib/request_log_analyzer.rb spec/database.yml Rakefile lib/request_log_analyzer/database/connection.rb spec/unit/filter/filter_spec.rb spec/fixtures/test_language_combined.log lib/request_log_analyzer/aggregator/database_inserter.rb lib/request_log_analyzer/aggregator/summarizer.rb lib/request_log_analyzer/file_format/rack.rb lib/request_log_analyzer/database/source.rb lib/request_log_analyzer/file_format/rails.rb spec/fixtures/decompression.tar.gz spec/unit/tracker/traffic_tracker_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/database/base_class_spec.rb lib/request_log_analyzer/filter/timespan.rb lib/request_log_analyzer/source/log_parser.rb spec/fixtures/decompression.tgz spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/fixtures/header_and_footer.log lib/cli/tools.rb lib/request_log_analyzer/file_format/merb.rb spec/fixtures/multiple_files_1.log spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/line_definition_spec.rb lib/request_log_analyzer/source.rb lib/request_log_analyzer/request.rb lib/cli/database_console.rb spec/unit/database/connection_spec.rb spec/unit/controller/controller_spec.rb spec/lib/mocks.rb spec/lib/helpers.rb spec/fixtures/rails_1x.log lib/cli/database_console_init.rb lib/request_log_analyzer/output.rb lib/request_log_analyzer/file_format/apache.rb spec/fixtures/decompression.log.zip spec/unit/source/log_parser_spec.rb spec/integration/scouts_custom_output.rb spec/fixtures/test_file_format.log tasks/github-gem.rake spec/unit/database/database_spec.rb spec/integration/munin_plugins_rails_spec.rb lib/request_log_analyzer/tracker/duration.rb lib/request_log_analyzer/tracker/traffic.rb lib/request_log_analyzer/file_format.rb spec/unit/aggregator/summarizer_spec.rb spec/fixtures/syslog_1x.log spec/fixtures/rails_22.log lib/request_log_analyzer/database/request.rb spec/fixtures/multiple_files_2.log LICENSE lib/request_log_analyzer/source/database_loader.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb lib/cli/command_line_arguments.rb)
39
+ s.test_files = %w(spec/unit/filter/anonymize_filter_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/apache_format_spec.rb spec/integration/command_line_usage_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/request_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/integration/scout_spec.rb spec/unit/mailer_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/filter_spec.rb spec/unit/tracker/traffic_tracker_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/database/base_class_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/database/connection_spec.rb spec/unit/controller/controller_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/database/database_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb)
40
40
  end
@@ -72,9 +72,9 @@ describe RequestLogAnalyzer, 'running from command line' do
72
72
  end
73
73
 
74
74
  it "should dump the results to a YAML file" do
75
- run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:dump)}")
76
- File.exist?(temp_output_file(:dump)).should be_true
77
- YAML::load(File.read(temp_output_file(:dump))).should have_at_least(1).item
75
+ run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:yaml)}")
76
+ File.exist?(temp_output_file(:yaml)).should be_true
77
+ YAML::load(File.read(temp_output_file(:yaml))).should have_at_least(1).item
78
78
  end
79
79
 
80
80
  it "should parse 4 requests from the standard input" do
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RequestLogAnalyzer, 'when harvesting like munin-plugins-rails the YAML output' do
4
+
5
+ before(:each) do
6
+ cleanup_temp_files!
7
+ run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:yaml)}")
8
+ @rla = YAML::load(File.read(temp_output_file(:yaml)))
9
+ end
10
+
11
+ after(:each) do
12
+ cleanup_temp_files!
13
+ end
14
+
15
+ it "should contain database times" do
16
+ @rla["Database time"].each do |item|
17
+ item[1][:min].should_not be_nil
18
+ item[1][:max].should_not be_nil
19
+ item[1][:hits].should_not be_nil
20
+ item[1][:sum].should_not be_nil
21
+ end
22
+ end
23
+
24
+ it "should contain request times" do
25
+ @rla["Request duration"].each do |item|
26
+ item[1][:min].should_not be_nil
27
+ item[1][:max].should_not be_nil
28
+ item[1][:hits].should_not be_nil
29
+ item[1][:sum].should_not be_nil
30
+ end
31
+ end
32
+
33
+ it "should contain failed requests" do
34
+ @rla.keys.should include("Failed requests")
35
+ end
36
+
37
+ it "should contain Process blockers" do
38
+ @rla.keys.should include("Process blockers (> 1 sec duration)")
39
+ end
40
+
41
+ it "should contain HTTP Methods" do
42
+ @rla["HTTP methods"]["GET"].should_not be_nil
43
+ end
44
+
45
+ it "should contain HTTP Methods" do
46
+ @rla["HTTP methods"]["GET"].should_not be_nil
47
+ end
48
+
49
+ it "should contain view rendering times" do
50
+ @rla["View rendering time"].each do |item|
51
+ item[1][:min].should_not be_nil
52
+ item[1][:max].should_not be_nil
53
+ item[1][:hits].should_not be_nil
54
+ item[1][:sum].should_not be_nil
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,71 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/scouts_custom_output'
3
+
4
+ def capture_stdout_and_stderr_with_warnings_on
5
+ $stdout, $stderr, warnings, $VERBOSE =
6
+ StringIO.new, StringIO.new, $VERBOSE, true
7
+ yield
8
+ return $stdout.string, $stderr.string
9
+ ensure
10
+ $stdout, $stderr, $VERBOSE = STDOUT, STDERR, warnings
11
+ end
12
+
13
+ describe RequestLogAnalyzer, 'when using the rla API like the scout plugin' do
14
+
15
+ before(:each) do
16
+ # prepare a place to capture the output
17
+ sio = StringIO.new
18
+
19
+ # place an IO object where I want RequestLogAnalyzer to read from
20
+ open(log_fixture(:rails_1x)) do |log|
21
+ completed_count = 0
22
+ log.each do |line|
23
+ completed_count += 1 if line =~ /\ACompleted\b/
24
+ break if completed_count == 2 # skipping first two requests
25
+ end
26
+
27
+ # trigger the log parse
28
+ @stdout, @stderr = capture_stdout_and_stderr_with_warnings_on do
29
+ RequestLogAnalyzer::Controller.build(
30
+ :output => EmbeddedHTML,
31
+ :file => sio,
32
+ :after => Time.local(2008, 8, 14, 21, 16, 31), # after 3rd req
33
+ :source_files => log
34
+ ).run!
35
+ end
36
+ end
37
+
38
+ # read the resulting output
39
+ @analysis = sio.string
40
+ end
41
+
42
+ it "should generate an analysis" do
43
+ @analysis.should_not be_empty
44
+ end
45
+
46
+ it "should generate customized output using the passed Class" do
47
+ credit = %r{<p>Powered by request-log-analyzer v\d+(?:\.\d+)+</p>\z}
48
+ @analysis.should match(credit)
49
+ end
50
+
51
+ it "should skip requests before :after Time" do
52
+ @analysis.should_not include("PeopleController#show")
53
+ end
54
+
55
+ it "should include requests after IO#pos and :after Time" do
56
+ @analysis.should include("PeopleController#picture")
57
+ end
58
+
59
+ it "should skip requests before IO#pos" do
60
+ @analysis.should_not include("PeopleController#index")
61
+ end
62
+
63
+ it "should not print to $stdout" do
64
+ @stdout.should be_empty
65
+ end
66
+
67
+ it "should not print to $stderr (with warnings on)" do
68
+ @stderr.should be_empty
69
+ end
70
+
71
+ end
@@ -0,0 +1,78 @@
1
+ class EmbeddedHTML < RequestLogAnalyzer::Output::Base
2
+ def print(str)
3
+ @io << str
4
+ end
5
+ alias_method :<<, :print
6
+
7
+ def puts(str = "")
8
+ @io << "#{str}<br/>\n"
9
+ end
10
+
11
+ def title(title)
12
+ @io.puts(tag(:h2, title))
13
+ end
14
+
15
+ def line(*font)
16
+ @io.puts(tag(:hr))
17
+ end
18
+
19
+ def link(text, url = nil)
20
+ url = text if url.nil?
21
+ tag(:a, text, :href => url)
22
+ end
23
+
24
+ def table(*columns, &block)
25
+ rows = Array.new
26
+ yield(rows)
27
+
28
+ @io << tag(:table, :cellspacing => 0) do |content|
29
+ if table_has_header?(columns)
30
+ content << tag(:tr) do
31
+ columns.map { |col| tag(:th, col[:title]) }.join("\n")
32
+ end
33
+ end
34
+
35
+ odd = false
36
+ rows.each do |row|
37
+ odd = !odd
38
+ content << tag(:tr) do
39
+ if odd
40
+ row.map { |cell| tag(:td, cell, :class => "alt") }.join("\n")
41
+ else
42
+ row.map { |cell| tag(:td, cell) }.join("\n")
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def header
50
+ end
51
+
52
+ def footer
53
+ @io << tag(:hr) << tag(:p, "Powered by request-log-analyzer v#{RequestLogAnalyzer::VERSION}")
54
+ end
55
+
56
+ private
57
+
58
+ def tag(tag, content = nil, attributes = nil)
59
+ if block_given?
60
+ attributes = content.nil? ? "" : " " + content.map { |(key, value)| "#{key}=\"#{value}\"" }.join(" ")
61
+ content_string = ""
62
+ content = yield(content_string)
63
+ content = content_string unless content_string.empty?
64
+ "<#{tag}#{attributes}>#{content}</#{tag}>"
65
+ else
66
+ attributes = attributes.nil? ? "" : " " + attributes.map { |(key, value)| "#{key}=\"#{value}\"" }.join(" ")
67
+ if content.nil?
68
+ "<#{tag}#{attributes} />"
69
+ else
70
+ if content.class == Float
71
+ "<#{tag}#{attributes}><div class='color_bar' style=\"width:#{(content*200).floor}px;\"/></#{tag}>"
72
+ else
73
+ "<#{tag}#{attributes}>#{content}</#{tag}>"
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -10,6 +10,11 @@ module RequestLogAnalyzer::Spec::Helpers
10
10
  File.dirname(__FILE__) + "/../fixtures/#{name}.#{extention}"
11
11
  end
12
12
 
13
+ # Creates a log file given some lines
14
+ def log_stream(*lines)
15
+ StringIO.new(lines.join("\n") + "\n")
16
+ end
17
+
13
18
  # Request loopback
14
19
  def request(fields, format = testing_format)
15
20
  if fields.kind_of?(Array)
@@ -70,5 +70,7 @@ module RequestLogAnalyzer::Spec::Mocks
70
70
  return connection
71
71
  end
72
72
 
73
-
73
+ def request_counter
74
+ @request_counter ||= mock('aggregator to count request')
75
+ end
74
76
  end
@@ -51,146 +51,153 @@ describe RequestLogAnalyzer::FileFormat::Apache do
51
51
 
52
52
  context '"Common" access log parsing' do
53
53
  before(:all) do
54
- @file_format = RequestLogAnalyzer::FileFormat.load(:apache, :common)
55
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
56
- @sample_1 = '1.129.119.13 - - [08/Sep/2009:07:54:09 -0400] "GET /profile/18543424 HTTP/1.0" 200 8223'
57
- @sample_2 = '1.82.235.29 - - [08/Sep/2009:07:54:05 -0400] "GET /gallery/fresh?page=23&per_page=16 HTTP/1.1" 200 23414'
54
+ @file_format = RequestLogAnalyzer::FileFormat.load(:apache, :common)
55
+ @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
56
+ @sample_1 = '1.129.119.13 - - [08/Sep/2009:07:54:09 -0400] "GET /profile/18543424 HTTP/1.0" 200 8223'
57
+ @sample_2 = '1.82.235.29 - - [08/Sep/2009:07:54:05 -0400] "GET /gallery/fresh?page=23&per_page=16 HTTP/1.1" 200 23414'
58
+ @nonsense_sample = 'addasdsasadadssadasd'
58
59
  end
59
60
 
60
61
  it "should have a valid language definitions" do
61
62
  @file_format.should be_valid
62
63
  end
63
64
 
64
- it "should parse a valid access log line" do
65
- @file_format.line_definitions[:access].matches(@sample_1).should be_kind_of(Hash)
66
- end
67
-
68
65
  it "should not parse a valid access log line" do
69
- @file_format.line_definitions[:access].matches('addasdsasadadssadasd').should be_false
66
+ @file_format.should_not parse_line(@nonsense_sample)
70
67
  end
71
68
 
72
69
  it "should read the correct values from a valid HTTP/1.0 access log line" do
73
- @log_parser.parse_io(StringIO.new(@sample_1)) do |request|
74
- request[:remote_host].should == '1.129.119.13'
75
- request[:timestamp].should == 20090908075409
76
- request[:http_status].should == 200
77
- request[:http_method].should == 'GET'
78
- request[:http_version].should == '1.0'
79
- request[:bytes_sent].should == 8223
80
- request[:user].should == nil
81
- end
70
+ @file_format.should parse_line(@sample_1).as(:access).and_capture(
71
+ :remote_host => '1.129.119.13',
72
+ :remote_logname => nil,
73
+ :user => nil,
74
+ :timestamp => 20090908075409,
75
+ :http_status => 200,
76
+ :http_method => 'GET',
77
+ :http_version => '1.0',
78
+ :bytes_sent => 8223)
82
79
  end
83
80
 
84
81
  it "should read the correct values from a valid 200 access log line" do
85
- @log_parser.parse_io(StringIO.new(@sample_2)) do |request|
86
- request[:remote_host].should == '1.82.235.29'
87
- request[:timestamp].should == 20090908075405
88
- request[:http_status].should == 200
89
- request[:http_method].should == 'GET'
90
- request[:http_version].should == '1.1'
91
- request[:bytes_sent].should == 23414
92
- request[:user].should == nil
82
+ @file_format.should parse_line(@sample_2).as(:access).and_capture(
83
+ :remote_host => '1.82.235.29',
84
+ :remote_logname => nil,
85
+ :user => nil,
86
+ :timestamp => 20090908075405,
87
+ :http_status => 200,
88
+ :http_method => 'GET',
89
+ :http_version => '1.1',
90
+ :bytes_sent => 23414)
91
+ end
92
+
93
+ it "should parse 10 request from fixture access log without warnings" do
94
+ request_counter.should_receive(:hit!).exactly(10).times
95
+ @log_parser.should_not_receive(:warn)
96
+
97
+ @log_parser.parse_file(log_fixture(:apache_common)) do |request|
98
+ request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Apache::Request)
93
99
  end
94
100
  end
95
-
96
- it "should parse 10 request from fixture access log" do
97
- counter = mock('counter')
98
- counter.should_receive(:hit!).exactly(10).times
99
- @log_parser.parse_file(log_fixture(:apache_common)) { counter.hit! }
100
- end
101
101
  end
102
102
 
103
- context '"Rack" access log parser' do
104
- before(:each) do
105
- @file_format = RequestLogAnalyzer::FileFormat.load(:rack)
106
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
107
- @sample_1 = '127.0.0.1 - - [16/Sep/2009 06:40:08] "GET /favicon.ico HTTP/1.1" 500 63183 0.0453'
108
- end
103
+ context '"Combined" access log parsing' do
109
104
 
110
- it "should create a kind of an Apache file format" do
111
- @file_format.should be_kind_of(RequestLogAnalyzer::FileFormat::Apache)
105
+ before(:all) do
106
+ @file_format = RequestLogAnalyzer::FileFormat.load(:apache, :combined)
107
+ @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
108
+ @sample_1 = '69.41.0.45 - - [02/Sep/2009:12:02:40 +0200] "GET //phpMyAdmin/ HTTP/1.1" 404 209 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"'
109
+ @sample_2 = '10.0.1.1 - - [02/Sep/2009:05:08:33 +0200] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"'
110
+ @nonsense_sample = 'addasdsasadadssadasd'
112
111
  end
113
112
 
114
113
  it "should have a valid language definitions" do
115
114
  @file_format.should be_valid
116
115
  end
117
116
 
118
- it "should parse a valid access log line" do
119
- @file_format.line_definitions[:access].matches(@sample_1).should be_kind_of(Hash)
120
- end
121
-
122
117
  it "should not parse a valid access log line" do
123
- @file_format.line_definitions[:access].matches('addasdsasadadssadasd').should be_false
118
+ @file_format.should_not parse_line(@nonsense_sample)
124
119
  end
125
120
 
126
121
  it "should read the correct values from a valid 404 access log line" do
127
- @log_parser.parse_io(StringIO.new(@sample_1)) do |request|
128
- request[:remote_host].should == '127.0.0.1'
129
- request[:timestamp].should == 20090916064008
130
- request[:http_status].should == 500
131
- request[:http_method].should == 'GET'
132
- request[:http_version].should == '1.1'
133
- request[:bytes_sent].should == 63183
134
- request[:user].should == nil
135
- request[:duration].should == 0.0453
122
+ @file_format.should parse_line(@sample_1).as(:access).and_capture(
123
+ :remote_host => '69.41.0.45',
124
+ :remote_logname => nil,
125
+ :user => nil,
126
+ :timestamp => 20090902120240,
127
+ :http_status => 404,
128
+ :http_method => 'GET',
129
+ :http_version => '1.1',
130
+ :bytes_sent => 209,
131
+ :referer => nil,
132
+ :user_agent => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)')
133
+ end
134
+
135
+ it "should read the correct values from a valid 200 access log line" do
136
+ @file_format.should parse_line(@sample_2).as(:access).and_capture(
137
+ :remote_host => '10.0.1.1',
138
+ :remote_logname => nil,
139
+ :user => nil,
140
+ :timestamp => 20090902050833,
141
+ :http_status => 200,
142
+ :http_method => 'GET',
143
+ :http_version => '1.1',
144
+ :bytes_sent => 30,
145
+ :referer => nil,
146
+ :user_agent => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9')
147
+ end
148
+
149
+ it "should parse 5 request from fixture access log without warnings" do
150
+ request_counter.should_receive(:hit!).exactly(5).times
151
+ @log_parser.should_not_receive(:warn)
152
+
153
+ @log_parser.parse_file(log_fixture(:apache_combined)) do |request|
154
+ request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Apache::Request)
136
155
  end
137
156
  end
138
157
  end
139
-
140
- context '"Combined" access log parsing' do
141
-
142
- before(:all) do
143
- @file_format = RequestLogAnalyzer::FileFormat.load(:apache, :combined)
158
+
159
+ context '"Rack" access log parser' do
160
+ before(:each) do
161
+ @file_format = RequestLogAnalyzer::FileFormat.load(:rack)
144
162
  @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
145
- @sample_1 = '69.41.0.45 - - [02/Sep/2009:12:02:40 +0200] "GET //phpMyAdmin/ HTTP/1.1" 404 209 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"'
146
- @sample_2 = '10.0.1.1 - - [02/Sep/2009:05:08:33 +0200] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"'
163
+ @sample_1 = '127.0.0.1 - - [16/Sep/2009 07:40:08] "GET /favicon.ico HTTP/1.1" 500 63183 0.0453'
164
+ @sample_2 = '127.0.0.1 - - [01/Oct/2009 07:58:10] "GET / HTTP/1.1" 200 1 0.0045'
165
+ @nonsense_sample = 'addasdsasadadssadasd'
166
+ end
167
+
168
+ it "should create a kind of an Apache file format" do
169
+ @file_format.should be_kind_of(RequestLogAnalyzer::FileFormat::Apache)
147
170
  end
148
171
 
149
172
  it "should have a valid language definitions" do
150
173
  @file_format.should be_valid
151
174
  end
152
175
 
153
- it "should parse a valid access log line" do
154
- @file_format.line_definitions[:access].matches(@sample_1).should be_kind_of(Hash)
176
+ it "should parse a valid access log line with status 500" do
177
+ @file_format.should parse_line(@sample_1).as(:access).and_capture(
178
+ :remote_host => '127.0.0.1', :timestamp => 20090916074008, :user => nil,
179
+ :http_status => 500, :http_method => 'GET', :http_version => '1.1',
180
+ :duration => 0.0453, :bytes_sent => 63183, :remote_logname => nil)
155
181
  end
156
182
 
157
- it "should not parse a valid access log line" do
158
- @file_format.line_definitions[:access].matches('addasdsasadadssadasd').should be_false
183
+ it "should parse a valid access log line with status 200" do
184
+ @file_format.should parse_line(@sample_2).as(:access).and_capture(
185
+ :remote_host => '127.0.0.1', :timestamp => 20091001075810, :user => nil,
186
+ :http_status => 200, :http_method => 'GET', :http_version => '1.1',
187
+ :duration => 0.0045, :bytes_sent => 1, :remote_logname => nil)
159
188
  end
160
189
 
161
- it "should read the correct values from a valid 404 access log line" do
162
- @log_parser.parse_io(StringIO.new(@sample_1)) do |request|
163
- request[:remote_host].should == '69.41.0.45'
164
- request[:timestamp].should == 20090902120240
165
- request[:http_status].should == 404
166
- request[:http_method].should == 'GET'
167
- request[:http_version].should == '1.1'
168
- request[:bytes_sent].should == 209
169
- request[:referer].should == nil
170
- request[:user].should == nil
171
- request[:user_agent].should == 'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)'
172
- end
190
+ it "should not parse an invalid access log line" do
191
+ @file_format.should_not parse_line(@nonsense_sample)
173
192
  end
174
193
 
175
- it "should read the correct values from a valid 200 access log line" do
176
- @log_parser.parse_io(StringIO.new(@sample_2)) do |request|
177
- request[:remote_host].should == '10.0.1.1'
178
- request[:timestamp].should == 20090902050833
179
- request[:http_status].should == 200
180
- request[:http_method].should == 'GET'
181
- request[:http_version].should == '1.1'
182
- request[:bytes_sent].should == 30
183
- request[:referer].should == nil
184
- request[:user].should == nil
185
- request[:user_agent].should == 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9'
194
+ it "should parse 2 Apache requests from a sample without warnings" do
195
+ request_counter.should_receive(:hit!).twice
196
+ @log_parser.should_not_receive(:warn)
197
+
198
+ @log_parser.parse_io(log_stream(@sample_1, @nonsense_sample, @sample_2)) do |request|
199
+ request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Apache::Request)
186
200
  end
187
201
  end
188
-
189
- it "should parse 5 request from fixture access log" do
190
- counter = mock('counter')
191
- counter.should_receive(:hit!).exactly(5).times
192
- @log_parser.parse_file(log_fixture(:apache_combined)) { counter.hit! }
193
- end
194
202
  end
195
203
  end
196
-
@@ -120,35 +120,32 @@ describe RequestLogAnalyzer::FileFormat::Rails do
120
120
  end
121
121
 
122
122
  it "should parse a Rails 2.1 style log and find valid Rails requests without warnings" do
123
+ request_counter.should_receive(:hit!).exactly(4).times
123
124
  @log_parser.should_not_receive(:warn)
125
+
124
126
  @log_parser.parse_file(log_fixture(:rails_1x)) do |request|
125
- request.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails::Request)
126
- request.should be_completed
127
+ request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
127
128
  end
128
129
  end
129
130
 
130
131
  it "should parse a Rails 2.2 style log and find valid Rails requests without warnings" do
132
+ request_counter.should_receive(:hit!).once
131
133
  @log_parser.should_not_receive(:warn)
134
+
132
135
  @log_parser.parse_file(log_fixture(:rails_22)) do |request|
133
- request.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails::Request)
134
- request.should be_completed
136
+ request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
135
137
  end
136
138
  end
137
139
 
138
140
  it "should parse a Rails SyslogLogger file with prefix and find valid requests without warnings" do
141
+ request_counter.should_receive(:hit!).once
139
142
  @log_parser.should_not_receive(:warn)
143
+
140
144
  @log_parser.parse_file(log_fixture(:syslog_1x)) do |request|
141
- request.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails::Request)
142
- request.should be_completed
145
+ request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
143
146
  end
144
147
  end
145
148
 
146
- it "should find 4 completed requests" do
147
- @log_parser.should_not_receive(:warn)
148
- @log_parser.should_receive(:handle_request).exactly(4).times
149
- @log_parser.parse_file(log_fixture(:rails_1x))
150
- end
151
-
152
149
  it "should parse cached requests" do
153
150
  @log_parser.should_not_receive(:warn)
154
151
  @log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
@@ -116,7 +116,7 @@ describe RequestLogAnalyzer::Tracker::Base do
116
116
  end
117
117
 
118
118
  it "should receive :to_yaml object when finalizing" do
119
- @summarizer.options[:dump] = temp_output_file(:dump)
119
+ @summarizer.options[:yaml] = temp_output_file(:yaml)
120
120
  @tracker.should_receive(:to_yaml_object).once
121
121
  @summarizer.to_yaml
122
122
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: request-log-analyzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Bergen
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-09-30 00:00:00 +02:00
13
+ date: 2009-10-03 00:00:00 +02:00
14
14
  default_executable: request-log-analyzer
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -94,6 +94,7 @@ files:
94
94
  - spec/unit/tracker/tracker_api_spec.rb
95
95
  - spec/unit/tracker/duration_tracker_spec.rb
96
96
  - spec/unit/file_format/amazon_s3_format_spec.rb
97
+ - spec/integration/scout_spec.rb
97
98
  - lib/request_log_analyzer/aggregator/echo.rb
98
99
  - spec/unit/mailer_spec.rb
99
100
  - spec/unit/controller/log_processor_spec.rb
@@ -137,9 +138,11 @@ files:
137
138
  - lib/request_log_analyzer/file_format/apache.rb
138
139
  - spec/fixtures/decompression.log.zip
139
140
  - spec/unit/source/log_parser_spec.rb
141
+ - spec/integration/scouts_custom_output.rb
140
142
  - spec/fixtures/test_file_format.log
141
143
  - tasks/github-gem.rake
142
144
  - spec/unit/database/database_spec.rb
145
+ - spec/integration/munin_plugins_rails_spec.rb
143
146
  - lib/request_log_analyzer/tracker/duration.rb
144
147
  - lib/request_log_analyzer/tracker/traffic.rb
145
148
  - lib/request_log_analyzer/file_format.rb
@@ -197,6 +200,7 @@ test_files:
197
200
  - spec/unit/tracker/tracker_api_spec.rb
198
201
  - spec/unit/tracker/duration_tracker_spec.rb
199
202
  - spec/unit/file_format/amazon_s3_format_spec.rb
203
+ - spec/integration/scout_spec.rb
200
204
  - spec/unit/mailer_spec.rb
201
205
  - spec/unit/controller/log_processor_spec.rb
202
206
  - spec/unit/filter/filter_spec.rb
@@ -211,6 +215,7 @@ test_files:
211
215
  - spec/unit/controller/controller_spec.rb
212
216
  - spec/unit/source/log_parser_spec.rb
213
217
  - spec/unit/database/database_spec.rb
218
+ - spec/integration/munin_plugins_rails_spec.rb
214
219
  - spec/unit/aggregator/summarizer_spec.rb
215
220
  - spec/unit/tracker/frequency_tracker_spec.rb
216
221
  - spec/unit/file_format/rails_format_spec.rb