request-log-analyzer 1.10.0 → 1.11.0

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.
Files changed (49) hide show
  1. data/.gitignore +2 -1
  2. data/.infinity_test +8 -0
  3. data/bin/request-log-analyzer +0 -1
  4. data/lib/request_log_analyzer/aggregator/database_inserter.rb +2 -1
  5. data/lib/request_log_analyzer/aggregator.rb +5 -5
  6. data/lib/request_log_analyzer/controller.rb +0 -3
  7. data/lib/request_log_analyzer/database.rb +6 -7
  8. data/lib/request_log_analyzer/file_format/apache.rb +1 -1
  9. data/lib/request_log_analyzer/file_format/delayed_job2.rb +2 -2
  10. data/lib/request_log_analyzer/file_format/delayed_job21.rb +2 -2
  11. data/lib/request_log_analyzer/file_format/haproxy.rb +107 -13
  12. data/lib/request_log_analyzer/file_format/mysql.rb +5 -5
  13. data/lib/request_log_analyzer/file_format/rails3.rb +8 -1
  14. data/lib/request_log_analyzer/file_format.rb +43 -14
  15. data/lib/request_log_analyzer/filter.rb +4 -5
  16. data/lib/request_log_analyzer/line_definition.rb +6 -4
  17. data/lib/request_log_analyzer/output.rb +3 -5
  18. data/lib/request_log_analyzer/source/log_parser.rb +56 -4
  19. data/lib/request_log_analyzer/source.rb +3 -4
  20. data/lib/request_log_analyzer/tracker.rb +8 -8
  21. data/lib/request_log_analyzer.rb +15 -29
  22. data/request-log-analyzer.gemspec +3 -3
  23. data/spec/fixtures/mysql_slow_query.log +0 -1
  24. data/spec/integration/command_line_usage_spec.rb +0 -5
  25. data/spec/lib/helpers.rb +2 -2
  26. data/spec/lib/matchers.rb +38 -7
  27. data/spec/lib/mocks.rb +1 -5
  28. data/spec/unit/database/base_class_spec.rb +1 -0
  29. data/spec/unit/file_format/amazon_s3_format_spec.rb +58 -55
  30. data/spec/unit/file_format/apache_format_spec.rb +74 -162
  31. data/spec/unit/file_format/common_regular_expressions_spec.rb +51 -26
  32. data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -31
  33. data/spec/unit/file_format/delayed_job2_format_spec.rb +27 -32
  34. data/spec/unit/file_format/delayed_job_format_spec.rb +44 -63
  35. data/spec/unit/file_format/haproxy_format_spec.rb +69 -71
  36. data/spec/unit/file_format/line_definition_spec.rb +26 -33
  37. data/spec/unit/file_format/merb_format_spec.rb +22 -37
  38. data/spec/unit/file_format/mysql_format_spec.rb +80 -123
  39. data/spec/unit/file_format/oink_format_spec.rb +29 -61
  40. data/spec/unit/file_format/postgresql_format_spec.rb +2 -4
  41. data/spec/unit/file_format/rack_format_spec.rb +49 -44
  42. data/spec/unit/file_format/rails3_format_spec.rb +39 -37
  43. data/spec/unit/file_format/rails_format_spec.rb +52 -68
  44. data/spec/unit/file_format/w3c_format_spec.rb +40 -39
  45. data/spec/unit/source/log_parser_spec.rb +1 -1
  46. metadata +4 -6
  47. data/lib/mixins/gets_memory_protection.rb +0 -80
  48. data/lib/request_log_analyzer/output/fancy_html.rb +0 -44
  49. data/lib/request_log_analyzer/source/database_loader.rb +0 -87
@@ -5,186 +5,170 @@ describe RequestLogAnalyzer::FileFormat::Rails do
5
5
  describe '.create' do
6
6
 
7
7
  context 'without providing a lines argument' do
