request-log-analyzer 1.4.0 → 1.4.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.
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