request-log-analyzer 1.2.3 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .svn/
2
+ .DS_Store
3
+ request-log-analyzer-*.gem
4
+ requests.db
5
+ /pkg
6
+ /doc
7
+ /tmp
8
+ /classes
9
+ /files
10
+ /coverage
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
1
  Dir[File.dirname(__FILE__) + "/tasks/*.rake"].each { |file| load(file) }
2
+
3
+ GithubGem::RakeTasks.new(:gem)
2
4
 
3
- task :default => "spec:fancy"
5
+ task :default => "spec:specdoc"
@@ -11,7 +11,7 @@ module RequestLogAnalyzer
11
11
 
12
12
  # The current version of request-log-analyzer.
13
13
  # This will be diplayed in output reports etc.
14
- VERSION = '1.2.1'
14
+ VERSION = "1.2.6"
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.
@@ -46,6 +46,7 @@ module RequestLogAnalyzer::Aggregator
46
46
  def finalize
47
47
  @request_count = orm_module::Request.count
48
48
  remove_database_connection!
49
+ deinitialize_orm_module!
49
50
  end
50
51
 
51
52
  # Records w warining in the warnings table.
@@ -64,6 +65,11 @@ module RequestLogAnalyzer::Aggregator
64
65
  output << "\n"
65
66
  end
66
67
 
68
+ # Retreives the connection that is used for the database inserter
69
+ def connection
70
+ orm_module::Base.connection
71
+ end
72
+
67
73
  protected
68
74
 
69
75
  # Create a module and a default subclass of ActiveRecord::Base on which to establish the database connection
@@ -79,16 +85,22 @@ module RequestLogAnalyzer::Aggregator
79
85
  orm_base_class.abstract_class = true
80
86
  orm_module.const_set('Base', orm_base_class)
81
87
  end
82
- end
83
-
88
+ end
89
+
90
+ # Deinitializes the ORM module and the ActiveRecord::Base subclass.
91
+ def deinitialize_orm_module!
92
+ file_format.class.send(:remove_const, 'Database') if file_format.class.const_defined?('Database')
93
+ @orm_module = nil
94
+ end
95
+
84
96
  # Established a connection with the database for this session
85
97
  def establish_database_connection!
86
98
  orm_module::Base.establish_connection(:adapter => 'sqlite3', :database => options[:database])
87
- ActiveRecord::Migration.class_eval("def self.connection; #{@orm_module.to_s}::Base.connection; end ")
88
- end
89
-
99
+ #ActiveRecord::Migration.class_eval("def self.connection; #{@orm_module.to_s}::Base.connection; end ")
100
+ end
101
+
90
102
  def remove_database_connection!
91
- ActiveRecord::Migration.class_eval("def self.connection; ActiveRecord::Base.connection; end ")
103
+ #ActiveRecord::Migration.class_eval("def self.connection; ActiveRecord::Base.connection; end ")
92
104
  orm_module::Base.remove_connection
93
105
  end
94
106
 
@@ -97,8 +109,7 @@ module RequestLogAnalyzer::Aggregator
97
109
  # what line in the original file the line was found, and a request_id to link lines related
98
110
  # to the same request. It will also create an index in the request_id field to speed up queries.
99
111
  def create_database_table(definition)
100
- ActiveRecord::Migration.verbose = options[:debug] # keep it down a notch please
101
- ActiveRecord::Migration.create_table("#{definition.name}_lines") do |t|
112
+ connection.create_table("#{definition.name}_lines") do |t|
102
113
 
103
114
  # Add default fields for every line type
104
115
  t.column(:request_id, :integer)
@@ -114,7 +125,7 @@ module RequestLogAnalyzer::Aggregator
114
125
  end
115
126
 
116
127
  # Create an index on the request_id column to support faster querying
117
- ActiveRecord::Migration.add_index("#{definition.name}_lines", [:request_id])
128
+ connection.add_index("#{definition.name}_lines", [:request_id])
118
129
  end
119
130
 
120
131
  # Creates an ActiveRecord class for a given line definition.
@@ -126,8 +137,8 @@ module RequestLogAnalyzer::Aggregator
126
137
  klass = Class.new(orm_module::Base)
127
138
  klass.send(:belongs_to, :request)
128
139
 