8
- before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails) }
8
+ subject { RequestLogAnalyzer::FileFormat::Rails.create }
9
9
 
10
- it "should create a valid file format" do
11
- @rails.should be_valid
12
- end
10
+ it { should be_well_formed }
11
+ it { should have(11).report_trackers }
13
12
 
14
- it "should parse the production lines" do
15
- production_rails = RequestLogAnalyzer::FileFormat.load(:rails, 'production')
16
- @rails.line_definitions.should == production_rails.line_definitions
13
+ it "should parse the lines in the production set" do
14
+ subject.line_definitions.should == RequestLogAnalyzer::FileFormat.load(:rails, 'production').line_definitions
17
15
  end
18
16
  end
19
17
 
20
18
  context 'using a comma separated list of lines as argument' do
21
- before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, 'minimal,failure') }
22
-
23
- it "should return a valid language" do
24
- @rails.should be_valid
25
- end
19
+ subject { RequestLogAnalyzer::FileFormat.load(:rails, 'minimal,failure') }
26
20
 
27
- it "should at least parse :processing and :completed lines" do
28
- @rails.line_definitions.should include(:processing, :completed, :failure)
29
- end
21
+ it { should be_well_formed }
22
+ it { should have(10).report_trackers }
23
+
24
+ it { should have_line_definition(:processing) }
25
+ it { should have_line_definition(:completed) }
26
+ it { should have_line_definition(:failure) }
30
27
  end
31
28
 
32
29
  RequestLogAnalyzer::FileFormat::Rails::LINE_COLLECTIONS.keys.each do |constant|
33
30
 
34
31
  context "using the '#{constant}' line collection constant" do
35
- before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, constant) }
32
+ subject { RequestLogAnalyzer::FileFormat.load(:rails, constant) }
36
33
 
37
- it "should return a valid language" do
38
- @rails.should be_valid
39
- end
34
+ it { should be_well_formed }
35
+ it { should have_at_least(9).report_trackers }
40
36
 
41
- it "should at least parse :processing and :completed lines" do
42
- @rails.line_definitions.should include(:processing, :completed)
43
- end
37
+ it { should have_line_definition(:processing) }
38
+ it { should have_line_definition(:completed) }
44
39
  end
45
40
  end
46
41
  end
42
+
43
+ subject { RequestLogAnalyzer::FileFormat.load(:rails, :all) }
47
44
 
48
45
  describe '#parse_line' do
49
- before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, :all) }
50
46
 
51
47
  {'with prefix' => 'LINE PREFIX: ', 'without prefix' => '' }.each do |context, prefix|
52
48
  context context do
53
49
  it "should parse a :processing line correctly" do
54
50
  line = prefix + 'Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]'
55
- @rails.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '1.1.1.1')
51
+ subject.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '1.1.1.1')
56
52
  end
57
53
 
58
54
  it "should parse a :processing line correctly when it contains ipv6 localhost address" do
59
55
  line = prefix + 'Processing PeopleController#index (for ::1 at 2008-08-14 21:16:30) [GET]'
60
- @rails.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '::1')
56
+ subject.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '::1')
61
57
  end
62
58
 
63
59
  it "should parse a :processing line correctly when it contains ipv6 address" do
64
60
  line = prefix + 'Processing PeopleController#index (for 3ffe:1900:4545:3:200:f8ff:fe21:67cf at 2008-08-14 21:16:30) [GET]'
65
- @rails.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '3ffe:1900:4545:3:200:f8ff:fe21:67cf')
61
+ subject.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '3ffe:1900:4545:3:200:f8ff:fe21:67cf')
66
62
  end
67
63
 
68
64
  it "should parse a Rails 2.1 style :completed line correctly" do
69
65
  line = prefix + 'Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]'
