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.
- data/.gitignore +2 -1
- data/.infinity_test +8 -0
- data/bin/request-log-analyzer +0 -1
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +2 -1
- data/lib/request_log_analyzer/aggregator.rb +5 -5
- data/lib/request_log_analyzer/controller.rb +0 -3
- data/lib/request_log_analyzer/database.rb +6 -7
- data/lib/request_log_analyzer/file_format/apache.rb +1 -1
- data/lib/request_log_analyzer/file_format/delayed_job2.rb +2 -2
- data/lib/request_log_analyzer/file_format/delayed_job21.rb +2 -2
- data/lib/request_log_analyzer/file_format/haproxy.rb +107 -13
- data/lib/request_log_analyzer/file_format/mysql.rb +5 -5
- data/lib/request_log_analyzer/file_format/rails3.rb +8 -1
- data/lib/request_log_analyzer/file_format.rb +43 -14
- data/lib/request_log_analyzer/filter.rb +4 -5
- data/lib/request_log_analyzer/line_definition.rb +6 -4
- data/lib/request_log_analyzer/output.rb +3 -5
- data/lib/request_log_analyzer/source/log_parser.rb +56 -4
- data/lib/request_log_analyzer/source.rb +3 -4
- data/lib/request_log_analyzer/tracker.rb +8 -8
- data/lib/request_log_analyzer.rb +15 -29
- data/request-log-analyzer.gemspec +3 -3
- data/spec/fixtures/mysql_slow_query.log +0 -1
- data/spec/integration/command_line_usage_spec.rb +0 -5
- data/spec/lib/helpers.rb +2 -2
- data/spec/lib/matchers.rb +38 -7
- data/spec/lib/mocks.rb +1 -5
- data/spec/unit/database/base_class_spec.rb +1 -0
- data/spec/unit/file_format/amazon_s3_format_spec.rb +58 -55
- data/spec/unit/file_format/apache_format_spec.rb +74 -162
- data/spec/unit/file_format/common_regular_expressions_spec.rb +51 -26
- data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -31
- data/spec/unit/file_format/delayed_job2_format_spec.rb +27 -32
- data/spec/unit/file_format/delayed_job_format_spec.rb +44 -63
- data/spec/unit/file_format/haproxy_format_spec.rb +69 -71
- data/spec/unit/file_format/line_definition_spec.rb +26 -33
- data/spec/unit/file_format/merb_format_spec.rb +22 -37
- data/spec/unit/file_format/mysql_format_spec.rb +80 -123
- data/spec/unit/file_format/oink_format_spec.rb +29 -61
- data/spec/unit/file_format/postgresql_format_spec.rb +2 -4
- data/spec/unit/file_format/rack_format_spec.rb +49 -44
- data/spec/unit/file_format/rails3_format_spec.rb +39 -37
- data/spec/unit/file_format/rails_format_spec.rb +52 -68
- data/spec/unit/file_format/w3c_format_spec.rb +40 -39
- data/spec/unit/source/log_parser_spec.rb +1 -1
- metadata +4 -6
- data/lib/mixins/gets_memory_protection.rb +0 -80
- data/lib/request_log_analyzer/output/fancy_html.rb +0 -44
- data/lib/request_log_analyzer/source/database_loader.rb +0 -87
|
@@ -2,153 +2,110 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Mysql do
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
subject { RequestLogAnalyzer::FileFormat.load(:mysql) }
|
|
6
|
+
|
|
7
|
+
it { should be_well_formed }
|
|
8
|
+
it { should have_line_definition(:time).capturing(:timestamp) }
|
|
9
|
+
it { should have_line_definition(:user_host).capturing(:user, :host, :ip) }
|
|
10
|
+
it { should have_line_definition(:query_statistics).capturing(:query_time, :lock_time, :rows_sent, :rows_examined) }
|
|
11
|
+
it { should have_line_definition(:use_database).capturing(:database) }
|
|
12
|
+
it { should have_line_definition(:query_part).capturing(:query_fragment) }
|
|
13
|
+
it { should have_line_definition(:query).capturing(:query) }
|
|
14
|
+
it { should have(7).report_trackers }
|
|
15
|
+
|
|
9
16
|
describe '#parse_line' do
|
|
10
|
-
before(:each) do
|
|
11
|
-
@file_format = RequestLogAnalyzer::FileFormat.load(:mysql)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it "should parse a :time line correctly" do
|
|
15
|
-
line = '# Time: 091112 8:13:56'
|
|
16
|
-
@file_format.should parse_line(line).as(:time).and_capture(:timestamp => 20091112081356)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "should parse a :user_host line correctly with IP present" do
|
|
20
|
-
line = '# User@Host: admin[admin] @ db1 [10.0.0.1]'
|
|
21
|
-
@file_format.should parse_line(line).as(:user_host).and_capture(:user => "admin", :host => 'db1', :ip => '10.0.0.1')
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it "should parse a :user_host line correctly without a host" do
|
|
25
|
-
line = '# User@Host: admin[admin] @ [10.0.0.1]'
|
|
26
|
-
@file_format.should parse_line(line).as(:user_host).and_capture(:user => "admin", :host => '', :ip => '10.0.0.1')
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it "should parse a :user_host line correctly with IP absent" do
|
|
30
|
-
line = '# User@Host: root[root] @ localhost []'
|
|
31
|
-
@file_format.should parse_line(line).as(:user_host).and_capture(:user => "root", :host => 'localhost', :ip => "")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "should parse a :query_statistics line" do
|
|
35
|
-
line = '# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307'
|
|
36
|
-
@file_format.should parse_line(line).as(:query_statistics).and_capture(:query_time => 10.0,
|
|
37
|
-
:lock_time => 0.0, :rows_sent => 1191307, :rows_examined => 1191307)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "should parse a :query_statistics line with floating point durations" do
|
|
41
|
-
line = '# Query_time: 10.00000 Lock_time: 0.00000 Rows_sent: 1191307 Rows_examined: 1191307'
|
|
42
|
-
@file_format.should parse_line(line).as(:query_statistics).and_capture(:query_time => 10.0,
|
|
43
|
-
:lock_time => 0.0, :rows_sent => 1191307, :rows_examined => 1191307)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it "should parse a :query_part line" do
|
|
47
|
-
line = ' AND clients.index > 0'
|
|
48
|
-
@file_format.should parse_line(line).as(:query_part).and_capture(:query_fragment => line)
|
|
49
|
-
end
|
|
50
17
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@
|
|
54
|
-
'
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
it
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
it
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
18
|
+
let(:time_sample) { '# Time: 091112 8:13:56' }
|
|
19
|
+
let(:user_host_sample) { '# User@Host: admin[admin] @ db1 [10.0.0.1]' }
|
|
20
|
+
let(:user_host_wo_host_sample) { '# User@Host: admin[admin] @ [10.0.0.1]' }
|
|
21
|
+
let(:user_host_wo_ip_sample) { '# User@Host: root[root] @ localhost []' }
|
|
22
|
+
let(:float_query_statistics_sample) { '# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307' }
|
|
23
|
+
let(:int_query_statistics_sample) { '# Query_time: 10.00000 Lock_time: 0.00000 Rows_sent: 1191307 Rows_examined: 1191307' }
|
|
24
|
+
let(:partial_query_sample) { 'AND clients.index > 0' }
|
|
25
|
+
let(:full_query_sample) { 'SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`; ' }
|
|
26
|
+
let(:use_db_sample) { 'use db;' }
|
|
27
|
+
let(:set_timestamp_sample) { 'SET timestamp=1250651725;' }
|
|
28
|
+
let(:set_insertid_sample) { 'SET insert_id=1250651725;' }
|
|
29
|
+
let(:set_timestamp_insertid_sample) { 'SET timestamp=1250651725, insert_id=45674;' }
|
|
30
|
+
|
|
31
|
+
it { should parse_line(time_sample).as(:time).and_capture(:timestamp => 20091112081356) }
|
|
32
|
+
it { should parse_line(user_host_sample).as(:user_host).and_capture(:user => "admin", :host => 'db1', :ip => '10.0.0.1') }
|
|
33
|
+
it { should parse_line(user_host_wo_host_sample, 'without host').as(:user_host).and_capture(:user => "admin", :host => '', :ip => '10.0.0.1') }
|
|
34
|
+
it { should parse_line(user_host_wo_ip_sample, 'without IP').as(:user_host).and_capture(:user => "root", :host => 'localhost', :ip => "") }
|
|
35
|
+
it { should parse_line(float_query_statistics_sample, 'using floats').as(:query_statistics).and_capture(:query_time => 10.0, :lock_time => 0.0, :rows_sent => 1191307, :rows_examined => 1191307) }
|
|
36
|
+
it { should parse_line(int_query_statistics_sample, 'using integers').as(:query_statistics).and_capture(:query_time => 10.0, :lock_time => 0.0, :rows_sent => 1191307, :rows_examined => 1191307) }
|
|
37
|
+
it { should parse_line(partial_query_sample).as(:query_part).and_capture(:query_fragment => 'AND clients.index > 0') }
|
|
38
|
+
it { should parse_line(full_query_sample).as(:query).and_capture(:query => 'SELECT /*!:int SQL_NO_CACHE */ * FROM events') }
|
|
39
|
+
it { should parse_line(use_db_sample).as(:use_database).and_capture(:database => 'db') }
|
|
40
|
+
|
|
41
|
+
it { should_not parse_line(set_timestamp_sample) }
|
|
42
|
+
it { should_not parse_line(set_insertid_sample) }
|
|
43
|
+
it { should_not parse_line(set_timestamp_insertid_sample) }
|
|
78
44
|
end
|
|
79
45
|
|
|
80
46
|
describe '#parse_io' do
|
|
81
|
-
|
|
82
|
-
@log_parser = RequestLogAnalyzer::Source::LogParser.new(RequestLogAnalyzer::FileFormat.load(:mysql))
|
|
83
|
-
end
|
|
47
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
84
48
|
|
|
85
49
|
it "should parse a single line query entry correctly" do
|
|
86
|
-
fixture =
|
|
87
|
-
# Time: 091112 18:13:56
|
|
88
|
-
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
89
|
-
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
90
|
-
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
91
|
-
EOS
|
|
92
|
-
|
|
93
|
-
|
|
50
|
+
fixture = <<-EOS
|
|
51
|
+
# Time: 091112 18:13:56
|
|
52
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
53
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
54
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
55
|
+
EOS
|
|
56
|
+
|
|
57
|
+
log_parser.parse_string(fixture) do |request|
|
|
94
58
|
request[:query].should == 'SELECT /*!:int SQL_NO_CACHE */ * FROM events'
|
|
95
59
|
end
|
|
96
60
|
end
|
|
97
61
|
|
|
98
62
|
it "should parse a multiline query entry correctly" do
|
|
99
|
-
fixture =
|
|
100
|
-
# Time: 091112 18:13:56
|
|
101
|
-
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
102
|
-
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
103
|
-
SELECT * FROM `clients` WHERE (1=1
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
EOS
|
|
108
|
-
|
|
109
|
-
|
|
63
|
+
fixture = <<-EOS
|
|
64
|
+
# Time: 091112 18:13:56
|
|
65
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
66
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
67
|
+
SELECT * FROM `clients` WHERE (1=1
|
|
68
|
+
AND clients.valid_from < '2009-12-05' AND (clients.valid_to IS NULL or clients.valid_to > '2009-11-20')
|
|
69
|
+
AND clients.index > 0
|
|
70
|
+
) AND (clients.deleted_at IS NULL);
|
|
71
|
+
EOS
|
|
72
|
+
|
|
73
|
+
log_parser.parse_string(fixture) do |request|
|
|
110
74
|
request[:query].should == "SELECT * FROM clients WHERE (:int=:int AND clients.valid_from < :date AND (clients.valid_to IS NULL or clients.valid_to > :date) AND clients.index > :int ) AND (clients.deleted_at IS NULL)"
|
|
111
75
|
end
|
|
112
76
|
end
|
|
113
77
|
|
|
114
|
-
it "should parse a request without timestamp correctly" do
|
|
115
|
-
fixture =
|
|
116
|
-
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
117
|
-
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
118
|
-
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
119
|
-
EOS
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Mysql::Request) && request.completed?
|
|
125
|
-
end
|
|
78
|
+
it "should parse a request without timestamp correctly, without warnings" do
|
|
79
|
+
fixture = <<-EOS
|
|
80
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
81
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
82
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
83
|
+
EOS
|
|
84
|
+
|
|
85
|
+
log_parser.should_receive(:handle_request).once
|
|
86
|
+
log_parser.should_not_receive(:warn)
|
|
87
|
+
log_parser.parse_string(fixture)
|
|
126
88
|
end
|
|
127
89
|
|
|
128
90
|
it "should parse a query with context information correctly" do
|
|
129
|
-
fixture =
|
|
130
|
-
# Time: 091112 18:13:56
|
|
131
|
-
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
132
|
-
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
133
|
-
use database_name;
|
|
134
|
-
SET timestamp=4324342342423, insert_id = 224253443;
|
|
135
|
-
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
136
|
-
EOS
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
@log_parser.should_not_receive(:warn)
|
|
140
|
-
|
|
141
|
-
@log_parser.parse_io(StringIO.new(fixture)) do |request|
|
|
142
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Mysql::Request) && request.completed?
|
|
91
|
+
fixture = <<-EOS
|
|
92
|
+
# Time: 091112 18:13:56
|
|
93
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
94
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
95
|
+
use database_name;
|
|
96
|
+
SET timestamp=4324342342423, insert_id = 224253443;
|
|
97
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
98
|
+
EOS
|
|
99
|
+
|
|
100
|
+
log_parser.parse_string(fixture) do |request|
|
|
143
101
|
request[:query].should == 'SELECT /*!:int SQL_NO_CACHE */ * FROM events'
|
|
144
102
|
end
|
|
145
|
-
|
|
146
103
|
end
|
|
147
104
|
|
|
148
|
-
|
|
149
105
|
it "should find 26 completed sloq query entries" do
|
|
150
|
-
|
|
151
|
-
|
|
106
|
+
log_parser.should_not_receive(:warn)
|
|
107
|
+
log_parser.should_receive(:handle_request).exactly(26).times
|
|
108
|
+
log_parser.parse_file(log_fixture(:mysql_slow_query))
|
|
152
109
|
end
|
|
153
110
|
end
|
|
154
111
|
end
|
|
@@ -1,103 +1,71 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Oink do
|
|
4
|
-
describe '.create' do
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
before(:each) { @oink = RequestLogAnalyzer::FileFormat.load(:oink) }
|
|
8
|
-
|
|
9
|
-
it "should create a valid file format" do
|
|
10
|
-
@oink.should be_valid
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "should parse :memory_usage line" do
|
|
14
|
-
@oink.line_definitions.should include(:memory_usage)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
end
|
|
5
|
+
subject { RequestLogAnalyzer::FileFormat.load(:oink) }
|
|
20
6
|
|
|
7
|
+
it { should have_line_definition(:memory_usage).capturing(:pid, :memory) }
|
|
8
|
+
it { should have_line_definition(:processing).capturing(:pid, :controller, :action, :ip) }
|
|
9
|
+
it { should have_line_definition(:instance_type_counter).capturing(:pid, :instance_counts) }
|
|
10
|
+
it { should have(12).report_trackers }
|
|
11
|
+
|
|
21
12
|
describe '#parse_line' do
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
let(:memory_usage_sample) { 'Jun 18 11:27:36 derek rails[67783]: Memory usage: 714052 | PID: 67783' }
|
|
14
|
+
let(:processing_sample) { 'Aug 14 21:16:30 derek rails[67783]: Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]' }
|
|
15
|
+
let(:instance_type_counter_sample) { "Dec 13 12:00:44 storenvy rails[26364]: Instantiation Breakdown: Total: 732 | User: 376 | Post: 323 | Comment: 32 | Blog: 1" }
|
|
16
|
+
|
|
24
17
|
it "should parse a :memory_usage line correctly" do
|
|
25
|
-
|
|
26
|
-
@oink.should parse_line(line).as(:memory_usage).and_capture(:pid => 67783, :memory => 714052)
|
|
18
|
+
subject.should parse_line(memory_usage_sample).as(:memory_usage).and_capture(:pid => 67783, :memory => 714052)
|
|
27
19
|
end
|
|
28
20
|
|
|
29
21
|
it "should parse the PID from a :processing line correctly" do
|
|
30
|
-
|
|
31
|
-
@oink.should parse_line(line).as(:processing).and_capture(:pid => 67783, :controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '1.1.1.1')
|
|
22
|
+
subject.should parse_line(processing_sample).as(:processing).and_capture(:pid => 67783, :controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '1.1.1.1')
|
|
32
23
|
end
|
|
33
24
|
|
|
34
25
|
it "should parse a :instance_type_counter correctly" do
|
|
35
|
-
|
|
36
|
-
line = "Dec 13 12:00:44 storenvy rails[26364]: Instantiation Breakdown: Total: 732 | User: 376 | Post: 323 | Comment: 32 | Blog: 1"
|
|
37
|
-
|
|
38
|
-
@oink.should parse_line(line).as(:instance_type_counter).and_capture(:pid => 26364, :instance_counts => {'Total' => 732, 'User' => 376, 'Post' => 323, 'Comment' => 32, 'Blog' => 1})
|
|
26
|
+
subject.should parse_line(instance_type_counter_sample).as(:instance_type_counter).and_capture(:pid => 26364, :instance_counts => {'Total' => 732, 'User' => 376, 'Post' => 323, 'Comment' => 32, 'Blog' => 1})
|
|
39
27
|
end
|
|
40
28
|
end
|
|
41
29
|
|
|
42
30
|
describe '#parse_io' do
|
|
31
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
32
|
+
|
|
43
33
|
context "Rails 2.2 style log" do
|
|
44
|
-
before(:each) do
|
|
45
|
-
@log_parser = RequestLogAnalyzer::Source::LogParser.new(
|
|
46
|
-
RequestLogAnalyzer::FileFormat.load(:oink), :parse_strategy => 'cautious')
|
|
47
|
-
end
|
|
48
|
-
|
|
49
34
|
it "should parse requests" do
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
|
|
54
|
-
end
|
|
35
|
+
log_parser.should_receive(:handle_request).exactly(4).times
|
|
36
|
+
log_parser.should_not_receive(:warn)
|
|
37
|
+
log_parser.parse_file(log_fixture(:oink_22))
|
|
55
38
|
end
|
|
56
39
|
|
|
57
40
|
it "should not record :memory_diff on first request" do
|
|
58
|
-
|
|
59
|
-
if
|
|
60
|
-
request[:memory_diff].should == nil
|
|
61
|
-
end
|
|
41
|
+
log_parser.parse_file(log_fixture(:oink_22)) do |request|
|
|
42
|
+
request[:memory_diff].should == nil if log_parser.parsed_requests == 1
|
|
62
43
|
end
|
|
63
44
|
end
|
|
64
45
|
|
|
65
46
|
it "should record :memory_diff of 2nd tracked PID" do
|
|
66
|
-
|
|
67
|
-
if
|
|
68
|
-
request[:memory_diff].should == 50000*1024
|
|
69
|
-
end
|
|
47
|
+
log_parser.parse_file(log_fixture(:oink_22)) do |request|
|
|
48
|
+
request[:memory_diff].should == 50000 * 1024 if log_parser.parsed_requests == 3
|
|
70
49
|
end
|
|
71
50
|
end
|
|
72
51
|
|
|
73
52
|
it "should record :memory_diff of 1st tracked PID" do
|
|
74
|
-
|
|
75
|
-
if
|
|
76
|
-
request[:memory_diff].should == 30000*1024
|
|
77
|
-
end
|
|
53
|
+
log_parser.parse_file(log_fixture(:oink_22)) do |request|
|
|
54
|
+
request[:memory_diff].should == 30000 * 1024 if log_parser.parsed_requests == 4
|
|
78
55
|
end
|
|
79
56
|
end
|
|
80
57
|
end
|
|
81
58
|
|
|
82
59
|
context 'Rails 2.2 style log w/failure' do
|
|
83
|
-
before(:each) do
|
|
84
|
-
@log_parser = RequestLogAnalyzer::Source::LogParser.new(
|
|
85
|
-
RequestLogAnalyzer::FileFormat.load(:oink), :parse_strategy => 'cautious')
|
|
86
|
-
end
|
|
87
|
-
|
|
88
60
|
it "should parse requests" do
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
|
|
93
|
-
end
|
|
61
|
+
log_parser.should_receive(:handle_request).exactly(4).times
|
|
62
|
+
log_parser.should_not_receive(:warn)
|
|
63
|
+
log_parser.parse_file(log_fixture(:oink_22_failure))
|
|
94
64
|
end
|
|
95
65
|
|
|
96
66
|
it "should ignore memory changes when a failure occurs" do
|
|
97
|
-
|
|
98
|
-
if
|
|
99
|
-
request[:memory_diff].should == nil
|
|
100
|
-
end
|
|
67
|
+
log_parser.parse_file(log_fixture(:oink_22_failure)) do |request|
|
|
68
|
+
request[:memory_diff].should == nil if log_parser.parsed_requests == 4
|
|
101
69
|
end
|
|
102
70
|
end
|
|
103
71
|
end
|
|
@@ -5,7 +5,7 @@ describe RequestLogAnalyzer::FileFormat::Postgresql do
|
|
|
5
5
|
subject { RequestLogAnalyzer::FileFormat.load(:Postgresql) }
|
|
6
6
|
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
7
7
|
|
|
8
|
-
it { should
|
|
8
|
+
it { should be_well_formed }
|
|
9
9
|
|
|
10
10
|
describe '#parse_line' do
|
|
11
11
|
it "should parse a :query line correctly" do
|
|
@@ -32,10 +32,8 @@ describe RequestLogAnalyzer::FileFormat::Postgresql do
|
|
|
32
32
|
2010-10-10 15:00:02 GMT [38747]: [1670-1] LOCATION: exec_simple_query, postgres.c:1081
|
|
33
33
|
EOS
|
|
34
34
|
|
|
35
|
-
request_counter.should_receive(:hit!).exactly(1).times
|
|
36
35
|
log_parser.should_not_receive(:warn)
|
|
37
|
-
log_parser.
|
|
38
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Postgresql::Request) && request.completed?
|
|
36
|
+
log_parser.parse_string(fixture) do |request|
|
|
39
37
|
request[:query].should == 'INSERT INTO delayed_jobs (failed_at, locked_by, created_at, handler, updated_at, priority, run_at, attempts, locked_at, last_error) VALUES(NULL, NULL, :string, E:string, :string, :int, :string, :int, NULL, NULL) RETURNING id'
|
|
40
38
|
end
|
|
41
39
|
end
|
|
@@ -1,50 +1,55 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Rack do
|
|
4
|
+
|
|
5
|
+
subject { RequestLogAnalyzer::FileFormat.load(:rack)}
|
|
6
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
7
|
+
|
|
8
|
+
it { should be_well_formed }
|
|
9
|
+
it { should have_line_definition(:access).capturing(:remote_host, :user, :remote_logname,
|
|
10
|
+
:timestamp, :http_method, :path, :http_version, :http_status, :bytes_sent, :duration) }
|
|
11
|
+
|
|
12
|
+
it { should have(7).report_trackers }
|
|
13
|
+
|
|
14
|
+
let(:sample1) { '127.0.0.1 - - [23/Nov/2009 21:47:47] "GET /css/stylesheet.css HTTP/1.1" 200 3782 0.0024' }
|
|
15
|
+
let(:sample2) { '127.0.0.1 - - [16/Sep/2009 07:40:08] "GET /favicon.ico HTTP/1.1" 500 63183 0.0453' }
|
|
16
|
+
let(:sample3) { '127.0.0.1 - - [01/Oct/2009 07:58:10] "GET / HTTP/1.1" 200 1 0.0045' }
|
|
17
|
+
let(:irrelevant) { '== Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Mongrel' }
|
|
18
|
+
|
|
19
|
+
describe '#parse_line' do
|
|
20
|
+
|
|
21
|
+
it { should parse_line(sample1, 'a sample access line').and_capture(
|
|
22
|
+
:remote_host => '127.0.0.1', :timestamp => 20091123214747, :user => nil,
|
|
23
|
+
:http_status => 200, :http_method => 'GET', :http_version => '1.1',
|
|
24
|
+
:duration => 0.0024, :bytes_sent => 3782, :remote_logname => nil,
|
|
25
|
+
:path => '/css/stylesheet.css')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
it { should parse_line(sample2, 'another sample access line').and_capture(
|
|
29
|
+
:remote_host => '127.0.0.1', :timestamp => 20090916074008, :user => nil,
|
|
30
|
+
:http_status => 500, :http_method => 'GET', :http_version => '1.1',
|
|
31
|
+
:duration => 0.0453, :bytes_sent => 63183, :remote_logname => nil,
|
|
32
|
+
:path => '/favicon.ico')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
it { should parse_line(sample3, 'a third sample access line').and_capture(
|
|
36
|
+
:remote_host => '127.0.0.1', :timestamp => 20091001075810, :user => nil,
|
|
37
|
+
:http_status => 200, :http_method => 'GET', :http_version => '1.1',
|
|
38
|
+
:duration => 0.0045, :bytes_sent => 1, :remote_logname => nil,
|
|
39
|
+
:path => '/')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
it { should_not parse_line(irrelevant, 'an irrelevant line') }
|
|
43
|
+
it { should_not parse_line('nonsense', 'a nonsense line') }
|
|
44
|
+
end
|
|
4
45
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
it "should be a valid file format" do
|
|
14
|
-
@file_format.should be_valid
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "should parse access lines and capture all of its fields" do
|
|
18
|
-
@file_format.should have_line_definition(:access).capturing(:remote_host, :timestamp, :http_method, :path, :http_version,
|
|
19
|
-
:http_status, :bytes_sent, :duration)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it "should match the sample line" do
|
|
23
|
-
@file_format.parse_line(@sample).should include(:line_definition, :captures)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "should not match a nonsense line" do
|
|
27
|
-
@file_format.parse_line('== Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Mongrel').should be_nil
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it "should parse the sample fields correctly" do
|
|
31
|
-
match = @file_format.parse_line(@sample)
|
|
32
|
-
match.should_not be_nil
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it "should parse and convert the sample fields correctly" do
|
|
36
|
-
@log_parser.parse_io(StringIO.new(@sample)) do |request|
|
|
37
|
-
request[:remote_host].should == '127.0.0.1'
|
|
38
|
-
request[:timestamp].should == 20091123214747
|
|
39
|
-
request[:http_method].should == 'GET'
|
|
40
|
-
request[:path].should == '/css/stylesheet.css'
|
|
41
|
-
request[:http_version].should == '1.1'
|
|
42
|
-
request[:http_status].should == 200
|
|
43
|
-
request[:bytes_sent].should == 3782
|
|
44
|
-
request[:duration].should == 0.0024
|
|
45
|
-
end
|
|
46
|
+
describe '#parse_io' do
|
|
47
|
+
let(:snippet) { log_snippet(irrelevant, sample1, sample2, sample3) }
|
|
48
|
+
|
|
49
|
+
it "shouldparse a snippet without warnings" do
|
|
50
|
+
log_parser.should_receive(:handle_request).exactly(3).times
|
|
51
|
+
log_parser.should_not_receive(:warn)
|
|
52
|
+
log_parser.parse_io(snippet)
|
|
46
53
|
end
|
|
47
|
-
|
|
48
54
|
end
|
|
49
|
-
|
|
50
|
-
end
|
|
55
|
+
end
|
|
@@ -1,69 +1,82 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe RequestLogAnalyzer::FileFormat::
|
|
3
|
+
describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
subject { RequestLogAnalyzer::FileFormat.load(:rails3) }
|
|
6
|
+
|
|
7
|
+
it { should be_well_formed }
|
|
8
|
+
it { should have(9).report_trackers }
|
|
8
9
|
|
|
9
10
|
describe '#parse_line' do
|
|
10
|
-
before(:each) { @file_format = RequestLogAnalyzer::FileFormat.load(:rails3) }
|
|
11
11
|
|
|
12
12
|
it "should parse :started lines correctly" do
|
|
13
13
|
line = 'Started GET "/queries" for 127.0.0.1 at Thu Feb 25 16:15:18 -0800 2010'
|
|
14
|
-
|
|
14
|
+
subject.should parse_line(line).as(:started).and_capture(:method => 'GET',
|
|
15
15
|
:path => '/queries', :ip => '127.0.0.1', :timestamp => 20100225161518)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
it "should parse :started lines in Oct, Nov and Dec correctly" do
|
|
19
19
|
line = 'Started GET "/queries" for 127.0.0.1 at Thu Oct 25 16:15:18 -0800 2010'
|
|
20
|
-
|
|
20
|
+
subject.should parse_line(line).as(:started).and_capture(:method => 'GET',
|
|
21
21
|
:path => '/queries', :ip => '127.0.0.1', :timestamp => 20101025161518)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it "should parse :started lines in Ruby 1.9.2 format correctly" do
|
|
25
25
|
line = 'Started GET "/queries" for 127.0.0.1 at 2010-10-26 02:27:15 +0000'
|
|
26
|
-
|
|
26
|
+
subject.should parse_line(line).as(:started).and_capture(:method => 'GET',
|
|
27
27
|
:path => '/queries', :ip => '127.0.0.1', :timestamp => 20101026022715)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it "should parse :processing lines correctly" do
|
|
31
31
|
line = ' Processing by QueriesController#index as HTML'
|
|
32
|
-
|
|
32
|
+
subject.should parse_line(line).as(:processing).and_capture(
|
|
33
33
|
:controller => 'QueriesController', :action => 'index', :format => 'HTML')
|
|
34
34
|
end
|
|
35
|
+
|
|
35
36
|
it "should parse nested :processing lines correctly" do
|
|
36
37
|
line = ' Processing by Projects::QueriesController#index as HTML'
|
|
37
|
-
|
|
38
|
+
subject.should parse_line(line).as(:processing).and_capture(
|
|
38
39
|
:controller => 'Projects::QueriesController', :action => 'index', :format => 'HTML')
|
|
39
40
|
end
|
|
41
|
+
|
|
40
42
|
it "should parse :processing lines correctly with format */*" do
|
|
41
43
|
line = ' Processing by ProjectsController#avatar as */*'
|
|
42
|
-
|
|
44
|
+
subject.should parse_line(line).as(:processing).and_capture(
|
|
43
45
|
:controller => 'ProjectsController', :action => 'avatar', :format => '*/*')
|
|
44
46
|
end
|
|
47
|
+
|
|
48
|
+
it "should parse :processing lines correctly without format" do
|
|
49
|
+
line = ' Processing by ProjectsController#avatar as '
|
|
50
|
+
subject.should parse_line(line).as(:processing).and_capture(
|
|
51
|
+
:controller => 'ProjectsController', :action => 'avatar', :format => '')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should parse a :parameters line correctly" do
|
|
55
|
+
line = ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
|
56
|
+
subject.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
|
|
57
|
+
end
|
|
45
58
|
|
|
46
59
|
it "should parse :completed lines correctly" do
|
|
47
60
|
line = 'Completed 200 OK in 170ms (Views: 78.0ms | ActiveRecord: 48.2ms)'
|
|
48
|
-
|
|
61
|
+
subject.should parse_line(line).as(:completed).and_capture(
|
|
49
62
|
:duration => 0.170, :view => 0.078, :db => 0.0482, :status => 200)
|
|
50
63
|
end
|
|
51
64
|
|
|
52
65
|
it "should parse :completed lines correctly when ActiveRecord is not mentioned" do
|
|
53
66
|
line = 'Completed 200 OK in 364ms (Views: 31.4ms)'
|
|
54
|
-
|
|
67
|
+
subject.should parse_line(line).as(:completed).and_capture(:duration => 0.364, :status => 200)
|
|
55
68
|
end
|
|
56
69
|
|
|
57
70
|
it "should parse :completed lines correctly when other durations are specified" do
|
|
58
71
|
line = 'Completed 200 OK in 384ms (Views: 222.0ms | ActiveRecord: 121.0ms | Sphinx: 0.0ms)'
|
|
59
|
-
|
|
72
|
+
subject.should parse_line(line).as(:completed).and_capture(:duration => 0.384, :view => 0.222,
|
|
60
73
|
:db => 0.121, :status => 200)
|
|
61
74
|
end
|
|
62
75
|
|
|
63
76
|
|
|
64
77
|
it "should pase :failure lines correctly" do
|
|
65
78
|
line = "ActionView::Template::Error (undefined local variable or method `field' for #<Class>) on line #3 of /Users/willem/Code/warehouse/app/views/queries/execute.csv.erb:"
|
|
66
|
-
|
|
79
|
+
subject.should parse_line(line).as(:failure).and_capture(:line => 3,
|
|
67
80
|
:error => 'ActionView::Template::Error',
|
|
68
81
|
:message => "undefined local variable or method `field' for #<Class>",
|
|
69
82
|
:file => '/Users/willem/Code/warehouse/app/views/queries/execute.csv.erb')
|
|
@@ -71,10 +84,8 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
71
84
|
end
|
|
72
85
|
|
|
73
86
|
describe '#parse_io' do
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
|
|
87
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
88
|
+
|
|
78
89
|
it "should parse a successful request correctly" do
|
|
79
90
|
log = <<-EOLOG
|
|
80
91
|
Started GET "/" for 127.0.0.1 at Fri Mar 19 06:40:41 -0700 2010
|
|
@@ -85,12 +96,9 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
85
96
|
Completed 200 OK in 170ms (Views: 78.4ms | ActiveRecord: 48.2ms)
|
|
86
97
|
EOLOG
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@log_parser.parse_io(StringIO.new(log)) do |request|
|
|
92
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
|
93
|
-
end
|
|
99
|
+
log_parser.should_receive(:handle_request).once
|
|
100
|
+
log_parser.should_not_receive(:warn)
|
|
101
|
+
log_parser.parse_string(log)
|
|
94
102
|
end
|
|
95
103
|
|
|
96
104
|
it "should parse an unroutable request correctly" do
|
|
@@ -104,12 +112,9 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
104
112
|
|
|
105
113
|
EOLOG
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@log_parser.parse_io(StringIO.new(log)) do |request|
|
|
111
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
|
112
|
-
end
|
|
115
|
+
log_parser.should_receive(:handle_request).once
|
|
116
|
+
log_parser.should_not_receive(:warn)
|
|
117
|
+
log_parser.parse_string(log)
|
|
113
118
|
end
|
|
114
119
|
|
|
115
120
|
it "should parse a failing request correctly" do
|
|
@@ -136,12 +141,9 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
136
141
|
|
|
137
142
|
EOLOG
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
@log_parser.parse_io(StringIO.new(log)) do |request|
|
|
143
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
|
144
|
-
end
|
|
144
|
+
log_parser.should_receive(:handle_request).once
|
|
145
|
+
log_parser.should_not_receive(:warn)
|
|
146
|
+
log_parser.parse_string(log)
|
|
145
147
|
end
|
|
146
148
|
end
|
|
147
149
|
end
|