request-log-analyzer 1.2.3 → 1.2.6

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/.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