70
- @rails.should parse_line(line).as(:completed).and_capture(:duration => 0.21665, :db => 0.0, :view => 0.00926, :status => 200, :url => 'http://demo.nu/employees')
66
+ subject.should parse_line(line).as(:completed).and_capture(:duration => 0.21665, :db => 0.0, :view => 0.00926, :status => 200, :url => 'http://demo.nu/employees')
71
67
  end
72
68
 
73
69
  it "should parse a Rails 2.2 style :completed line correctly" do
74
70
  line = prefix + 'Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]'
75
- @rails.should parse_line(line).as(:completed).and_capture(:duration => 0.614, :db => 0.031, :view => 0.120, :status => 200, :url => 'http://floorplanner.local/demo')
71
+ subject.should parse_line(line).as(:completed).and_capture(:duration => 0.614, :db => 0.031, :view => 0.120, :status => 200, :url => 'http://floorplanner.local/demo')
76
72
  end
77
73
 
78
74
  it "should parse a Rails 2.2 style :completed line correctly when AR is disabled" do
79
75
  line = prefix + 'Completed in 597ms (View: 298 | 200 OK [http://shapado.com]'
80
- @rails.should parse_line(line).as(:completed).and_capture(:duration => 0.597, :db => nil, :view => 0.298, :status => 200, :url => 'http://shapado.com')
76
+ subject.should parse_line(line).as(:completed).and_capture(:duration => 0.597, :db => nil, :view => 0.298, :status => 200, :url => 'http://shapado.com')
81
77
  end
82
78
 
83
79
  it "should parse a Rails 2.2 style :completed line without view" do
84
80
  line = prefix + "Completed in 148ms (DB: 0) | 302 Found [http://iwp-sod.hargray.org/login]"
85
- @rails.should parse_line(line).as(:completed).and_capture(:duration => 0.148, :db => 0.0, :view => nil, :status => 302, :url => 'http://iwp-sod.hargray.org/login')
81
+ subject.should parse_line(line).as(:completed).and_capture(:duration => 0.148, :db => 0.0, :view => nil, :status => 302, :url => 'http://iwp-sod.hargray.org/login')
86
82
  end
87
83
 
88
84
  it "should parse a :failure line with exception correctly" do
89
85
  line = prefix + "NoMethodError (undefined method `update_domain_account' for nil:NilClass):"
90
- @rails.should parse_line(line).as(:failure).and_capture(:error => 'NoMethodError', :message => "undefined method `update_domain_account' for nil:NilClass")
86
+ subject.should parse_line(line).as(:failure).and_capture(:error => 'NoMethodError', :message => "undefined method `update_domain_account' for nil:NilClass")
91
87
  end
92
88
 
93
89
  it "should parse a :cache_hit line correctly with an filter instance reference" do
94
90
  line = prefix + 'Filter chain halted as [#<ActionController::Filters::AroundFilter:0x2a999ad120 @identifier=nil, @kind=:filter, @options={:only=>#<Set: {"cached"}>, :if=>:not_logged_in?, :unless=>nil}, @method=#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>>] did_not_yield.'
95
- @rails.should parse_line(line).as(:cache_hit)
91
+ subject.should parse_line(line).as(:cache_hit)
96
92
  end
97
93
 
98
94
  it "should parse a :cache_hit line correctly with an proc instance reference" do
99
95
  line = prefix + 'Filter chain halted as [#<ActionController::Filters::AroundFilter:0x2a9a923e38 @method=#<Proc:0x0000002a9818b3f8@/usr/local/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/caching/actions.rb:64>, @kind=:filter, @identifier=nil, @options={:unless=>nil, :if=>nil, :only=>#<Set: {"show"}>}>] did_not_yield.'
100
- @rails.should parse_line(line).as(:cache_hit)
96
+ subject.should parse_line(line).as(:cache_hit)
101
97
  end
102
98
 
103
99
 
104
100
  it "should parse a :parameters line correctly" do
105
101
  line = prefix + ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
106
- @rails.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
102
+ subject.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
107
103
  end
108
104
 
109
105
  it "should parse a :rendered line correctly" do