129
- definition.captures.each do |capture|
130
- klass.send(:serialize, capture[:name], Hash) if capture[:provides]
140
+ definition.captures.select { |c| c.has_key?(:provides) }.each do |capture|
141
+ klass.send(:serialize, capture[:name], Hash)
131
142
  end
132
143
 
133
144
  orm_module.const_set(class_name, klass) unless orm_module.const_defined?(class_name)
@@ -137,10 +148,9 @@ module RequestLogAnalyzer::Aggregator
137
148
  # Creates a requests table, in which a record is created for every request. It also creates an
138
149
  # ActiveRecord::Base class to communicate with this table.
139
150
  def create_request_table_and_class
140
- ActiveRecord::Migration.verbose = options[:debug]
141
- ActiveRecord::Migration.create_table("requests") do |t|
142
- t.integer :first_lineno
143
- t.integer :last_lineno
151
+ connection.create_table("requests") do |t|
152
+ t.column :first_lineno, :integer
153
+ t.column :last_lineno, :integer
144
154
  end
145
155
 
146
156
  orm_module.const_set('Request', Class.new(orm_module::Base)) unless orm_module.const_defined?('Request')
@@ -149,11 +159,10 @@ module RequestLogAnalyzer::Aggregator
149
159
 
150
160
  # Creates a warnings table and a corresponding Warning class to communicate with this table using ActiveRecord.
151
161
  def create_warning_table_and_class
152
- ActiveRecord::Migration.verbose = options[:debug]
153
- ActiveRecord::Migration.create_table("warnings") do |t|
154
- t.string :warning_type, :limit => 30, :null => false
155
- t.string :message
156
- t.integer :lineno
162
+ connection.create_table("warnings") do |t|
163
+ t.column :warning_type, :string, :limit => 30, :null => false
164
+ t.column :message, :string
165
+ t.column :lineno, :integer
157
166
  end
158
167
 
159
168
  orm_module.const_set('Warning', Class.new(orm_module::Base)) unless orm_module.const_defined?('Warning')
@@ -16,18 +16,16 @@ module RequestLogAnalyzer::FileFormat
16
16
  line.teaser = /Params/
17
17
  line.regexp = /Params\:\ (\{.+\})/
18
18
  line.captures << { :name => :params, :type => :eval, :provides => {
19
- :namespace => :string, :controller => :string, :action => :string, :format => :string } }
19
+ :namespace => :string, :controller => :string, :action => :string, :format => :string, :method => :string } }
20
20
  end
21
21
 
22
22
  # ~ {:dispatch_time=>0.006117, :after_filters_time=>6.1e-05, :before_filters_time=>0.000712, :action_time=>0.005833}
23
23
  line_definition :completed do |line|
24
24
  line.footer = true
