request-log-analyzer 1.13.1 → 1.13.3
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/bin/console +17 -0
- data/lib/cli/command_line_arguments.rb +29 -36
- data/lib/cli/database_console.rb +1 -3
- data/lib/cli/database_console_init.rb +11 -11
- data/lib/cli/progressbar.rb +30 -32
- data/lib/cli/tools.rb +20 -23
- data/lib/request_log_analyzer.rb +8 -8
- data/lib/request_log_analyzer/aggregator.rb +4 -7
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +10 -13
- data/lib/request_log_analyzer/aggregator/echo.rb +5 -7
- data/lib/request_log_analyzer/aggregator/summarizer.rb +15 -18
- data/lib/request_log_analyzer/class_level_inheritable_attributes.rb +23 -0
- data/lib/request_log_analyzer/controller.rb +36 -42
- data/lib/request_log_analyzer/database.rb +4 -6
- data/lib/request_log_analyzer/database/base.rb +39 -41
- data/lib/request_log_analyzer/database/connection.rb +8 -10
- data/lib/request_log_analyzer/database/request.rb +1 -3
- data/lib/request_log_analyzer/database/source.rb +0 -2
- data/lib/request_log_analyzer/database/warning.rb +4 -6
- data/lib/request_log_analyzer/file_format.rb +46 -49
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +15 -19
- data/lib/request_log_analyzer/file_format/apache.rb +42 -45
- data/lib/request_log_analyzer/file_format/delayed_job.rb +13 -15
- data/lib/request_log_analyzer/file_format/delayed_job2.rb +9 -11
- data/lib/request_log_analyzer/file_format/delayed_job21.rb +9 -11
- data/lib/request_log_analyzer/file_format/delayed_job3.rb +5 -8
- data/lib/request_log_analyzer/file_format/delayed_job4.rb +5 -8
- data/lib/request_log_analyzer/file_format/haproxy.rb +44 -48
- data/lib/request_log_analyzer/file_format/merb.rb +13 -17
- data/lib/request_log_analyzer/file_format/mysql.rb +21 -25
- data/lib/request_log_analyzer/file_format/nginx.rb +0 -2
- data/lib/request_log_analyzer/file_format/oink.rb +30 -31
- data/lib/request_log_analyzer/file_format/postgresql.rb +11 -15
- data/lib/request_log_analyzer/file_format/rack.rb +0 -2
- data/lib/request_log_analyzer/file_format/rails.rb +100 -104
- data/lib/request_log_analyzer/file_format/rails3.rb +19 -23
- data/lib/request_log_analyzer/file_format/rails_development.rb +0 -1
- data/lib/request_log_analyzer/file_format/w3c.rb +16 -18
- data/lib/request_log_analyzer/filter.rb +0 -2
- data/lib/request_log_analyzer/filter/anonymize.rb +4 -7
- data/lib/request_log_analyzer/filter/field.rb +3 -6
- data/lib/request_log_analyzer/filter/timespan.rb +2 -6
- data/lib/request_log_analyzer/line_definition.rb +16 -19
- data/lib/request_log_analyzer/log_processor.rb +10 -14
- data/lib/request_log_analyzer/mailer.rb +9 -12
- data/lib/request_log_analyzer/output.rb +12 -14
- data/lib/request_log_analyzer/output/fixed_width.rb +21 -28
- data/lib/request_log_analyzer/output/html.rb +11 -14
- data/lib/request_log_analyzer/request.rb +53 -33
- data/lib/request_log_analyzer/source.rb +2 -5
- data/lib/request_log_analyzer/source/log_parser.rb +9 -16
- data/lib/request_log_analyzer/tracker.rb +10 -12
- data/lib/request_log_analyzer/tracker/duration.rb +4 -6
- data/lib/request_log_analyzer/tracker/frequency.rb +9 -11
- data/lib/request_log_analyzer/tracker/hourly_spread.rb +8 -11
- data/lib/request_log_analyzer/tracker/numeric_value.rb +40 -44
- data/lib/request_log_analyzer/tracker/timespan.rb +5 -8
- data/lib/request_log_analyzer/tracker/traffic.rb +8 -10
- data/lib/request_log_analyzer/version.rb +1 -1
- data/request-log-analyzer.gemspec +6 -6
- data/spec/integration/command_line_usage_spec.rb +33 -33
- data/spec/integration/mailer_spec.rb +181 -185
- data/spec/integration/munin_plugins_rails_spec.rb +20 -20
- data/spec/integration/scout_spec.rb +40 -41
- data/spec/lib/helpers.rb +8 -9
- data/spec/lib/macros.rb +2 -4
- data/spec/lib/matchers.rb +20 -25
- data/spec/lib/mocks.rb +10 -11
- data/spec/lib/testing_format.rb +8 -10
- data/spec/spec_helper.rb +5 -1
- data/spec/unit/aggregator/database_inserter_spec.rb +23 -23
- data/spec/unit/aggregator/summarizer_spec.rb +7 -7
- data/spec/unit/controller/controller_spec.rb +14 -14
- data/spec/unit/controller/log_processor_spec.rb +3 -3
- data/spec/unit/database/base_class_spec.rb +36 -37
- data/spec/unit/database/connection_spec.rb +10 -10
- data/spec/unit/database/database_spec.rb +11 -11
- data/spec/unit/file_format/amazon_s3_format_spec.rb +66 -62
- data/spec/unit/file_format/apache_format_spec.rb +57 -52
- data/spec/unit/file_format/common_regular_expressions_spec.rb +18 -21
- data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -16
- data/spec/unit/file_format/delayed_job2_format_spec.rb +22 -16
- data/spec/unit/file_format/delayed_job3_format_spec.rb +14 -10
- data/spec/unit/file_format/delayed_job4_format_spec.rb +14 -10
- data/spec/unit/file_format/delayed_job_format_spec.rb +12 -12
- data/spec/unit/file_format/file_format_api_spec.rb +19 -19
- data/spec/unit/file_format/format_autodetection_spec.rb +7 -7
- data/spec/unit/file_format/haproxy_format_spec.rb +53 -49
- data/spec/unit/file_format/inheritance_spec.rb +13 -0
- data/spec/unit/file_format/line_definition_spec.rb +35 -33
- data/spec/unit/file_format/merb_format_spec.rb +13 -11
- data/spec/unit/file_format/mysql_format_spec.rb +24 -24
- data/spec/unit/file_format/oink_format_spec.rb +29 -29
- data/spec/unit/file_format/postgresql_format_spec.rb +9 -9
- data/spec/unit/file_format/rack_format_spec.rb +36 -31
- data/spec/unit/file_format/rails3_format_spec.rb +46 -46
- data/spec/unit/file_format/rails_format_spec.rb +52 -53
- data/spec/unit/file_format/w3c_format_spec.rb +27 -24
- data/spec/unit/filter/anonymize_filter_spec.rb +7 -7
- data/spec/unit/filter/field_filter_spec.rb +26 -26
- data/spec/unit/filter/filter_spec.rb +4 -4
- data/spec/unit/filter/timespan_filter_spec.rb +22 -22
- data/spec/unit/mailer_spec.rb +21 -21
- data/spec/unit/request_spec.rb +29 -29
- data/spec/unit/source/log_parser_spec.rb +5 -5
- data/spec/unit/tracker/duration_tracker_spec.rb +23 -23
- data/spec/unit/tracker/frequency_tracker_spec.rb +29 -30
- data/spec/unit/tracker/hourly_spread_spec.rb +35 -35
- data/spec/unit/tracker/numeric_value_tracker_spec.rb +71 -72
- data/spec/unit/tracker/timespan_tracker_spec.rb +31 -31
- data/spec/unit/tracker/tracker_api_spec.rb +43 -44
- data/spec/unit/tracker/traffic_tracker_spec.rb +7 -7
- metadata +38 -35
|
@@ -5,108 +5,108 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
|
5
5
|
subject { RequestLogAnalyzer::FileFormat.load(:rails3) }
|
|
6
6
|
|
|
7
7
|
it { should be_well_formed }
|
|
8
|
-
it { should
|
|
8
|
+
it { should satisfy { |ff| ff.report_trackers.length == 11 } }
|
|
9
9
|
|
|
10
10
|
describe '#parse_line' do
|
|
11
11
|
|
|
12
|
-
it
|
|
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
|
-
subject.should parse_line(line).as(:started).and_capture(:
|
|
15
|
-
:
|
|
14
|
+
subject.should parse_line(line).as(:started).and_capture(method: 'GET',
|
|
15
|
+
path: '/queries', ip: '127.0.0.1', timestamp: 20_100_225_161_518)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
it
|
|
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
|
-
subject.should parse_line(line).as(:started).and_capture(:
|
|
21
|
-
:
|
|
20
|
+
subject.should parse_line(line).as(:started).and_capture(method: 'GET',
|
|
21
|
+
path: '/queries', ip: '127.0.0.1', timestamp: 20_101_025_161_518)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
it
|
|
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
|
-
subject.should parse_line(line).as(:started).and_capture(:
|
|
27
|
-
:
|
|
26
|
+
subject.should parse_line(line).as(:started).and_capture(method: 'GET',
|
|
27
|
+
path: '/queries', ip: '127.0.0.1', timestamp: 20_101_026_022_715)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
it
|
|
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
|
|
36
|
+
it 'should parse nested :processing lines correctly' do
|
|
37
37
|
line = ' Processing by Projects::QueriesController#index as HTML'
|
|
38
38
|
subject.should parse_line(line).as(:processing).and_capture(
|
|
39
|
-
:
|
|
39
|
+
controller: 'Projects::QueriesController', action: 'index', format: 'HTML')
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
it
|
|
42
|
+
it 'should parse :processing lines correctly with format */*' do
|
|
43
43
|
line = ' Processing by ProjectsController#avatar as */*'
|
|
44
44
|
subject.should parse_line(line).as(:processing).and_capture(
|
|
45
|
-
:
|
|
45
|
+
controller: 'ProjectsController', action: 'avatar', format: '*/*')
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
it
|
|
48
|
+
it 'should parse :processing lines correctly without format' do
|
|
49
49
|
line = ' Processing by ProjectsController#avatar as '
|
|
50
50
|
subject.should parse_line(line).as(:processing).and_capture(
|
|
51
|
-
:
|
|
51
|
+
controller: 'ProjectsController', action: 'avatar', format: '')
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
it
|
|
54
|
+
it 'should parse a :parameters line correctly' do
|
|
55
55
|
line = ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
|
56
|
-
subject.should parse_line(line).as(:parameters).and_capture(:
|
|
56
|
+
subject.should parse_line(line).as(:parameters).and_capture(params: { action: 'cached', controller: 'cached' })
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
it
|
|
59
|
+
it 'should parse a :parameters line with no indentation correctly' do
|
|
60
60
|
line = 'Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
|
61
|
-
subject.should parse_line(line).as(:parameters).and_capture(:
|
|
61
|
+
subject.should parse_line(line).as(:parameters).and_capture(params: { action: 'cached', controller: 'cached' })
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
it
|
|
64
|
+
it 'should parse :completed lines correctly' do
|
|
65
65
|
line = 'Completed 200 OK in 170ms (Views: 78.0ms | ActiveRecord: 48.2ms)'
|
|
66
66
|
subject.should parse_line(line).as(:completed).and_capture(
|
|
67
|
-
:
|
|
67
|
+
duration: 0.170, view: 0.078, db: 0.0482, status: 200)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
it
|
|
70
|
+
it 'should parse :completed lines correctly when ActiveRecord is not mentioned' do
|
|
71
71
|
line = 'Completed 200 OK in 364ms (Views: 31.4ms)'
|
|
72
|
-
subject.should parse_line(line).as(:completed).and_capture(:
|
|
72
|
+
subject.should parse_line(line).as(:completed).and_capture(duration: 0.364, status: 200)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
it
|
|
75
|
+
it 'should parse :completed lines correctly when other durations are specified' do
|
|
76
76
|
line = 'Completed 200 OK in 384ms (Views: 222.0ms | ActiveRecord: 121.0ms | Sphinx: 0.0ms)'
|
|
77
|
-
subject.should parse_line(line).as(:completed).and_capture(:
|
|
78
|
-
:
|
|
77
|
+
subject.should parse_line(line).as(:completed).and_capture(duration: 0.384, view: 0.222,
|
|
78
|
+
db: 0.121, status: 200)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
it
|
|
81
|
+
it 'should parse :routing_error lines correctly' do
|
|
82
82
|
line = "ActionController::RoutingError (No route matches [GET] \"/static/faq\"):"
|
|
83
|
-
subject.should parse_line(line).as(:routing_errors).and_capture(:
|
|
84
|
-
|
|
83
|
+
subject.should parse_line(line).as(:routing_errors).and_capture(missing_resource_method: 'GET',
|
|
84
|
+
missing_resource: '/static/faq')
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
it
|
|
87
|
+
it 'should parse :failure lines correctly' do
|
|
88
88
|
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:"
|
|
89
|
-
subject.should parse_line(line).as(:failure).and_capture(:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
subject.should parse_line(line).as(:failure).and_capture(line: 3,
|
|
90
|
+
error: 'ActionView::Template::Error',
|
|
91
|
+
message: "undefined local variable or method `field' for #<Class>",
|
|
92
|
+
file: '/Users/willem/Code/warehouse/app/views/queries/execute.csv.erb')
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
it
|
|
96
|
-
line =
|
|
97
|
-
subject.should parse_line(line).as(:rendered).and_capture(:
|
|
95
|
+
it 'should parse :rendered lines as an array' do
|
|
96
|
+
line = ' Rendered queries/index.html.erb (0.6ms)'
|
|
97
|
+
subject.should parse_line(line).as(:rendered).and_capture(partial_duration: [0.0006])
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
-
it
|
|
101
|
-
line =
|
|
102
|
-
subject.should parse_line(line).as(:rendered).and_capture(:
|
|
100
|
+
it 'should parse :rendered lines with no identation as an array' do
|
|
101
|
+
line = 'Rendered queries/index.html.erb (0.6ms)'
|
|
102
|
+
subject.should parse_line(line).as(:rendered).and_capture(partial_duration: [0.0006])
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
describe '#parse_io' do
|
|
107
107
|
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
108
108
|
|
|
109
|
-
it
|
|
109
|
+
it 'should parse a successful request correctly' do
|
|
110
110
|
log = <<-EOLOG
|
|
111
111
|
Started GET "/" for 127.0.0.1 at Fri Mar 19 06:40:41 -0700 2010
|
|
112
112
|
Processing by QueriesController#index as HTML
|
|
@@ -121,7 +121,7 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
|
121
121
|
log_parser.parse_string(log)
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
-
it
|
|
124
|
+
it 'should count partials correctly' do
|
|
125
125
|
log = <<-EOLOG
|
|
126
126
|
Started GET "/stream_support" for 127.0.0.1 at 2012-11-21 15:21:31 +0100
|
|
127
127
|
Processing by HomeController#stream_support as */*
|
|
@@ -133,7 +133,7 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
|
133
133
|
log_parser.parse_string(log)
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
-
it
|
|
136
|
+
it 'should parse a failing request correctly' do
|
|
137
137
|
log = <<-EOLOG
|
|
138
138
|
Started POST "/queries/397638749/execute.csv" for 127.0.0.1 at Mon Mar 01 18:44:33 -0800 2010
|
|
139
139
|
Processing by QueriesController#execute as CSV
|
|
@@ -5,12 +5,12 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
5
5
|
describe '.create' do
|
|
6
6
|
|
|
7
7
|
context 'without providing a lines argument' do
|
|
8
|
-
subject { RequestLogAnalyzer::FileFormat::Rails.create }
|
|
8
|
+
subject { RequestLogAnalyzer::FileFormat::Rails.create }
|
|
9
9
|
|
|
10
10
|
it { should be_well_formed }
|
|
11
|
-
it { should
|
|
11
|
+
it { should satisfy { |ff| ff.report_trackers.length >= 11 } }
|
|
12
12
|
|
|
13
|
-
it
|
|
13
|
+
it 'should parse the lines in the production set' do
|
|
14
14
|
subject.line_definitions.should == RequestLogAnalyzer::FileFormat.load(:rails, 'production').line_definitions
|
|
15
15
|
end
|
|
16
16
|
end
|
|
@@ -19,8 +19,8 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
19
19
|
subject { RequestLogAnalyzer::FileFormat.load(:rails, 'minimal,failure') }
|
|
20
20
|
|
|
21
21
|
it { should be_well_formed }
|
|
22
|
-
it { should
|
|
23
|
-
|
|
22
|
+
it { should satisfy { |ff| ff.report_trackers.length >= 10 } }
|
|
23
|
+
|
|
24
24
|
it { should have_line_definition(:processing) }
|
|
25
25
|
it { should have_line_definition(:completed) }
|
|
26
26
|
it { should have_line_definition(:failure) }
|
|
@@ -32,102 +32,101 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
32
32
|
subject { RequestLogAnalyzer::FileFormat.load(:rails, constant) }
|
|
33
33
|
|
|
34
34
|
it { should be_well_formed }
|
|
35
|
-
it { should
|
|
35
|
+
it { should satisfy { |ff| ff.report_trackers.length >= 9 } }
|
|
36
36
|
|
|
37
37
|
it { should have_line_definition(:processing) }
|
|
38
38
|
it { should have_line_definition(:completed) }
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
subject { RequestLogAnalyzer::FileFormat.load(:rails, :all) }
|
|
44
44
|
|
|
45
45
|
describe '#parse_line' do
|
|
46
46
|
|
|
47
|
-
{'with prefix' => 'LINE PREFIX: ', 'without prefix' => '' }.each do |context, prefix|
|
|
47
|
+
{ 'with prefix' => 'LINE PREFIX: ', 'without prefix' => '' }.each do |context, prefix|
|
|
48
48
|
context context do
|
|
49
|
-
it
|
|
49
|
+
it 'should parse a :processing line correctly' do
|
|
50
50
|
line = prefix + 'Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]'
|
|
51
|
-
subject.should parse_line(line).as(:processing).and_capture(:
|
|
51
|
+
subject.should parse_line(line).as(:processing).and_capture(controller: 'PeopleController', action: 'index', timestamp: 20_080_814_211_630, method: 'GET', ip: '1.1.1.1')
|
|
52
52
|
end
|
|
53
|
-
|
|
54
|
-
it
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
|
|
54
|
+
it 'should parse a :processing line correctly when it contains ipv6 localhost address' do
|
|
55
|
+
line = prefix + 'Processing PeopleController#index (for ::1 at 2008-08-14 21:16:30) [GET]'
|
|
56
|
+
subject.should parse_line(line).as(:processing).and_capture(controller: 'PeopleController', action: 'index', timestamp: 20_080_814_211_630, method: 'GET', ip: '::1')
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
it
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
it 'should parse a :processing line correctly when it contains ipv6 address' do
|
|
60
|
+
line = prefix + 'Processing PeopleController#index (for 3ffe:1900:4545:3:200:f8ff:fe21:67cf at 2008-08-14 21:16:30) [GET]'
|
|
61
|
+
subject.should parse_line(line).as(:processing).and_capture(controller: 'PeopleController', action: 'index', timestamp: 20_080_814_211_630, method: 'GET', ip: '3ffe:1900:4545:3:200:f8ff:fe21:67cf')
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
it
|
|
64
|
+
it 'should parse a Rails 2.1 style :completed line correctly' do
|
|
65
65
|
line = prefix + 'Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]'
|
|
66
|
-
subject.should parse_line(line).as(:completed).and_capture(:
|
|
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')
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
it
|
|
69
|
+
it 'should parse a Rails 2.2 style :completed line correctly' do
|
|
70
70
|
line = prefix + 'Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]'
|
|
71
|
-
subject.should parse_line(line).as(:completed).and_capture(:
|
|
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')
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
it
|
|
74
|
+
it 'should parse a Rails 2.2 style :completed line correctly when AR is disabled' do
|
|
75
75
|
line = prefix + 'Completed in 597ms (View: 298 | 200 OK [http://shapado.com]'
|
|
76
|
-
subject.should parse_line(line).as(:completed).and_capture(:
|
|
76
|
+
subject.should parse_line(line).as(:completed).and_capture(duration: 0.597, db: nil, view: 0.298, status: 200, url: 'http://shapado.com')
|
|
77
77
|
end
|
|
78
|
-
|
|
79
|
-
it
|
|
80
|
-
line = prefix +
|
|
81
|
-
subject.should parse_line(line).as(:completed).and_capture(:
|
|
78
|
+
|
|
79
|
+
it 'should parse a Rails 2.2 style :completed line without view' do
|
|
80
|
+
line = prefix + 'Completed in 148ms (DB: 0) | 302 Found [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')
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
it
|
|
84
|
+
it 'should parse a :failure line with exception correctly' do
|
|
85
85
|
line = prefix + "NoMethodError (undefined method `update_domain_account' for nil:NilClass):"
|
|
86
|
-
subject.should parse_line(line).as(:failure).and_capture(:
|
|
86
|
+
subject.should parse_line(line).as(:failure).and_capture(error: 'NoMethodError', message: "undefined method `update_domain_account' for nil:NilClass")
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
it
|
|
89
|
+
it 'should parse a :cache_hit line correctly with an filter instance reference' do
|
|
90
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.'
|
|
91
91
|
subject.should parse_line(line).as(:cache_hit)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
it
|
|
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.'
|
|
94
|
+
it 'should parse a :cache_hit line correctly with an proc instance reference' do
|
|
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.'
|
|
96
96
|
subject.should parse_line(line).as(:cache_hit)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
it "should parse a :parameters line correctly" do
|
|
99
|
+
it 'should parse a :parameters line correctly' do
|
|
101
100
|
line = prefix + ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
|
102
|
-
subject.should parse_line(line).as(:parameters).and_capture(:
|
|
101
|
+
subject.should parse_line(line).as(:parameters).and_capture(params: { action: 'cached', controller: 'cached' })
|
|
103
102
|
end
|
|
104
103
|
|
|
105
|
-
it
|
|
104
|
+
it 'should parse a :rendered line correctly' do
|
|
106
105
|
line = prefix + 'Rendered layouts/_footer (2.9ms)'
|
|
107
|
-
subject.should parse_line(line).as(:rendered).and_capture(:
|
|
106
|
+
subject.should parse_line(line).as(:rendered).and_capture(render_file: 'layouts/_footer', render_duration: 0.0029)
|
|
108
107
|
end
|
|
109
108
|
|
|
110
|
-
it
|
|
109
|
+
it 'should parse a :query_executed line with colors' do
|
|
111
110
|
line = prefix + ' [4;36;1mUser Load (0.4ms)[0m [0;1mSELECT * FROM `users` WHERE (`users`.`id` = 18205844) [0m'
|
|
112
|
-
subject.should parse_line(line).as(:query_executed).and_capture(:
|
|
111
|
+
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)')
|
|
113
112
|
end
|
|
114
113
|
|
|
115
|
-
it
|
|
114
|
+
it 'should parse a :query_executed line without colors' do
|
|
116
115
|
line = prefix + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
|
|
117
|
-
subject.should parse_line(line).as(:query_executed).and_capture(:
|
|
116
|
+
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)')
|
|
118
117
|
end
|
|
119
118
|
|
|
120
|
-
it
|
|
119
|
+
it 'should parse a :query_cached line with colors' do
|
|
121
120
|
line = prefix + ' [4;35;1mCACHE (0.0ms)[0m [0mSELECT * FROM `users` WHERE (`users`.`id` = 0) [0m'
|
|
122
|
-
subject.should parse_line(line).as(:query_cached).and_capture(:
|
|
121
|
+
subject.should parse_line(line).as(:query_cached).and_capture(cached_duration: 0.0, cached_sql: 'SELECT * FROM users WHERE (users.id = :int)')
|
|
123
122
|
end
|
|
124
123
|
|
|
125
|
-
it
|
|
124
|
+
it 'should parse a :query_cached line without colors' do
|
|
126
125
|
line = prefix + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
|
|
127
|
-
subject.should parse_line(line).as(:query_cached).and_capture(:
|
|
126
|
+
subject.should parse_line(line).as(:query_cached).and_capture(cached_duration: 0.0, cached_sql: 'SELECT * FROM users WHERE (users.id = :int)')
|
|
128
127
|
end
|
|
129
128
|
|
|
130
|
-
it
|
|
129
|
+
it 'should not parse an unsupported line' do
|
|
131
130
|
line = prefix + 'nonsense line that should not be parsed as anything'
|
|
132
131
|
subject.should_not parse_line(line)
|
|
133
132
|
end
|
|
@@ -136,27 +135,27 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
136
135
|
end
|
|
137
136
|
|
|
138
137
|
describe '#parse_io' do
|
|
139
|
-
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject, :
|
|
138
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject, parse_strategy: 'cautious') }
|
|
140
139
|
|
|
141
|
-
it
|
|
140
|
+
it 'should parse a Rails 2.1 style log and find valid Rails requests without warnings' do
|
|
142
141
|
log_parser.should_receive(:handle_request).exactly(4).times
|
|
143
142
|
log_parser.should_not_receive(:warn)
|
|
144
|
-
log_parser.parse_file(log_fixture(:rails_1x))
|
|
143
|
+
log_parser.parse_file(log_fixture(:rails_1x))
|
|
145
144
|
end
|
|
146
145
|
|
|
147
|
-
it
|
|
146
|
+
it 'should parse a Rails 2.2 style log and find valid Rails requests without warnings' do
|
|
148
147
|
log_parser.should_receive(:handle_request).once
|
|
149
148
|
log_parser.should_not_receive(:warn)
|
|
150
149
|
log_parser.parse_file(log_fixture(:rails_22))
|
|
151
150
|
end
|
|
152
151
|
|
|
153
|
-
it
|
|
152
|
+
it 'should parse a Rails SyslogLogger file with prefix and find valid requests without warnings' do
|
|
154
153
|
log_parser.should_receive(:handle_request).once
|
|
155
154
|
log_parser.should_not_receive(:warn)
|
|
156
155
|
log_parser.parse_file(log_fixture(:syslog_1x))
|
|
157
156
|
end
|
|
158
157
|
|
|
159
|
-
it
|
|
158
|
+
it 'should parse cached requests' do
|
|
160
159
|
log_parser.should_not_receive(:warn)
|
|
161
160
|
log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
|
|
162
161
|
request.should be_completed
|
|
@@ -164,7 +163,7 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
|
164
163
|
end
|
|
165
164
|
end
|
|
166
165
|
|
|
167
|
-
it
|
|
166
|
+
it 'should detect unordered requests in the logs' do
|
|
168
167
|
log_parser.should_not_receive(:handle_request)
|
|
169
168
|
log_parser.should_receive(:warn).with(:unclosed_request, anything).once
|
|
170
169
|
log_parser.should_receive(:warn).with(:no_current_request, anything).at_least(:twice)
|
|
@@ -5,40 +5,43 @@ describe RequestLogAnalyzer::FileFormat::W3c do
|
|
|
5
5
|
subject { RequestLogAnalyzer::FileFormat.load(:w3c) }
|
|
6
6
|
|
|
7
7
|
it { should be_well_formed }
|
|
8
|
-
it
|
|
9
|
-
|
|
8
|
+
it do
|
|
9
|
+
should have_line_definition(:access).capturing(:timestamp, :remote_ip, :username, :local_ip, :port,
|
|
10
|
+
:method, :path, :http_status, :bytes_sent, :bytes_received, :duration, :user_agent, :referer)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it { should satisfy { |ff| ff.report_trackers.length == 10 } }
|
|
10
14
|
|
|
11
|
-
it { should have(10).report_trackers }
|
|
12
|
-
|
|
13
15
|
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
16
|
let(:irrelevant) { '#Software: Microsoft Internet Information Services 6.0' }
|
|
15
|
-
|
|
17
|
+
|
|
16
18
|
describe '#parse_line' do
|
|
17
|
-
it
|
|
18
|
-
|
|
19
|
-
:
|
|
20
|
-
:
|
|
21
|
-
:
|
|
22
|
-
:
|
|
23
|
-
:
|
|
24
|
-
:
|
|
25
|
-
:
|
|
26
|
-
:
|
|
27
|
-
:
|
|
28
|
-
:
|
|
29
|
-
:
|
|
30
|
-
:
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
it do
|
|
20
|
+
should parse_line(sample1, 'an access line').and_capture(
|
|
21
|
+
timestamp: 20_020_524_201_801,
|
|
22
|
+
remote_ip: '172.224.24.114',
|
|
23
|
+
username: nil,
|
|
24
|
+
local_ip: '206.73.118.24',
|
|
25
|
+
port: 80,
|
|
26
|
+
method: 'GET',
|
|
27
|
+
path: '/Default.htm',
|
|
28
|
+
http_status: 200,
|
|
29
|
+
bytes_sent: 7930,
|
|
30
|
+
bytes_received: 248,
|
|
31
|
+
duration: 0.031,
|
|
32
|
+
user_agent: 'Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server)',
|
|
33
|
+
referer: 'http://64.224.24.114/')
|
|
34
|
+
end
|
|
35
|
+
|
|
33
36
|
it { should_not parse_line(irrelevant, 'an irrelevant line') }
|
|
34
37
|
it { should_not parse_line('nonsense', 'a nonsense line') }
|
|
35
38
|
end
|
|
36
|
-
|
|
39
|
+
|
|
37
40
|
describe '#parse_io' do
|
|
38
41
|
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
|
39
42
|
let(:snippet) { log_snippet(irrelevant, sample1, sample1) }
|
|
40
|
-
|
|
41
|
-
it
|
|
43
|
+
|
|
44
|
+
it 'should parse a snippet successully without warnings' do
|
|
42
45
|
log_parser.should_receive(:handle_request).twice
|
|
43
46
|
log_parser.should_not_receive(:warn)
|
|
44
47
|
log_parser.parse_io(snippet)
|
|
@@ -6,16 +6,16 @@ describe RequestLogAnalyzer::Filter::Anonymize, 'anonymize request' do
|
|
|
6
6
|
@filter = RequestLogAnalyzer::Filter::Anonymize.new(testing_format)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
it
|
|
10
|
-
@filter.filter(request(:
|
|
9
|
+
it 'should anonimize ip' do
|
|
10
|
+
@filter.filter(request(ip: '123.123.123.123'))[:ip].should_not eql('123.123.123.123')
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
it
|
|
14
|
-
@filter.filter(request(:
|
|
13
|
+
it 'should anonimize url' do
|
|
14
|
+
@filter.filter(request(url: 'https://test.mysite.com/employees'))[:url].should eql('http://example.com/employees')
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
it
|
|
18
|
-
@filter.filter(request(:
|
|
17
|
+
it 'should fuzz durations' do
|
|
18
|
+
@filter.filter(request(duration: 100))[:duration].should_not eql(100)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
end
|
|
21
|
+
end
|