110
106
  line = prefix + 'Rendered layouts/_footer (2.9ms)'
111
- @rails.should parse_line(line).as(:rendered).and_capture(:render_file => 'layouts/_footer', :render_duration => 0.0029)
107
+ subject.should parse_line(line).as(:rendered).and_capture(:render_file => 'layouts/_footer', :render_duration => 0.0029)
112
108
  end
113
109
 
114
110
  it "should parse a :query_executed line with colors" do
115
111
  line = prefix + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
116
- @rails.should parse_line(line).as(:query_executed).and_capture(:query_class => 'User', :query_duration => 0.0004, :query_sql => 'SELECT * FROM users WHERE (users.id = :int)')
112
+ subject.should parse_line(line).as(:query_executed).and_capture(:query_class => 'User', :query_duration => 0.0004, :query_sql => 'SELECT * FROM users WHERE (users.id = :int)')
117
113
  end
118
114
 
119
115
  it "should parse a :query_executed line without colors" do
120
116
  line = prefix + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
121
- @rails.should parse_line(line).as(:query_executed).and_capture(:query_class => 'User', :query_duration => 0.0004, :query_sql => 'SELECT * FROM users WHERE (users.id = :int)')
117
+ subject.should parse_line(line).as(:query_executed).and_capture(:query_class => 'User', :query_duration => 0.0004, :query_sql => 'SELECT * FROM users WHERE (users.id = :int)')
122
118
  end
123
119
 
124
120
  it "should parse a :query_cached line with colors" do
125
121
  line = prefix + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
126
- @rails.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
122
+ subject.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
127
123
  end
128
124
 
129
125
  it "should parse a :query_cached line without colors" do
130
126
  line = prefix + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
131
- @rails.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
127
+ subject.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
132
128
  end
133
129
 
134
130
  it "should not parse an unsupported line" do
135
131
  line = prefix + 'nonsense line that should not be parsed as anything'
136
- @rails.should_not parse_line(line)
132
+ subject.should_not parse_line(line)
137
133
  end
138
134
  end
139
135
  end
140
136
  end
141
137
 
142
138
  describe '#parse_io' do
143
- before(:each) do
144
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(
145
- RequestLogAnalyzer::FileFormat.load(:rails), :parse_strategy => 'cautious')
146
- end
139
+ let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject, :parse_strategy => 'cautious') }
147
140
 
148
141
  it "should parse a Rails 2.1 style log and find valid Rails requests without warnings" do
149
- request_counter.should_receive(:hit!).exactly(4).times
150
- @log_parser.should_not_receive(:warn)
151
-
152
- @log_parser.parse_file(log_fixture(:rails_1x)) do |request|
153
- request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
154
- end
142
+ log_parser.should_receive(:handle_request).exactly(4).times
143
+ log_parser.should_not_receive(:warn)
144
+ log_parser.parse_file(log_fixture(:rails_1x))\
155
145
  end
156
146
 
157
147
  it "should parse a Rails 2.2 style log and find valid Rails requests without warnings" do
158
- request_counter.should_receive(:hit!).once
159
- @log_parser.should_not_receive(:warn)
160
-
161
- @log_parser.parse_file(log_fixture(:rails_22)) do |request|
162
- request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
163
- end
148
+ log_parser.should_receive(:handle_request).once
149
+ log_parser.should_not_receive(:warn)
150
+ log_parser.parse_file(log_fixture(:rails_22))
164
151
  end
165
152
 
166
153
  it "should parse a Rails SyslogLogger file with prefix and find valid requests without warnings" do
167
- request_counter.should_receive(:hit!).once
168
- @log_parser.should_not_receive(:warn)
169
-
170
- @log_parser.parse_file(log_fixture(:syslog_1x)) do |request|
171
- request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
172
- end
154
+ log_parser.should_receive(:handle_request).once
155
+ log_parser.should_not_receive(:warn)
156
+ log_parser.parse_file(log_fixture(:syslog_1x))
173
157
  end
