wvanbergen-request-log-analyzer 0.2.2 → 0.3.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/{README → README.textile} +29 -36
- data/Rakefile +3 -70
- data/TODO +43 -8
- data/bin/request-log-analyzer +32 -99
- data/lib/base/summarizer.rb +14 -0
- data/lib/bashcolorizer.rb +1 -1
- data/lib/command_line/arguments.rb +15 -2
- data/lib/command_line/flag.rb +12 -0
- data/lib/rails_analyzer/summarizer.rb +12 -4
- data/lib/rails_analyzer/virtual_mongrel.rb +91 -0
- data/lib/request_log_analyzer/aggregator/base.rb +34 -0
- data/lib/request_log_analyzer/aggregator/database.rb +86 -0
- data/lib/request_log_analyzer/aggregator/echo.rb +10 -0
- data/lib/request_log_analyzer/aggregator/summarizer.rb +53 -0
- data/lib/request_log_analyzer/controller.rb +90 -0
- data/lib/request_log_analyzer/file_format/merb.rb +30 -0
- data/lib/request_log_analyzer/file_format/rails.rb +84 -0
- data/lib/request_log_analyzer/file_format.rb +91 -0
- data/lib/request_log_analyzer/log_parser.rb +122 -0
- data/lib/request_log_analyzer/request.rb +72 -0
- data/lib/request_log_analyzer.rb +5 -0
- data/output/blockers.rb +2 -4
- data/output/errors.rb +1 -2
- data/output/hourly_spread.rb +3 -3
- data/output/mean_db_time.rb +1 -2
- data/output/mean_rendering_time.rb +2 -3
- data/output/mean_time.rb +2 -3
- data/output/most_requested.rb +1 -2
- data/output/timespan.rb +10 -8
- data/output/total_db_time.rb +2 -3
- data/output/total_time.rb +2 -3
- data/output/usage.rb +3 -2
- data/spec/controller_spec.rb +33 -0
- data/spec/database_inserter_spec.rb +81 -0
- data/{test/log_fragments/merb_1.log → spec/fixtures/merb.log} +0 -0
- data/spec/fixtures/multiple_files_1.log +5 -0
- data/spec/fixtures/multiple_files_2.log +2 -0
- data/{test/log_fragments/fragment_1.log → spec/fixtures/rails_1x.log} +5 -5
- data/{test/log_fragments/fragment_3.log → spec/fixtures/rails_22.log} +2 -2
- data/spec/fixtures/rails_22_cached.log +10 -0
- data/spec/fixtures/rails_unordered.log +24 -0
- data/{test/log_fragments/fragment_2.log → spec/fixtures/syslog_1x.log} +0 -0
- data/spec/fixtures/test_file_format.log +11 -0
- data/spec/fixtures/test_language_combined.log +14 -0
- data/spec/fixtures/test_order.log +16 -0
- data/spec/line_definition_spec.rb +34 -0
- data/spec/log_parser_spec.rb +92 -0
- data/spec/merb_format_spec.rb +58 -0
- data/spec/rails_format_spec.rb +95 -0
- data/spec/request_spec.rb +76 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/summarizer_spec.rb +109 -0
- data/tasks/github-gem.rake +177 -0
- data/tasks/request_log_analyzer.rake +10 -0
- data/tasks/rspec.rake +6 -0
- data/test/base_summarizer_test.rb +30 -0
- metadata +46 -22
- data/bin/request-log-database +0 -81
- data/lib/base/log_parser.rb +0 -78
- data/lib/base/record_inserter.rb +0 -139
- data/lib/merb_analyzer/log_parser.rb +0 -26
- data/lib/rails_analyzer/log_parser.rb +0 -35
- data/lib/rails_analyzer/record_inserter.rb +0 -39
- data/test/merb_log_parser_test.rb +0 -39
- data/test/rails_log_parser_test.rb +0 -95
- data/test/record_inserter_test.rb +0 -45
- data/test/tasks.rake +0 -8
data/output/blockers.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
# Print requests that took more than a second to complete, sorted by their frequency.
|
2
|
-
amount = $arguments[:amount] || 10
|
3
|
-
|
4
2
|
puts
|
5
|
-
puts "Mongrel process blockers (> #{
|
3
|
+
puts "Mongrel process blockers (> #{@summarizer.blocker_duration} seconds)"
|
6
4
|
puts green("========================================================================")
|
7
5
|
|
8
|
-
|
6
|
+
@summarizer.sort_blockers_by(:count).reverse[0, @amount].each do |a|
|
9
7
|
puts "%-50s: %10.03fs [#{green("%d requests")}]" % [a[0], a[1][:total_time], a[1][:count]]
|
10
8
|
end
|
11
9
|
|
data/output/errors.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# Print errors that occured often
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
3
|
puts "Errors"
|
5
4
|
puts green("========================================================================")
|
6
|
-
|
5
|
+
@summarizer.sort_errors_by(:count).reverse[0, @amount].each do |a|
|
7
6
|
puts "%s: [#{green("%d requests")}]" % [a[0] + 'Error', a[1][:count]]
|
8
7
|
puts blue(' -> ' + (a[1][:exception_strings].invert[ a[1][:exception_strings].values.max ])[0..79])
|
9
8
|
end
|
data/output/hourly_spread.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Draws a graph containing the average amound of requests per hour per day
|
2
|
-
if
|
2
|
+
if @summarizer.request_time_graph?
|
3
3
|
|
4
|
-
max_request_graph =
|
4
|
+
max_request_graph = @summarizer.request_time_graph.max / @summarizer.duration
|
5
5
|
deviation = max_request_graph / 20
|
6
6
|
deviation = 1 if deviation == 0
|
7
7
|
color_cutoff = 15
|
@@ -11,7 +11,7 @@ if $summarizer.request_time_graph?
|
|
11
11
|
puts green("========================================================================")
|
12
12
|
|
13
13
|
(0..23).each do |a|
|
14
|
-
requests =
|
14
|
+
requests = @summarizer.request_time_graph[a] / @summarizer.duration
|
15
15
|
display_chars = requests / deviation
|
16
16
|
|
17
17
|
if display_chars >= color_cutoff
|
data/output/mean_db_time.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Prints a table sorted by the highest database times.
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
3
|
puts "Top #{amount} worst DB offenders - mean time"
|
5
4
|
puts green("========================================================================")
|
6
|
-
print_table(
|
5
|
+
print_table(@summarizer, :mean_db_time, @amount)
|
7
6
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# Prints a table showing the slowest renderes
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
|
-
puts "Top #{amount} slow renderers - mean time"
|
3
|
+
puts "Top #{@amount} slow renderers - mean time"
|
5
4
|
puts green("========================================================================")
|
6
|
-
print_table(
|
5
|
+
print_table(@summarizer, :mean_rendering_time, @amount)
|
7
6
|
|
data/output/mean_time.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Prints table sorted by the duration of the requests
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
|
-
puts "Top #{amount} actions by time - per request mean"
|
3
|
+
puts "Top #{@amount} actions by time - per request mean"
|
5
4
|
puts green("========================================================================")
|
6
5
|
|
7
|
-
print_table(
|
6
|
+
print_table(@summarizer, :mean_time, @amount)
|
data/output/most_requested.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# Prints a table sorted by the most frequently requested actions
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
3
|
puts "Top #{amount} most requested actions"
|
5
4
|
puts green("========================================================================")
|
6
|
-
print_table(
|
5
|
+
print_table(@summarizer, :count, @amount)
|
data/output/timespan.rb
CHANGED
@@ -2,15 +2,17 @@
|
|
2
2
|
puts
|
3
3
|
puts green("========================================================================")
|
4
4
|
|
5
|
-
if
|
6
|
-
puts "Timestamp first request: #{
|
7
|
-
puts "Timestamp last request: #{
|
8
|
-
puts "Total time analyzed:
|
5
|
+
if @summarizer.has_timestamps?
|
6
|
+
puts "Timestamp first request: #{@summarizer.first_request_at}"
|
7
|
+
puts "Timestamp last request: #{@summarizer.last_request_at}"
|
8
|
+
puts "Total time analyzed: #{@summarizer.duration} days"
|
9
|
+
puts ""
|
10
|
+
puts "Total requests analyzed: #{@summarizer.request_count}"
|
9
11
|
end
|
10
12
|
|
11
13
|
methods_print_array = []
|
12
|
-
methods_request_count =
|
13
|
-
|
14
|
-
methods_print_array << "%s (%0.01f%%)" % [key,
|
14
|
+
methods_request_count = @summarizer.methods.inject(0) { |subtotal, (k, v)| subtotal + v }
|
15
|
+
@summarizer.methods.each do |key, value|
|
16
|
+
methods_print_array << green("%s (%0.01f%%)") % [key, (value * 100) / methods_request_count.to_f]
|
15
17
|
end
|
16
|
-
puts 'Methods: ' + methods_print_array.join(', ') + '.'
|
18
|
+
puts 'Methods: ' + methods_print_array.join(', ') + '.'
|
data/output/total_db_time.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# Prints a list of the actions that spend most of their time waiting for database results.
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
|
-
puts "Top #{amount} worst DB offenders - cumulative time"
|
3
|
+
puts "Top #{@amount} worst DB offenders - cumulative time"
|
5
4
|
puts green("========================================================================")
|
6
|
-
print_table(
|
5
|
+
print_table(@summarizer, :total_db_time, @amount)
|
data/output/total_time.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# Prints a list ordered by the requests that took the most time in total.
|
2
|
-
amount = $arguments[:amount] || 10
|
3
2
|
puts
|
4
|
-
puts "Top #{amount} actions by time - cumulative"
|
3
|
+
puts "Top #{@amount} actions by time - cumulative"
|
5
4
|
puts green("========================================================================")
|
6
|
-
print_table(
|
5
|
+
print_table(@summarizer, :total_time, @amount)
|
data/output/usage.rb
CHANGED
@@ -2,14 +2,15 @@
|
|
2
2
|
puts "Usage: request-log-analyzer [LOGFILES*] <OPTIONS>"
|
3
3
|
puts
|
4
4
|
puts "Options:"
|
5
|
-
puts " --fast, -
|
5
|
+
puts " --fast, -f: Only use completed requests"
|
6
6
|
puts " --guess-database-time, -g: Guesses the database duration of requests"
|
7
7
|
puts " --output, -o: Comma-separated list of reports to show"
|
8
8
|
puts " --amount, -c: Displays the top <amount> elements in the reports"
|
9
9
|
puts " --colorize, -z: Fancy bash coloring"
|
10
10
|
puts " --merb, -m: Parse merb logfiles"
|
11
|
+
puts " --install rails, -i rails Install Rails task rake log:analyze"
|
11
12
|
puts
|
12
13
|
puts "Examples:"
|
13
14
|
puts " request-log-analyzer development.log"
|
14
15
|
puts " request-log-analyzer mongrel.0.log mongrel.1.log mongrel.2.log -g -f -o mean_time,most_requested,blockers -c 20 -z"
|
15
|
-
puts
|
16
|
+
puts " request-log-analyzer --install rails"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::Controller do
|
4
|
+
|
5
|
+
include RequestLogAnalyzerSpecHelper
|
6
|
+
|
7
|
+
it "should include the file format module" do
|
8
|
+
controller = RequestLogAnalyzer::Controller.new(:rails)
|
9
|
+
(class << controller; self; end).ancestors.include?(RequestLogAnalyzer::FileFormat::Rails)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should call the aggregators when run" do
|
13
|
+
controller = RequestLogAnalyzer::Controller.new(:rails)
|
14
|
+
controller << log_fixture(:rails_1x)
|
15
|
+
|
16
|
+
mock_aggregator = mock('aggregator')
|
17
|
+
mock_aggregator.should_receive(:prepare).once.ordered
|
18
|
+
mock_aggregator.should_receive(:aggregate).with(an_instance_of(RequestLogAnalyzer::Request)).at_least(:twice).ordered
|
19
|
+
mock_aggregator.should_receive(:finalize).once.ordered
|
20
|
+
mock_aggregator.should_receive(:report).once.ordered
|
21
|
+
|
22
|
+
another_mock_aggregator = mock('another aggregator')
|
23
|
+
another_mock_aggregator.should_receive(:prepare).once.ordered
|
24
|
+
another_mock_aggregator.should_receive(:aggregate).with(an_instance_of(RequestLogAnalyzer::Request)).at_least(:twice).ordered
|
25
|
+
another_mock_aggregator.should_receive(:finalize).once.ordered
|
26
|
+
another_mock_aggregator.should_receive(:report).once.ordered
|
27
|
+
|
28
|
+
|
29
|
+
controller.aggregators << mock_aggregator << another_mock_aggregator
|
30
|
+
controller.run!
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'request_log_analyzer/aggregator/database'
|
3
|
+
|
4
|
+
|
5
|
+
describe RequestLogAnalyzer::Aggregator::Database, "schema creation" do
|
6
|
+
|
7
|
+
TEST_DATABASE_FILE = File.dirname(__FILE__) + "/fixtures/requests.db"
|
8
|
+
include RequestLogAnalyzerSpecHelper
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@database_inserter = RequestLogAnalyzer::Aggregator::Database.new(TestFileFormat, :database => TEST_DATABASE_FILE)
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:each) do
|
15
|
+
File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should create the correct tables" do
|
19
|
+
ActiveRecord::Migration.should_receive(:create_table).with("warnings")
|
20
|
+
ActiveRecord::Migration.should_receive(:create_table).with("first_lines")
|
21
|
+
ActiveRecord::Migration.should_receive(:create_table).with("test_lines")
|
22
|
+
ActiveRecord::Migration.should_receive(:create_table).with("last_lines")
|
23
|
+
@database_inserter.prepare
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create the default table names" do
|
27
|
+
@database_inserter.prepare
|
28
|
+
@database_inserter.file_format.line_definitions.each do |name, definition|
|
29
|
+
klass = TestFileFormat.const_get("#{name}_line".camelize)
|
30
|
+
klass.column_names.should include('id')
|
31
|
+
klass.column_names.should include('lineno')
|
32
|
+
klass.column_names.should include('request_id')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create the correct fields in the table" do
|
37
|
+
@database_inserter.prepare
|
38
|
+
|
39
|
+
TestFileFormat::FirstLine.column_names.should include('request_no')
|
40
|
+
TestFileFormat::LastLine.column_names.should include('request_no')
|
41
|
+
TestFileFormat::TestLine.column_names.should include('test_capture')
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe RequestLogAnalyzer::Aggregator::Database, "record insertion" do
|
47
|
+
|
48
|
+
before(:each) do
|
49
|
+
@database_inserter = RequestLogAnalyzer::Aggregator::Database.new(TestFileFormat, :database => TEST_DATABASE_FILE)
|
50
|
+
@database_inserter.prepare
|
51
|
+
|
52
|
+
@single = RequestLogAnalyzer::Request.create(TestFileFormat, {:line_type => :first, :request_no => 564})
|
53
|
+
@combined = RequestLogAnalyzer::Request.create(TestFileFormat,
|
54
|
+
{:line_type => :first, :request_no => 564},
|
55
|
+
{:line_type => :test, :test_capture => "awesome"},
|
56
|
+
{:line_type => :test, :test_capture => "indeed"},
|
57
|
+
{:line_type => :last, :request_no => 564})
|
58
|
+
end
|
59
|
+
|
60
|
+
after(:each) do
|
61
|
+
File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should insert a record in the relevant table" do
|
65
|
+
TestFileFormat::FirstLine.should_receive(:create!).with(hash_including(:request_no => 564))
|
66
|
+
@database_inserter.aggregate(@single)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should insert records in all relevant tables" do
|
70
|
+
TestFileFormat::FirstLine.should_receive(:create!).with(hash_including(:request_no => 564)).once
|
71
|
+
TestFileFormat::TestLine.should_receive(:create!).twice
|
72
|
+
TestFileFormat::LastLine.should_receive(:create!).with(hash_including(:request_no => 564)).once
|
73
|
+
@database_inserter.aggregate(@combined)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should log a warning in the warnings table" do
|
77
|
+
TestFileFormat::Warning.should_receive(:create!).with(hash_including(:warning_type => 'test_warning'))
|
78
|
+
@database_inserter.warning(:test_warning, "Testing the warning system", 12)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Processing DashboardController#index (for
|
1
|
+
Processing DashboardController#index (for 1.1.1.1 at 2008-08-14 21:16:25) [GET]
|
2
2
|
Session ID: BAh7CToMcmVmZXJlciIbL3ByaXNjaWxsYS9wZW9wbGUvMjM1MCIKZmxhc2hJ
|
3
3
|
QzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVz
|
4
4
|
ZWR7ADoNbGFuZ3VhZ2VvOhNMb2NhbGU6Ok9iamVjdBI6CUB3aW4wOg1AY291
|
@@ -13,7 +13,7 @@ Rendering dashboard/index
|
|
13
13
|
Completed in 0.22699 (4 reqs/sec) | Rendering: 0.02667 (11%) | DB: 0.03057 (13%) | 200 OK [https://www.example.com/]
|
14
14
|
|
15
15
|
|
16
|
-
Processing PeopleController#index (for
|
16
|
+
Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]
|
17
17
|
Session ID: BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo
|
18
18
|
SGFzaHsABjoKQHVzZWR7ADoMcmVmZXJlciIQL3ByaXNjaWxsYS86DnBlcnNv
|
19
19
|
bl9pZGkCMgc6DWxhbmd1YWdlbzoTTG9jYWxlOjpPYmplY3QSOg1AY291bnRy
|
@@ -27,7 +27,7 @@ Redirected to https://www.example.com/people/2545
|
|
27
27
|
Completed in 0.04759 (21 reqs/sec) | DB: 0.03719 (78%) | 302 Found [https://www.example.com/people?q=gaby&commit=Zoek]
|
28
28
|
|
29
29
|
|
30
|
-
Processing PeopleController#show (for
|
30
|
+
Processing PeopleController#show (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]
|
31
31
|
Session ID: BAh7CToMcmVmZXJlciIpL3ByaXNjaWxsYS9wZW9wbGU/cT1nYWJ5JmNvbW1p
|
32
32
|
dD1ab2VrIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxh
|
33
33
|
c2hIYXNoewAGOgpAdXNlZHsAOg1sYW5ndWFnZW86E0xvY2FsZTo6T2JqZWN0
|
@@ -40,11 +40,11 @@ X2lkaQIyBw==--3ad1948559448522a49d289a2a89dc7ccbe8847a
|
|
40
40
|
Set language to: nl_NL
|
41
41
|
Rendering template within layouts/priscilla
|
42
42
|
Rendering people/show
|
43
|
-
person:
|
43
|
+
person: John Doe, study_year: 2008/2009
|
44
44
|
Completed in 0.29077 (3 reqs/sec) | Rendering: 0.24187 (83%) | DB: 0.04030 (13%) | 200 OK [https://www.example.com/people/2545]
|
45
45
|
|
46
46
|
|
47
|
-
Processing PeopleController#picture (for
|
47
|
+
Processing PeopleController#picture (for 1.1.1.1 at 2008-08-14 21:16:35) [GET]
|
48
48
|
Session ID: BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo
|
49
49
|
SGFzaHsABjoKQHVzZWR7ADoMcmVmZXJlciIbL3ByaXNjaWxsYS9wZW9wbGUv
|
50
50
|
MjU0NToOcGVyc29uX2lkaQIyBzoNbGFuZ3VhZ2VvOhNMb2NhbGU6Ok9iamVj
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Processing PageController#demo (for 127.0.0.1 at 2008-12-10 16:28:09) [GET]
|
2
2
|
Parameters: {"action"=>"demo", "controller"=>"page"}
|
3
3
|
Logging in from session data...
|
4
|
-
Logged in as
|
4
|
+
Logged in as test@example.com
|
5
5
|
Using locale: en-US, http-accept: ["en-US"], session: , det browser: en-US, det domain:
|
6
6
|
Rendering template within layouts/demo
|
7
7
|
Rendering page/demo
|
@@ -9,4 +9,4 @@ Rendered shared/_analytics (0.2ms)
|
|
9
9
|
Rendered layouts/_actions (0.6ms)
|
10
10
|
Rendered layouts/_menu (2.2ms)
|
11
11
|
Rendered layouts/_tabbar (0.5ms)
|
12
|
-
Completed in 614ms (View: 120, DB: 31) | 200 OK [http://
|
12
|
+
Completed in 614ms (View: 120, DB: 31) | 200 OK [http://www.example.coml/demo]
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Processing CachedController#cached (for 1.1.1.1 at 2008-12-24 07:36:53) [GET]
|
2
|
+
Parameters: {"action"=>"cached", "controller"=>"cached"}
|
3
|
+
Logging in from session data...
|
4
|
+
Logging in using cookie...
|
5
|
+
Using locale: zh-Hans, http-accept: ["zh-CN", "zh-HK", "zh-TW", "en-US"], session: , det browser: zh-Hans, det domain: , user pref locale:
|
6
|
+
Referer: http://www.example.com/referer
|
7
|
+
Cached fragment hit: views/zh-Hans-www-cached-cached-all-CN--- (0.0ms)
|
8
|
+
Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>] rendered_or_redirected.
|
9
|
+
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.
|
10
|
+
Completed in 3ms (View: 0, DB: 0) | 200 OK [http://www.example.com/cached/cached/]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Processing AccountController#dashboard (for 1.1.1.1 at 2008-12-24 07:36:49) [GET]
|
2
|
+
Parameters: {"action"=>"dashboard", "controller"=>"account", "first_use"=>"true"}
|
3
|
+
Logging in from session data...
|
4
|
+
|
5
|
+
|
6
|
+
Processing ProjectsController#new (for 1.1.1.1 at 2008-12-24 07:36:49) [GET]
|
7
|
+
Parameters: {"action"=>"new", "controller"=>"projects"}
|
8
|
+
Rendering template within layouts/default
|
9
|
+
Rendering account/dashboard
|
10
|
+
Logging in from session data...
|
11
|
+
Logging in using cookie...
|
12
|
+
Using locale: en-US, http-accept: [], session: , det browser: , det domain: , user pref locale:
|
13
|
+
Rendered shared/_maintenance (0.6ms)
|
14
|
+
Rendering template within layouts/templates/general_default/index.html.erb
|
15
|
+
Rendered projects/_recent_designs (4.3ms)
|
16
|
+
Rendered projects/_project (13.6ms)
|
17
|
+
Rendered projects/_projects (18.7ms)
|
18
|
+
Rendered layouts/_menu (1.4ms)
|
19
|
+
Completed in 36ms (View: 30, DB: 3) | 200 OK [http://www.example.com/projects/new]
|
20
|
+
Rendered layouts/_actions (0.3ms)
|
21
|
+
Rendered layouts/_menu (1.6ms)
|
22
|
+
Rendered layouts/_tabbar (1.9ms)
|
23
|
+
Rendered layouts/_footer (3.2ms)
|
24
|
+
Completed in 50ms (View: 41, DB: 4) | 200 OK [http://www.example.com/dashboard?first_use=true]
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::FileFormat::LineDefinition do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@line_definition = RequestLogAnalyzer::FileFormat::LineDefinition.new(:test, {
|
7
|
+
:teaser => /Testing /,
|
8
|
+
:regexp => /Testing (\w+), tries\: (\d+)/,
|
9
|
+
:captures => [{:what => :string}, {:tries => :integer}]
|
10
|
+
})
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return false on an unmatching line" do
|
14
|
+
(@line_definition =~ "nonmatching").should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return false when only the teaser matches" do
|
18
|
+
(@line_definition =~ "Testing LineDefinition").should be_false
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return a hash if the line matches" do
|
22
|
+
(@line_definition =~ "Testing LineDefinition, tries: 123").should be_kind_of(Hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return a hash with all captures set" do
|
26
|
+
hash = @line_definition.matches("Testing LineDefinition, tries: 123")
|
27
|
+
hash[:what].should == "LineDefinition"
|
28
|
+
hash[:tries].should == 123
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return a hash with :line_type set" do
|
32
|
+
@line_definition.matches("Testing LineDefinition, tries: 123")[:line_type].should == :test
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::LogParser, :single_line_requests do
|
4
|
+
|
5
|
+
include RequestLogAnalyzerSpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@log_parser = RequestLogAnalyzer::LogParser.new(TestFileFormat)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have line definitions" do
|
12
|
+
@log_parser.file_format.line_definitions.should_not be_empty
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have include the language specific hooks in the instance, not in the class" do
|
16
|
+
metaclass = (class << @log_parser; self; end)
|
17
|
+
metaclass.ancestors.should include(TestFileFormat::LogParser)
|
18
|
+
@log_parser.class.ancestors.should_not include(TestFileFormat::LogParser)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should parse a stream and find valid requests" do
|
22
|
+
io = File.new(log_fixture(:test_file_format), 'r')
|
23
|
+
@log_parser.parse_io(io, :line_types => [:test]) do |request|
|
24
|
+
request.should be_kind_of(RequestLogAnalyzer::Request)
|
25
|
+
request.should =~ :test
|
26
|
+
request[:test_capture].should_not be_nil
|
27
|
+
end
|
28
|
+
io.close
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should find as many lines as request" do
|
32
|
+
@log_parser.parse_file(log_fixture(:test_file_format)) { |request| request.should be_single_line }
|
33
|
+
@log_parser.parsed_lines.should eql(@log_parser.parsed_requests)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe RequestLogAnalyzer::LogParser, :combined_requests do
|
38
|
+
include RequestLogAnalyzerSpecHelper
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
@log_parser = RequestLogAnalyzer::LogParser.new(TestFileFormat, :combined_requests => true)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have multiple line definitions" do
|
45
|
+
@log_parser.file_format.line_definitions.length.should >= 2
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have a valid language" do
|
49
|
+
@log_parser.file_format.should be_valid
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should parse more lines than requests" do
|
53
|
+
@log_parser.should_receive(:handle_request).with(an_instance_of(RequestLogAnalyzer::Request)).twice
|
54
|
+
@log_parser.parse_file(log_fixture(:test_language_combined)) { |request| request.should be_combined }
|
55
|
+
@log_parser.parsed_lines.should > 2
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should parse requests spanned over multiple files" do
|
59
|
+
@log_parser.should_receive(:handle_request).with(an_instance_of(RequestLogAnalyzer::Request)).once
|
60
|
+
@log_parser.parse_files([log_fixture(:multiple_files_1), log_fixture(:multiple_files_2)])
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should parse all request values when spanned over multiple files" do
|
64
|
+
@log_parser.parse_files([log_fixture(:multiple_files_1), log_fixture(:multiple_files_2)]) do |request|
|
65
|
+
request.lines.should have(4).items
|
66
|
+
|
67
|
+
request[:request_no].should == 1
|
68
|
+
request[:test_capture].should == "amazing"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe RequestLogAnalyzer::LogParser, :warnings do
|
74
|
+
include RequestLogAnalyzerSpecHelper
|
75
|
+
|
76
|
+
it "should warn about teaser matching problems" do
|
77
|
+
@log_parser = RequestLogAnalyzer::LogParser.new(TestFileFormat)
|
78
|
+
@log_parser.should_receive(:warn).with(:teaser_check_failed, anything).exactly(5).times
|
79
|
+
@log_parser.parse_file(log_fixture(:test_file_format))
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should warn about unmatching request headers and footers" do
|
83
|
+
@log_parser = RequestLogAnalyzer::LogParser.new(TestFileFormat, :combined_requests => true)
|
84
|
+
|
85
|
+
@log_parser.should_receive(:warn).with(:unclosed_request, anything).at_least(1).times
|
86
|
+
@log_parser.should_receive(:warn).with(:no_current_request, anything).at_least(1).times
|
87
|
+
@log_parser.should_not_receive(:handle_request)
|
88
|
+
@log_parser.parse_file(log_fixture(:test_order))
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::LogParser, "Merb without combined requests" do
|
4
|
+
include RequestLogAnalyzerSpecHelper
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@log_parser = RequestLogAnalyzer::LogParser.new(:merb, :combined_requests => false)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should parse a stream and find valid requests" do
|
11
|
+
File.open(log_fixture(:merb), 'r') do |io|
|
12
|
+
@log_parser.parse_io(io) do |request|
|
13
|
+
request.should be_kind_of(RequestLogAnalyzer::Request)
|
14
|
+
request.should be_single_line
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should find 33 request lines when lines are not linked" do
|
20
|
+
@log_parser.should_receive(:handle_request).exactly(33).times
|
21
|
+
@log_parser.parse_file(log_fixture(:merb))
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should find 11 request start lines when lines are not linked" do
|
25
|
+
@log_parser.should_receive(:handle_request).exactly(11).times
|
26
|
+
@log_parser.parse_file(log_fixture(:merb), :line_types => [:started])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
describe RequestLogAnalyzer::LogParser, "Merb with combined requests" do
|
32
|
+
include RequestLogAnalyzerSpecHelper
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
@log_parser = RequestLogAnalyzer::LogParser.new(:merb, :combined_requests => true)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have a valid language definitions" do
|
39
|
+
@log_parser.file_format.should be_valid
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should find 11 completed requests when lines are linked" do
|
43
|
+
@log_parser.should_receive(:handle_request).exactly(11).times
|
44
|
+
@log_parser.parse_file(log_fixture(:merb))
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse all details from a request correctly" do
|
48
|
+
request = nil
|
49
|
+
@log_parser.parse_file(log_fixture(:merb)) { |found_request| request ||= found_request }
|
50
|
+
|
51
|
+
request.should be_completed
|
52
|
+
request[:timestamp].should == 'Fri Aug 29 11:10:23 +0200 2008'
|
53
|
+
request[:dispatch_time].should == 0.243424
|
54
|
+
request[:after_filters_time].should == 6.9e-05
|
55
|
+
request[:before_filters_time].should == 0.213213
|
56
|
+
request[:action_time].should == 0.241652
|
57
|
+
end
|
58
|
+
end
|