25
- line.teaser = /\{:dispatch_time/
26
- line.regexp = /\{\:dispatch_time=>(\d+\.\d+(?:e-?\d+)?), (?:\:after_filters_time=>(\d+\.\d+(?:e-?\d+)?), )?(?:\:before_filters_time=>(\d+\.\d+(?:e-?\d+)?), )?\:action_time=>(\d+\.\d+(?:e-?\d+)?)\}/
27
- line.captures << { :name => :dispatch_time, :type => :duration } \
28
- << { :name => :after_filters_time, :type => :duration } \
29
- << { :name => :before_filters_time, :type => :duration } \
30
- << { :name => :action_time, :type => :duration }
25
+ line.regexp = /(\{.*\:dispatch_time\s*=>\s*\d+\.\d+.*\})/
26
+ line.captures << { :name => :times_hash, :type => :eval, :provides => {
27
+ :dispatch_time => :duration, :after_filters_time => :duration,
28
+ :before_filters_time => :duration, :action_time => :duration } }
31
29
  end
32
30
 
33
31
  REQUEST_CATEGORIZER = Proc.new do |request|
@@ -145,11 +145,11 @@ module RequestLogAnalyzer
145
145
  end
146
146
 
147
147
  def first_lineno
148
- @lines.first[:lineno]
148
+ @lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.min
149
149
  end
150
150
 
151
151
  def last_lineno
152
- @lines.last[:lineno]
152
+ @lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.max
153
153
  end
154
154
  end
155
155
  end
@@ -0,0 +1,36 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'request-log-analyzer'
3
+ s.version = "1.2.6"
4
+ s.date = "2009-09-02"
5
+
6
+ s.rubyforge_project = 'r-l-a'
7
+
8
+ s.bindir = 'bin'
9
+ s.executables = ['request-log-analyzer']
10
+ s.default_executable = 'request-log-analyzer'
11
+
12
+ s.summary = "A command line tool to analyze request logs for Rails, Merb and other application servers"
13
+ s.description = <<-eos
14
+ Request log analyzer's purpose is to find ot how your web application is being used and to focus your optimization efforts.
15
+ This tool will parse all requests in the application's log file and aggregate the information. Once it is finished parsing
16
+ the log file(s), it will show the requests that take op most server time using various metrics. It can also insert all
17
+ parsed request information into a database so you can roll your own analysis. It supports Rails- and Merb-based applications
18
+ out of the box, but file formats of other applications can easily be supported by supplying an easy to write log file format
19
+ definition.
20
+ eos
21
+
22
+ s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
23
+ s.extra_rdoc_files = ['README.rdoc']
24
+
25
+ s.requirements << "To use the database inserter, ActiveRecord and an appropriate database adapter are required."
26
+
27
+ s.add_development_dependency('rspec', '>= 1.2.4')
28
+ s.add_development_dependency('git', '>= 1.1.0')
29
+
30
+ s.authors = ['Willem van Bergen', 'Bart ten Brinke']
31
+ s.email = ['willem@railsdoctors.com', 'bart@railsdoctors.com']
32
+ s.homepage = 'http://railsdoctors.com'
33
+
34
+ s.files = %w(spec/unit/filter/anonymize_filter_spec.rb lib/request_log_analyzer/line_definition.rb lib/request_log_analyzer/output/html.rb lib/request_log_analyzer/controller.rb spec/fixtures/rails_22_cached.log lib/request_log_analyzer/file_format/rails_development.rb spec/lib/macros.rb spec/fixtures/merb_prefixed.log tasks/request_log_analyzer.rake spec/unit/file_format/file_format_api_spec.rb spec/integration/command_line_usage_spec.rb spec/fixtures/decompression.log.bz2 lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/filter.rb spec/fixtures/rails_unordered.log bin/request-log-analyzer request-log-analyzer.gemspec DESIGN.rdoc spec/unit/filter/timespan_filter_spec.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/matchers.rb spec/fixtures/test_order.log lib/request_log_analyzer/output/fixed_width.rb lib/request_log_analyzer/filter/anonymize.rb spec/lib/testing_format.rb lib/request_log_analyzer/tracker/timespan.rb lib/request_log_analyzer/aggregator.rb lib/cli/progressbar.rb README.rdoc 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 lib/request_log_analyzer/aggregator/echo.rb spec/unit/controller/log_processor_spec.rb lib/request_log_analyzer.rb Rakefile spec/spec_helper.rb spec/unit/filter/filter_spec.rb lib/request_log_analyzer/aggregator/summarizer.rb lib/request_log_analyzer/file_format/rails.rb spec/fixtures/test_language_combined.log spec/fixtures/decompression.tar.gz spec/unit/filter/field_filter_spec.rb spec/spec.opts lib/request_log_analyzer/aggregator/database.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 spec/unit/controller/controller_spec.rb lib/request_log_analyzer/output.rb spec/lib/helpers.rb spec/fixtures/rails_1x.log spec/lib/mocks.rb spec/fixtures/decompression.log.zip spec/unit/source/request_spec.rb spec/unit/source/log_parser_spec.rb spec/fixtures/test_file_format.log lib/request_log_analyzer/source/database.rb spec/unit/aggregator/database_spec.rb tasks/github-gem.rake lib/request_log_analyzer/tracker/duration.rb lib/request_log_analyzer/file_format.rb spec/unit/aggregator/summarizer_spec.rb spec/fixtures/rails_22.log spec/fixtures/multiple_files_2.log spec/fixtures/syslog_1x.log LICENSE spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb lib/cli/command_line_arguments.rb)
35
+ s.test_files = %w(spec/unit/filter/anonymize_filter_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/integration/command_line_usage_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/filter_spec.rb spec/unit/filter/field_filter_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/controller/controller_spec.rb spec/unit/source/request_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/aggregator/database_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb)
36
+ end
@@ -0,0 +1,9 @@
1
+ Aug 31 18:35:23 typekit-web001 merb: ~
2
+ Aug 31 18:35:23 typekit-web001 merb: cache: [GET /] miss
3
+ Aug 31 18:35:24 typekit-web001 merb: ~ Started request handling: Mon Aug 31 18:35:25 +0000 2009
4
+ Aug 31 18:35:24 typekit-web001 merb: ~ Routed to: {"action"=>"index", "controller"=>"home"}
5
+ Aug 31 18:35:24 typekit-web001 merb: ~ Params: {"action"=>"index", "controller"=>"home"}
6
+ Aug 31 18:35:24 typekit-web001 merb: ~ In repository block default
7
+ Aug 31 18:35:24 typekit-web001 merb: ~ (0.000000) SELECT `id`, `created_at`, `updated_at`, `braintree_vault_id`, `cancelled_at` FROM `accounts` WHERE (`id` IN (6214)) ORDER BY `id`
8
+ Aug 31 18:35:24 typekit-web001 merb: ~ Redirecting to: /plans (302)
9
+ Aug 31 18:35:24 typekit-web001 merb: ~ {:after_filters_time=>0.0, :before_filters_time=>0.0, :dispatch_time=>0.012001, :action_time=>0.012001}
data/spec/lib/mocks.rb CHANGED
@@ -38,10 +38,21 @@ module RequestLogAnalyzer::Spec::Mocks
38
38
  output.stub!(:title)
39
39
  output.stub!(:line)
40
40
  output.stub!(:with_style)
41
- output.stub!(:table) { yield [] }
41
+ output.stub!(:table).and_yield([])
42
42
  output.stub!(:io).and_return(mock_io)
43
43
  return output
44
44
  end
45
45
 
46
+ def mock_migrator
47
+ table_creator = mock('ActiveRecord table creator')
48
+ table_creator.stub!(:column)
49
+
50
+ migrator = mock('ActiveRecord::Base.connection for migrations')
51
+ migrator.stub!(:add_index)
52
+ migrator.stub!(:create_table).and_yield(table_creator).and_return(true)
53
+ migrator.stub!(:table_creator).and_return(table_creator)
54
+ return migrator
55
+ end
56
+
46
57
 
47
58
  end
@@ -2,13 +2,13 @@ require File.dirname(__FILE__) + '/../../spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Aggregator::Database do
4
4
 
5
- before(:each) do
5
+ before(:all) do
6
6
  log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format)