174
158
 
175
159
  it "should parse cached requests" do
176
- @log_parser.should_not_receive(:warn)
177
- @log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
160
+ log_parser.should_not_receive(:warn)
161
+ log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
178
162
  request.should be_completed
179
163
  request =~ :cache_hit
180
164
  end
181
165
  end
182
166
 
183
167
  it "should detect unordered requests in the logs" do
184
- @log_parser.should_not_receive(:handle_request)
185
- @log_parser.should_receive(:warn).with(:unclosed_request, anything).once
186
- @log_parser.should_receive(:warn).with(:no_current_request, anything).twice
187
- @log_parser.parse_file(log_fixture(:rails_unordered))
168
+ log_parser.should_not_receive(:handle_request)
169
+ log_parser.should_receive(:warn).with(:unclosed_request, anything).once
170
+ log_parser.should_receive(:warn).with(:no_current_request, anything).at_least(:twice)
171
+ log_parser.parse_file(log_fixture(:rails_unordered))
188
172
  end
189
173
  end
190
174
  end
@@ -2,45 +2,46 @@ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::W3c do
4
4
 
5
- before(:each) do
6
- @file_format = RequestLogAnalyzer::FileFormat.load(:w3c)
7
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
8
- # date time c-ip cs-username s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status sc-bytes cs-bytes time-taken cs(User-Agent) cs(Referrer)
9
- @sample = '2002-05-24 20:18:01 172.224.24.114 - 206.73.118.24 80 GET /Default.htm - 200 7930 248 31 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server) http://64.224.24.114/'
5
+ subject { RequestLogAnalyzer::FileFormat.load(:w3c) }
6
+
7
+ it { should be_well_formed }
8
+ it { should have_line_definition(:access).capturing(:timestamp, :remote_ip, :username, :local_ip, :port,
9
+ :method, :path, :http_status, :bytes_sent, :bytes_received, :duration, :user_agent, :referer) }
10
+
11
+ it { should have(10).report_trackers }
12
+
13
+ let(:sample1) { '2002-05-24 20:18:01 172.224.24.114 - 206.73.118.24 80 GET /Default.htm - 200 7930 248 31 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server) http://64.224.24.114/' }
14
+ let(:irrelevant) { '#Software: Microsoft Internet Information Services 6.0' }
15
+
16
+ describe '#parse_line' do
17
+ it { should parse_line(sample1, 'an access line').and_capture(
18
+ :timestamp => 20020524201801,
19
+ :remote_ip => "172.224.24.114",
20
+ :username => nil,
21
+ :local_ip => "206.73.118.24",
22
+ :port => 80,
23
+ :method => 'GET',
24
+ :path => '/Default.htm',
25
+ :http_status => 200,
26
+ :bytes_sent => 7930,
27
+ :bytes_received => 248,
28
+ :duration => 0.031,
29
+ :user_agent => 'Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server)',
30
+ :referer => 'http://64.224.24.114/')
31
+ }
32
+
33
+ it { should_not parse_line(irrelevant, 'an irrelevant line') }
34
+ it { should_not parse_line('nonsense', 'a nonsense line') }
10
35
  end
11
-
12
- it "should be a valid file format" do
13
- @file_format.should be_valid
14
- end
15
-
16
- it "should parse access lines and capture all of its fields" do
17
- @file_format.should have_line_definition(:access).capturing(:timestamp, :remote_ip, :username, :local_ip, :port, :method, :path, :http_status, :bytes_sent, :bytes_received, :duration, :user_agent, :referer)
18
- end
19
-
20
- it "should match the sample line" do
21
- @file_format.parse_line(@sample).should include(:line_definition, :captures)
22
- end
23
-
24
- it "should not match a nonsense line" do
25
- @file_format.parse_line('#Software: Microsoft Internet Information Services 6.0').should be_nil
26
- end
27
-
28
- it "should parse and convert the sample fields correctly" do
29
- @log_parser.parse_io(StringIO.new(@sample)) do |request|
30
- request[:timestamp].should == 20020524201801
31
- request[:remote_ip].should == "172.224.24.114"
32
- request[:username].should == nil
33
- request[:local_ip].should == "206.73.118.24"
34
- request[:port].should == 80
35
- request[:method].should == 'GET'
36
- request[:path].should == '/Default.htm'
37
- request[:http_status].should == 200
38
- request[:bytes_sent].should == 7930
39
- request[:bytes_received].should == 248
40
- request[:duration].should == 0.031
41
- request[:user_agent].should == 'Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server)'
42
- request[:referer].should == 'http://64.224.24.114/'
36
+
37
+ describe '#parse_io' do
38
+ let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
39
+ let(:snippet) { log_snippet(irrelevant, sample1, sample1) }
40
+
41
+ it "should parse a snippet successully without warnings" do
42
+ log_parser.should_receive(:handle_request).twice
43
+ log_parser.should_not_receive(:warn)
44
+ log_parser.parse_io(snippet)
43
45
  end
44
46
  end
45
-
46
- end
47
+ end
@@ -11,7 +11,7 @@ describe RequestLogAnalyzer::Source::LogParser, :requests do
11
11
  end
12
12
 
13
13
  it "should have a valid language" do
14
- @log_parser.file_format.should be_valid
14
+ @log_parser.file_format.should be_well_formed
15
15
  end
16
16
 
17
17
  it "should set the :source for every parsed line" do
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
- - 10
7
+ - 11
8
8
  - 0
9
- version: 1.10.0
9
+ version: 1.11.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Willem van Bergen
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-26 00:00:00 -05:00
18
+ date: 2011-04-27 00:00:00 -04:00
19
19
  default_executable: request-log-analyzer
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -83,6 +83,7 @@ extra_rdoc_files:
83
83
  - README.rdoc
84
84
  files:
85
85
  - .gitignore
86
+ - .infinity_test
86
87
  - DESIGN.rdoc
87
88
  - Gemfile
88
89
  - LICENSE
@@ -94,7 +95,6 @@ files:
94
95
  - lib/cli/database_console_init.rb
95
96
  - lib/cli/progressbar.rb
96
97
  - lib/cli/tools.rb
97
- - lib/mixins/gets_memory_protection.rb
98
98
  - lib/request_log_analyzer.rb
99
99
  - lib/request_log_analyzer/aggregator.rb
100
100
  - lib/request_log_analyzer/aggregator/database_inserter.rb
@@ -131,12 +131,10 @@ files:
131
131
  - lib/request_log_analyzer/log_processor.rb
132
132
  - lib/request_log_analyzer/mailer.rb
133
133
  - lib/request_log_analyzer/output.rb
134
- - lib/request_log_analyzer/output/fancy_html.rb
135
134
  - lib/request_log_analyzer/output/fixed_width.rb
136
135
  - lib/request_log_analyzer/output/html.rb
137
136
  - lib/request_log_analyzer/request.rb
138
137
  - lib/request_log_analyzer/source.rb
139
- - lib/request_log_analyzer/source/database_loader.rb
140
138
  - lib/request_log_analyzer/source/log_parser.rb
141
139
  - lib/request_log_analyzer/tracker.rb
142
140
  - lib/request_log_analyzer/tracker/duration.rb