7
7
  @database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => ':memory:')
8
8
 
9
9
  @line_definition = RequestLogAnalyzer::LineDefinition.new(:test, { :regexp => /Testing (\w+), tries\: (\d+)/,
10
10
  :captures => [{ :name => :what, :type => :string }, { :name => :tries, :type => :integer },
11
- { :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
11
+ { :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
12
12
  end
13
13
 
14
14
  # The prepare method is called before the parsing starts. It should establish a connection
@@ -16,12 +16,18 @@ describe RequestLogAnalyzer::Aggregator::Database do
16
16
  describe '#prepare' do
17
17
 
18
18
  before(:each) do
19
- @database_inserter.stub!(:establish_database_connection!)
19
+ @database_inserter.stub!(:initialize_orm_module!)
20
+ @database_inserter.stub!(:establish_database_connection!)
20
21
  @database_inserter.stub!(:create_database_schema!)
21
22
  end
22
23
 
24
+ it 'should create the ORM mdoule in which the classes can be created' do
25
+ @database_inserter.should_receive(:initialize_orm_module!)
26
+ @database_inserter.prepare
27
+ end
28
+
23
29
  it 'should establish the database connection' do
24
- @database_inserter.should_receive(:establish_database_connection!)
30
+ @database_inserter.should_receive(:establish_database_connection!)
25
31
  @database_inserter.prepare
26
32
  end
27
33
 
@@ -31,48 +37,70 @@ describe RequestLogAnalyzer::Aggregator::Database do
31
37
  end
32
38
  end
33
39
 
40
+ # The database inserter creates is own "Database" module within the file format
41
+ # class to create all the classes that are needed.
42
+ describe '#initialize_orm_module!' do
43
+
44
+ before(:all) { @database_inserter.send(:deinitialize_orm_module!) }
45
+ after(:all) { @database_inserter.send(:initialize_orm_module!) }
46
+
47
+ before(:each) { @database_inserter.send(:initialize_orm_module!) }
48
+ after(:each) { @database_inserter.send(:deinitialize_orm_module!) }
49
+
50
+ it "should create a Database module under the file format's class" do
51
+ testing_format.class.should be_const_defined('Database')
52
+ end
53
+
54
+ it "should define a Base class in the Database module" do
55
+ testing_format.class::Database.should be_const_defined('Base')
56
+ end
57
+
58
+ it "should create a ActiveRecord::Base class in the Database module" do
59
+ testing_format.class::Database::Base.ancestors.should include(ActiveRecord::Base)
60
+ end
61
+
62
+ end
63
+
34
64
  # The create_database_table method should create a database table according to the line definition,
35
65
  # so that parsed lines can be stored in it later on.
36
66
  describe '#create_database_table' do
37
67
 
38
68
  before(:each) do
39
- @table_creator = mock('create_table block')
40
- @table_creator.stub!(:column)
41
- ActiveRecord::Migration.stub!(:create_table).and_yield(@table_creator)
42
- ActiveRecord::Migration.stub!(:add_index)
69
+ @connection = mock_migrator
70
+ @database_inserter.stub!(:connection).and_return(@connection)
43
71
  end
44
72
 
45
73
  it "should create a table based on the line type name" do
46
- ActiveRecord::Migration.should_receive(:create_table).with('test_lines')
74
+ @connection.should_receive(:create_table).with('test_lines')
47
75
  @database_inserter.send(:create_database_table, @line_definition)
48
76
  end
49
77
 
50
78
  it "should create an index on the request_id field" do
51
- ActiveRecord::Migration.should_receive(:add_index).with('test_lines', [:request_id])
79
+ @connection.should_receive(:add_index).with('test_lines', [:request_id])
52
80
  @database_inserter.send(:create_database_table, @line_definition)
53
81
  end
54
82
 
55
83
  it "should create a request_id field to link the requests together" do
56
- @table_creator.should_receive(:column).with(:request_id, :integer)
84
+ @connection.table_creator.should_receive(:column).with(:request_id, :integer)
57
85
  @database_inserter.send(:create_database_table, @line_definition)
58
86
  end
59
87
 
60
88
  it "should create a lineno field to save the location of the line in the original file" do
61
- @table_creator.should_receive(:column).with(:lineno, :integer)
89
+ @connection.table_creator.should_receive(:column).with(:lineno, :integer)
62
90
  @database_inserter.send(:create_database_table, @line_definition)
63
91
  end
64
92
 
65
93
  it "should create a field of the correct type for every defined field" do
66
- @table_creator.should_receive(:column).with(:what, :string)
67
- @table_creator.should_receive(:column).with(:tries, :integer)
94
+ @connection.table_creator.should_receive(:column).with(:what, :string)
95
+ @connection.table_creator.should_receive(:column).with(:tries, :integer)
68
96
  # :hash capture type should map on a :text field type
69
- @table_creator.should_receive(:column).with(:evaluated, :text)
97
+ @connection.table_creator.should_receive(:column).with(:evaluated, :text)
70
98
  @database_inserter.send(:create_database_table, @line_definition)
71
99
  end
72
100
 
73
101
  it "should create a field of the correct type for every provided field" do
74
102
  # :duration capture type should map on a :double field type
75
- @table_creator.should_receive(:column).with(:evaluated_field, :double)
103
+ @connection.table_creator.should_receive(:column).with(:evaluated_field, :double)
76
104
  @database_inserter.send(:create_database_table, @line_definition)
77
105
  end
78
106
  end
@@ -129,21 +157,19 @@ describe RequestLogAnalyzer::Aggregator::Database do
129
157
  before(:each) do
130
158
  @line_type_cnt = testing_format.line_definitions.length
131
159
 
132
- #Make sure no actual migrations occur
133
- ActiveRecord::Migration.stub!(:add_index)
134
- ActiveRecord::Migration.stub!(:create_table)
160
+ @connection = mock_migrator
161
+ @database_inserter.stub!(:connection).and_return(@connection)
135
162
 
136
163
  # Stub the expected method calls for the preparation
137
164
  @database_inserter.stub!(:create_database_table)
138
165
  @database_inserter.stub!(:create_activerecord_class)
139
166
 
140
-
141
167
  # Make sure the ORM module exists
142
168
  @database_inserter.send(:initialize_orm_module!)
143
169
  end
144
170
 
145
171
  it "should create a requests table to join request lines" do
146
- ActiveRecord::Migration.should_receive(:create_table).with("requests")
172
+ @connection.should_receive(:create_table).with("requests")
147
173
  @database_inserter.send :create_database_schema!
148
174
  end
149
175
 
@@ -153,7 +179,7 @@ describe RequestLogAnalyzer::Aggregator::Database do
153
179
  end
154
180
 
155
181
  it "should create a warnings table for logging parse warnings" do
156
- ActiveRecord::Migration.should_receive(:create_table).with("warnings")
182
+ @connection.should_receive(:create_table).with("warnings")
157
183
  @database_inserter.send :create_database_schema!
158
184
  end
159
185
 
@@ -23,15 +23,34 @@ describe RequestLogAnalyzer::Source::LogParser, :merb do
23
23
  @log_parser.parse_file(log_fixture(:merb))
24
24
  end
25
25
 
26
- it "should parse all details from a request correctly" do
26
+ it "should parse all details from the first request correctly" do
27
27
  request = nil
28
28
  @log_parser.parse_file(log_fixture(:merb)) { |found_request| request ||= found_request }
29
29
 
30
30
  request.should be_completed
31
+ request[:controller].should == 'session'
32
+ request[:action].should == 'destroy'
33
+ request[:method].should == 'delete'
34
+ request[:params].should be_kind_of(Hash)
31
35
  request[:timestamp].should == 20080829111023 # 'Fri Aug 29 11:10:23 +0200 2008'
32
36
  request[:dispatch_time].should == 0.243424
33
37
  request[:after_filters_time].should == 6.9e-05
34
38
  request[:before_filters_time].should == 0.213213
35
39
  request[:action_time].should == 0.241652
40
+
41
+ end
42
+
43
+ it "should parse a prefixed Merb file correctly" do
44
+ request = nil
45
+ @log_parser.parse_file(log_fixture(:merb_prefixed)) { |found_request| request ||= found_request }
46
+
47
+ request.should be_completed
48
+ request[:timestamp].should == 20090831183525
49
+ request[:controller].should == 'home'
50
+ request[:action].should == 'index'
51
+ request[:dispatch_time].should == 0.012001
52
+ request[:after_filters_time].should == 0.0
53
+ request[:before_filters_time].should == 0.0
54
+ request[:action_time].should == 0.012001
36
55
  end
37
56
  end
@@ -1,85 +1,111 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
 
3
- describe RequestLogAnalyzer::Request, :incomplete_request do
3
+ describe RequestLogAnalyzer::Request do
4
4
 
5
5
  before(:each) do
6
- @incomplete_request = testing_format.request
7
- @incomplete_request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
8
- end
9
-
10
- it "should be single if only one line has been added" do
11
- @incomplete_request.should_not be_empty
12
- end
13
-
14
- it "should not be a completed request" do
15
- @incomplete_request.should_not be_completed
6
+ @request = testing_format.request
16
7
  end
17
8
 
18
- it "should take the line type of the first line as global line_type" do
19
- @incomplete_request.lines[0][:line_type].should == :test
20
- @incomplete_request.should =~ :test
9
+ it "should be empty without any captured lines in it" do
10
+ @request.should be_empty
21
11
  end
22
12
 
23
- it "should return the first field value" do
24
- @incomplete_request[:test_capture].should == 'awesome!'
25
- end
26
-
27
- it "should return nil if no such field is present" do
28
- @incomplete_request[:nonexisting].should be_nil
29
- end
30
- end
31
-
32
-
33
- describe RequestLogAnalyzer::Request, :completed_request do
13
+ context :incomplete do
34
14
 
35
- before(:each) do
36
- @completed_request = testing_format.request
37
- @completed_request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
38
- @completed_request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
39
- @completed_request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
40
- @completed_request << { :line_type => :last, :lineno => 10, :time => 0.03 }
41
- end
15
+ before(:each) do
16
+ @request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
17
+ end
42
18
 
43
- it "should not be empty when multiple liness are added" do
44
- @completed_request.should_not be_empty
45
- end
19
+ it "should be single if only one line has been added" do
20
+ @request.should_not be_empty
21
+ end
46
22
 
47
- it "should be a completed request" do
48
- @completed_request.should be_completed
49
- end
23
+ it "should not be a completed request" do
24
+ @request.should_not be_completed
25
+ end
50
26
 
51
- it "should recognize all line types" do
52
- [:first, :test, :last].each { |type| @completed_request.should =~ type }
53
- end
27
+ it "should take the line type of the first line as global line_type" do
28
+ @request.lines[0][:line_type].should == :test
29
+ @request.should =~ :test
30
+ end
54
31
 
55
- it "should detect the correct field value" do
56
- @completed_request[:name].should == 'first line!'
57
- @completed_request[:time].should == 0.03
58
- end
32
+ it "should return the first field value" do
33
+ @request[:test_capture].should == 'awesome!'
34
+ end
59
35
 
60
- it "should detect the first matching field value" do
61
- @completed_request.first(:test_capture).should == 'testing'
36
+ it "should return nil if no such field is present" do
37
+ @request[:nonexisting].should be_nil
38
+ end
62
39
  end
63
40
 
64
- it "should detect the every matching field value" do
65
- @completed_request.every(:test_capture).should == ['testing', "testing some more"]
66
- end
67
-
68
- it "should set the first_lineno for a request to the lowest lineno encountered" do
69
- @completed_request.first_lineno.should eql(1)
70
- end
41
+ context :completed do
42
+
43
+ before(:each) do
44
+ @request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
45
+ @request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
46
+ @request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
47
+ @request << { :line_type => :last, :lineno => 10, :time => 0.03 }
48
+ end
71
49
 
72
- it "should set the last_lineno for a request to the highest encountered lineno" do
73
- @completed_request.last_lineno.should eql(10)
74
- end
50
+ it "should not be empty when multiple liness are added" do
51
+ @request.should_not be_empty
52
+ end
75
53
 
76
- it "should not have a timestamp if no such field is captured" do
77
- @completed_request.timestamp.should be_nil
78
- end
54
+ it "should be a completed request" do
55
+ @request.should be_completed
56
+ end
57
+
58
+ it "should recognize all line types" do
59
+ [:first, :test, :last].each { |type| @request.should =~ type }
60
+ end
61
+
62
+ it "should detect the correct field value" do
63
+ @request[:name].should == 'first line!'
64
+ @request[:time].should == 0.03
65
+ end
66
+
67
+ it "should detect the first matching field value" do
68
+ @request.first(:test_capture).should == 'testing'
69
+ end
79
70
 
80
- it "should set return a timestamp field if such a field is captured" do
81
- @completed_request << { :line_type => :first, :lineno => 1, :name => 'first line!', :timestamp => Time.now}
82
- @completed_request.timestamp.should_not be_nil
71
+ it "should detect the every matching field value" do
72
+ @request.every(:test_capture).should == ['testing', "testing some more"]
73
+ end
74
+
75
+ it "should set the first_lineno for a request to the lowest lineno encountered" do
76
+ @request.first_lineno.should eql(1)
77
+ end
78
+
79
+ it "should set the first_lineno for a request if a line with a lower lineno is added" do
80
+ @request << { :line_type => :test, :lineno => 0 }
81
+ @request.first_lineno.should eql(0)
82
+ end
83
+
84
+ it "should set the last_lineno for a request to the highest encountered lineno" do
85
+ @request.last_lineno.should eql(10)
86
+ end
87
+
88
+ it "should not set the last_lineno for a request if a line with a lower lineno is added" do
89
+ @request << { :line_type => :test, :lineno => 7 }
90
+ @request.last_lineno.should eql(10)
91
+ end
92
+
93
+ it "should not have a timestamp if no such field is captured" do
94
+ @request.timestamp.should be_nil
95
+ end
96
+
97
+ it "should set return a timestamp field if such a field is captured" do
98
+ @request << { :line_type => :first, :lineno => 1, :name => 'first line!', :timestamp => Time.now}
99
+ @request.timestamp.should_not be_nil
100
+ end
83
101
  end
84
102
 
85
- end
103
+ context 'single line' do
104
+ # combined is both a header and a footer line
105
+ before(:each) { @request << { :line_type => :combined, :lineno => 1 } }
106
+
107
+ it "should be a completed request if the line is both header and footer" do
108
+ @request.should be_completed
109
+ end
110
+ end
111
+ end