@@ -1,80 +0,0 @@
1
- class File
2
- alias_method :gets_original, :gets
3
- # The size of the reads we will use to add to the line buffer.
4
- MAX_READ_SIZE=1024*100
5
-
6
- #
7
- # This method returns the next line of the File.
8
- #
9
- # It works by moving the file pointer forward +MAX_READ_SIZE+ at a time,
10
- # storing seen lines in <tt>@line_buffer</tt>. Once the buffer contains at
11
- # least two lines (ensuring we have seen on full line) or the file pointer
12
- # reaches the end of the File, the last line from the buffer is returned.
13
- # When the buffer is exhausted, this will throw +nil+ (from the empty Array).
14
- #
15
- # Read portions of the file that do not contain the +sep_string+ are not added to
16
- # the buffer. This prevents <tt>@line_buffer<tt> from growing signficantly when parsing
17
- # large lines.
18
- #
19
- def gets(sep_string = $/)
20
- @read_size ||= MAX_READ_SIZE
21
- # A buffer to hold lines read, but not yet returned.
22
- @line_buffer ||= Array.new
23
-
24
- # Record where we are.
25
- @current_pos ||= pos
26
-
27
- # Last Position in the file
28
- @last_pos ||= nil
29
- if @last_pos.nil?
30
- seek(0, IO::SEEK_END)
31
- @last_pos = pos
32
- seek(@current_pos, IO::SEEK_SET)
33
- end
34
-
35
- #
36
- # If we have more than one line in the buffer or we have reached the
37
- # beginning of the file, send the last line in the buffer to the caller.
38
- # (This may be +nil+, if the buffer has been exhausted.)
39
- #
40
- if @line_buffer.size > 2 or @current_pos >= @last_pos
41
- self.lineno += 1
42
- return @line_buffer.shift
43
- end
44
-
45
- sep =
46
-
47
- chunk = String.new
48
- while chunk and chunk !~ /#{sep_string}/
49
- chunk = read(@read_size)
50
- end
51
-
52
- # Appends new lines to the last element of the buffer
53
- line_buffer_pos = @line_buffer.any? ? @line_buffer.size-1 : 0
54
-
55
- if chunk
56
- @line_buffer[line_buffer_pos] = @line_buffer[line_buffer_pos].to_s<< chunk
57
- else
58
- # at the end
59
- return @line_buffer.shift
60
- end
61
-
62
- #
63
- # Divide the last line of the buffer based on +sep_string+ and #flatten!
64
- # those new lines into the buffer.
65
- #
66
- @line_buffer[line_buffer_pos] = @line_buffer[line_buffer_pos].scan(/.*?#{Regexp.escape(sep_string)}|.+/)
67
- @line_buffer.flatten!
68
-
69
- #
70
- # If we made it this far, we need to read more data to try and find the
71
- # end of a line or the end of the file. Move the file pointer
72
- # forward a step, to give us new bytes to read.
73
- #
74
- @current_pos += @read_size
75
- seek(@current_pos, IO::SEEK_SET)
76
-
77
- # We have more data now, so try again to read a line...
78
- gets(sep_string)
79
- end
80
- end
@@ -1,44 +0,0 @@
1
- begin
2
- require 'rubygems'
3
- require 'gchart'
4
- rescue LoadError
5
- $stderr.puts "The FancyHTML output format requires the googlechart gem:"
6
- $stderr.puts " (sudo) gem install googlecharts"
7
- end
8
-
9
- module RequestLogAnalyzer::Output
10
-
11
- class FancyHTML < HTML
12
-
13
- def report_tracker(tracker)
14
- case tracker
15
- when RequestLogAnalyzer::Tracker::HourlySpread then report_hourly_spread(tracker)
16
- else tracker.report(self)
17
- end
18
- end
19
-
20
- def report_hourly_spread(tracker)
21
- title tracker.title
22
- puts tag(:img, nil, :width => '700', :height => '120', :src =>
23
- Gchart.sparkline(:data => tracker.hour_frequencies, :size => '700x120', :line_colors => '0077CC',
24
- :axis_with_labels => 'x,y', :axis_labels => [x_axis_labels(tracker),y_axis_labels(tracker)]))
25
- end
26
-
27
- def x_axis_labels(tracker)
28
- frmt = '%H:%M'
29
- x_axis_labels = []
30
- num_labels = 5
31
- start = tracker.first_timestamp
32
- step = tracker.timespan / (num_labels - 1)
33
- for i in 0...num_labels do
34
- x_axis_labels << (start + step * i).strftime(frmt)
35
- end
36
- x_axis_labels
37
- end
38
-
39
- def y_axis_labels(tracker)
40
- sorted_frequencies = tracker.hour_frequencies.sort
41
- [sorted_frequencies.first, sorted_frequencies.last]
42
- end
43
- end
44
- end
@@ -1,87 +0,0 @@
1
- require 'rubygems'
2
- require 'activerecord'
3
-
4
- module RequestLogAnalyzer::Source
5
-
6
- # Active Resource hook
7
- class Request < ActiveRecord::Base
8
- has_many :completed_lines
9
- has_many :processing_lines
10
- def convert(file_format)
11
- send_attributes = self.attributes
12
- send_attributes.merge!(self.completed_lines.first.attributes) if self.completed_lines.first
13
- send_attributes.merge!(self.processing_lines.first.attributes) if self.processing_lines.first
14
- return RequestLogAnalyzer::Request.new(file_format, send_attributes)
15
- end
16
- end
17
-
18
- class CompletedLine < ActiveRecord::Base
19
- belongs_to :request
20
- end
21
-
22
- class ProcessingLine < ActiveRecord::Base
23
- belongs_to :request
24
- end
25
-
26
- # The Database class gets log data from the database.
27
- class DatabaseLoader < Base
28
-
29
- attr_reader :source_files, :file_format, :requests
30
-
31
- # Initializes the log file parser instance.
32
- # It will apply the language specific FileFormat module to this instance. It will use the line
33
- # definitions in this module to parse any input that it is given (see parse_io).
34
- #
35
- # <tt>format</tt>:: The current file format instance
36
- # <tt>options</tt>:: A hash of options that are used by the parser
37
- def initialize(format, options = {})
38
- super(format, options)
39
- @source_files = options[:source_files]
40
- @parsed_requests = 0
41
- @requests = []
42
- end
43
-
44
- # Reads the input, which can either be a file, sequence of files or STDIN to parse
45
- # lines specified in the FileFormat. This lines will be combined into Request instances,
46
- # that will be yielded. The actual parsing occurs in the parse_io method.
47
- # <tt>options</tt>:: A Hash of options that will be pased to parse_io.
48
- def each_request(options = {}, &block) # :yields: request
49
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => @source_files)
50
-
51
- @progress_handler.call(:started, @source_files) if @progress_handler
52
- RequestLogAnalyzer::Source::Request.find(:all).each do |request|
53
- @parsed_requests += 1
54
- @progress_handler.call(:progress, @parsed_requests) if @progress_handler
55
-
56
- yield request.convert(self.file_format)
57
- end
58
-
59
- @progress_handler.call(:finished, @source_files) if @progress_handler
60
- end
61
-
62
- # Add a block to this method to install a progress handler while parsing.
63
- # <tt>proc</tt>:: The proc that will be called to handle progress update messages
64
- def progress=(proc)
65
- @progress_handler = proc
66
- end
67
-
68
- # Add a block to this method to install a warning handler while parsing,
69
- # <tt>proc</tt>:: The proc that will be called to handle parse warning messages
70
- def warning=(proc)
71
- @warning_handler = proc
72
- end
73
-
74
- # This method is called by the parser if it encounteres any parsing problems.
75
- # It will call the installed warning handler if any.
76
- #
77
- # By default, RequestLogAnalyzer::Controller will install a warning handler
78
- # that will pass the warnings to each aggregator so they can do something useful
79
- # with it.
80
- #
81
- # <tt>type</tt>:: The warning type (a Symbol)
82
- # <tt>message</tt>:: A message explaining the warning
83
- def warn(type, message)
84
- @warning_handler.call(type, message, @current_io.lineno) if @warning_handler
85
- end
86
- end
87
- end