request-log-analyzer 1.6.2 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/request_log_analyzer.rb +1 -1
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +19 -18
- data/lib/request_log_analyzer/file_format/delayed_job.rb +14 -10
- data/lib/request_log_analyzer/file_format/mysql.rb +15 -12
- data/lib/request_log_analyzer/file_format/postgresql.rb +7 -5
- data/lib/request_log_analyzer/file_format/rails3.rb +86 -0
- data/lib/request_log_analyzer/line_definition.rb +19 -0
- data/lib/request_log_analyzer/output/fancy_html.rb +19 -1
- data/request-log-analyzer.gemspec +4 -4
- data/spec/unit/file_format/amazon_s3_format_spec.rb +18 -0
- data/spec/unit/file_format/rails3_format_spec.rb +120 -0
- data/tasks/github-gem.rake +17 -17
- metadata +33 -15
data/lib/request_log_analyzer.rb
CHANGED
@@ -11,7 +11,7 @@ module RequestLogAnalyzer
|
|
11
11
|
|
12
12
|
# The current version of request-log-analyzer.
|
13
13
|
# Do not change the value by hand; it will be updated automatically by the gem release script.
|
14
|
-
VERSION = "1.6.
|
14
|
+
VERSION = "1.6.3"
|
15
15
|
|
16
16
|
# Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
|
17
17
|
# <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
|
@@ -11,24 +11,25 @@ module RequestLogAnalyzer::FileFormat
|
|
11
11
|
line_definition :access do |line|
|
12
12
|
line.header = true
|
13
13
|
line.footer = true
|
14
|
-
line.regexp = /^([^\ ]+) ([^\ ]+) \[(#{timestamp('%d/%b/%Y:%H:%M:%S %z')})?\] (#{ip_address}) ([^\ ]+) ([^\ ]+) (\w+(?:\.\w+)*) ([^\ ]+) "([^"]+)" (\d+) ([^\ ]+) (\d+) (\d+) (\d+) (\d+) "([^"]
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
14
|
+
line.regexp = /^([^\ ]+) ([^\ ]+) \[(#{timestamp('%d/%b/%Y:%H:%M:%S %z')})?\] (#{ip_address}) ([^\ ]+) ([^\ ]+) (\w+(?:\.\w+)*) ([^\ ]+) "([^"]+)" (\d+) ([^\ ]+) (\d+) (\d+) (\d+) (\d+) "([^"]*)" "([^"]*)"/
|
15
|
+
|
16
|
+
line.capture(:bucket_owner)
|
17
|
+
line.capture(:bucket)
|
18
|
+
line.capture(:timestamp).as(:timestamp)
|
19
|
+
line.capture(:remote_ip)
|
20
|
+
line.capture(:requester)
|
21
|
+
line.capture(:request_id)
|
22
|
+
line.capture(:operation)
|
23
|
+
line.capture(:key).as(:nillable_string)
|
24
|
+
line.capture(:request_uri)
|
25
|
+
line.capture(:http_status).as(:integer)
|
26
|
+
line.capture(:error_code).as(:nillable_string)
|
27
|
+
line.capture(:bytes_sent).as(:traffic, :unit => :byte)
|
28
|
+
line.capture(:object_size).as(:traffic, :unit => :byte)
|
29
|
+
line.capture(:total_time).as(:duration, :unit => :msec)
|
30
|
+
line.capture(:turnaround_time).as(:duration, :unit => :msec)
|
31
|
+
line.capture(:referer).as(:referer)
|
32
|
+
line.capture(:user_agent).as(:user_agent)
|
32
33
|
end
|
33
34
|
|
34
35
|
report do |analyze|
|
@@ -7,38 +7,42 @@ module RequestLogAnalyzer::FileFormat
|
|
7
7
|
line_definition :job_lock do |line|
|
8
8
|
line.header = true
|
9
9
|
line.regexp = /\* \[JOB\] acquiring lock on (\S+)/
|
10
|
-
|
10
|
+
|
11
|
+
line.capture(:job)
|
11
12
|
end
|
12
13
|
|
13
14
|
line_definition :job_completed do |line|
|
14
15
|
line.footer = true
|
15
16
|
line.regexp = /\* \[JOB\] (\S+) completed after (\d+\.\d+)/
|
16
|
-
|
17
|
-
|
17
|
+
|
18
|
+
line.capture(:completed_job)
|
19
|
+
line.capture(:duration).as(:duration, :unit => :sec)
|
18
20
|
end
|
19
21
|
|
20
22
|
line_definition :job_failed do |line|
|
21
23
|
line.footer = true
|
22
24
|
line.regexp = /\* \[JOB\] (\S+) failed with (\S+)\: .* - (\d+) failed attempts/
|
23
|
-
line.captures << { :name => :failed_job, :type => :string } <<
|
24
|
-
{ :name => :exception, :type => :string } <<
|
25
|
-
{ :name => :attempts, :type => :integer }
|
26
25
|
|
26
|
+
line.capture(:failed_job)
|
27
|
+
line.capture(:exception)
|
28
|
+
line.capture(:attempts).as(:integer)
|
27
29
|
end
|
28
30
|
|
29
31
|
line_definition :job_lock_failed do |line|
|
30
32
|
line.footer = true
|
31
33
|
line.regexp = /\* \[JOB\] failed to acquire exclusive lock for (\S+)/
|
32
|
-
|
34
|
+
|
35
|
+
line.capture(:locked_job)
|
33
36
|
end
|
34
37
|
|
35
38
|
# line_definition :batch_completed do |line|
|
36
39
|
# line.header = true
|
37
40
|
# line.footer = true
|
38
41
|
# line.regexp = /(\d+) jobs processed at (\d+\.\d+) j\/s, (\d+) failed .../
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
+
#
|
43
|
+
# line.capture(:total_amount).as(:integer)
|
44
|
+
# line.capture(:mean_duration).as(:duration, :unit => :sec)
|
45
|
+
# line.capture(:failed_amount).as(:integer)
|
42
46
|
# end
|
43
47
|
|
44
48
|
report do |analyze|
|
@@ -8,42 +8,45 @@ module RequestLogAnalyzer::FileFormat
|
|
8
8
|
line.header = :alternative
|
9
9
|
line.teaser = /\# Time: /
|
10
10
|
line.regexp = /\# Time: (#{timestamp('%y%m%d %k:%M:%S')})/
|
11
|
-
|
11
|
+
|
12
|
+
line.capture(:timestamp).as(:timestamp)
|
12
13
|
end
|
13
14
|
|
14
15
|
line_definition :user_host do |line|
|
15
16
|
line.header = :alternative
|
16
17
|
line.teaser = /\# User\@Host\: /
|
17
18
|
line.regexp = /\# User\@Host\: ([\w-]+)\[[\w-]+\] \@ ([\w\.-]*) \[(#{ip_address(true)})\]/
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
|
20
|
+
line.capture(:user)
|
21
|
+
line.capture(:host)
|
22
|
+
line.capture(:ip)
|
21
23
|
end
|
22
24
|
|
23
25
|
line_definition :query_statistics do |line|
|
24
26
|
line.header = :alternative
|
25
27
|
line.teaser = /\# Query_time: /
|
26
28
|
line.regexp = /\# Query_time: (\d+(?:\.\d+)?)\s+Lock_time: (\d+(?:\.\d+)?)\s+Rows_sent: (\d+)\s+Rows_examined: (\d+)/
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
line.capture(:query_time).as(:duration, :unit => :sec)
|
31
|
+
line.capture(:lock_time).as(:duration, :unit => :sec)
|
32
|
+
line.capture(:rows_sent).as(:integer)
|
33
|
+
line.capture(:rows_examined).as(:integer)
|
31
34
|
end
|
32
35
|
|
33
36
|
line_definition :use_database do |line|
|
34
37
|
line.regexp = /^use (\w+);\s*$/
|
35
|
-
line.
|
38
|
+
line.capture(:database)
|
36
39
|
end
|
37
40
|
|
38
41
|
line_definition :query_part do |line|
|
39
42
|
line.regexp = /^(?!(?:use |\# |SET ))(.*[^;\s])\s*$/
|
40
|
-
line.
|
43
|
+
line.capture(:query_fragment)
|
41
44
|
end
|
42
45
|
|
43
46
|
line_definition :query do |line|
|
44
|
-
line.regexp = /^(?!(?:use |\# |SET ))(.*);\s*$/
|
45
|
-
line.captures << { :name => :query, :type => :sql }
|
46
47
|
line.footer = true
|
48
|
+
line.regexp = /^(?!(?:use |\# |SET ))(.*);\s*$/
|
49
|
+
line.capture(:query).as(:sql)
|
47
50
|
end
|
48
51
|
|
49
52
|
PER_USER = :user
|
@@ -8,21 +8,23 @@ module RequestLogAnalyzer::FileFormat
|
|
8
8
|
line.header = true
|
9
9
|
line.teaser = /LOG\: query\:/
|
10
10
|
line.regexp = /(#{timestamp('%y-%m-%d %k:%M:%S')})\ LOG: query:\s+(.*)/
|
11
|
-
|
12
|
-
|
11
|
+
|
12
|
+
line.capture(:timestamp).as(:timestamp)
|
13
|
+
line.capture(:query_fragment)
|
13
14
|
end
|
14
15
|
|
15
16
|
line_definition :duration do |line|
|
16
17
|
line.footer = true
|
17
18
|
line.teaser = /duration:/
|
18
19
|
line.regexp = /#{timestamp('%y-%m-%d %k:%M:%S')}\ LOG\: duration\: (.*)(\ )sec/
|
19
|
-
|
20
|
-
|
20
|
+
|
21
|
+
line.capture(:query_time).as(:duration, :unit => :sec)
|
22
|
+
line.capture(:query).as(:sql) # Hack to gather up fragments
|
21
23
|
end
|
22
24
|
|
23
25
|
line_definition :query_fragment do |line|
|
24
26
|
line.regexp = /^(?!.*LOG)\s*(.*)\s*/
|
25
|
-
line.
|
27
|
+
line.capture(:query_fragment)
|
26
28
|
end
|
27
29
|
|
28
30
|
report do |analyze|
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module RequestLogAnalyzer::FileFormat
|
2
|
+
|
3
|
+
# Default FileFormat class for Rails 3 logs.
|
4
|
+
#
|
5
|
+
# For now, this is just a basic implementation. It will probaby change after
|
6
|
+
# Rails 3 final has been released.
|
7
|
+
class Rails3 < Base
|
8
|
+
|
9
|
+
extend CommonRegularExpressions
|
10
|
+
|
11
|
+
# Started GET "/queries" for 127.0.0.1 at 2010-02-25 16:15:18
|
12
|
+
line_definition :started do |line|
|
13
|
+
line.header = true
|
14
|
+
line.teaser = /Started /
|
15
|
+
line.regexp = /Started ([A-Z]+) "([^"]+)" for (#{ip_address}) at (#{timestamp('%Y-%m-%d %H:%M:%S')})/
|
16
|
+
|
17
|
+
line.capture(:method)
|
18
|
+
line.capture(:path)
|
19
|
+
line.capture(:ip)
|
20
|
+
line.capture(:timestamp).as(:timestamp)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Processing by QueriesController#index as HTML
|
24
|
+
line_definition :processing do |line|
|
25
|
+
line.teaser = /Processing by /
|
26
|
+
line.regexp = /Processing by (\w+)\#(\w+) as (\w+)/
|
27
|
+
|
28
|
+
line.capture(:controller)
|
29
|
+
line.capture(:action)
|
30
|
+
line.capture(:format)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Completed in 9ms (Views: 4.9ms | ActiveRecord: 0.5ms) with 200
|
34
|
+
line_definition :completed do |line|
|
35
|
+
line.footer = true
|
36
|
+
line.teaser = /Completed /
|
37
|
+
line.regexp = /Completed (\d+) .* in (\d+)ms \([^\)]*\)/
|
38
|
+
|
39
|
+
line.capture(:status).as(:integer)
|
40
|
+
line.capture(:duration).as(:duration, :unit => :msec)
|
41
|
+
end
|
42
|
+
|
43
|
+
# 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:
|
44
|
+
line_definition :failure do |line|
|
45
|
+
line.footer = true
|
46
|
+
line.regexp = /((?:[A-Z]\w*[a-z]\w+\:\:)*[A-Z]\w*[a-z]\w+) \((.*)\)(?: on line #(\d+) of (.+))?\:\s*$/
|
47
|
+
|
48
|
+
line.capture(:error)
|
49
|
+
line.capture(:message)
|
50
|
+
line.capture(:line).as(:integer)
|
51
|
+
line.capture(:file)
|
52
|
+
end
|
53
|
+
|
54
|
+
# # Not parsed at the moment:
|
55
|
+
# SQL (0.2ms) SET SQL_AUTO_IS_NULL=0
|
56
|
+
# Query Load (0.4ms) SELECT `queries`.* FROM `queries`
|
57
|
+
# Rendered collection (0.0ms)
|
58
|
+
# Rendered queries/index.html.erb (0.6ms)
|
59
|
+
|
60
|
+
REQUEST_CATEGORIZER = lambda { |request| "#{request[:controller]}##{request[:action]}.#{request[:format]}" }
|
61
|
+
|
62
|
+
report do |analyze|
|
63
|
+
|
64
|
+
analyze.timespan
|
65
|
+
analyze.hourly_spread
|
66
|
+
|
67
|
+
analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Most requested'
|
68
|
+
analyze.frequency :method, :title => 'HTTP methods'
|
69
|
+
analyze.frequency :status, :title => 'HTTP statuses returned'
|
70
|
+
|
71
|
+
analyze.duration :duration, :category => REQUEST_CATEGORIZER, :title => "Request duration", :line_type => :completed
|
72
|
+
# analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
|
73
|
+
# analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
|
74
|
+
|
75
|
+
analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Process blockers (> 1 sec duration)',
|
76
|
+
:if => lambda { |request| request[:duration] && request[:duration] > 1.0 }
|
77
|
+
end
|
78
|
+
|
79
|
+
class Request < RequestLogAnalyzer::Request
|
80
|
+
def convert_timestamp(value, defintion)
|
81
|
+
value.gsub(/[^0-9]/, '')[0...14].to_i
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -26,6 +26,19 @@ module RequestLogAnalyzer
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
class CaptureDefiner
|
30
|
+
attr_accessor :capture_hash
|
31
|
+
|
32
|
+
def initialize(hash)
|
33
|
+
@capture_hash = hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def as(type, type_options = {})
|
37
|
+
@capture_hash.merge!(type_options.merge(:type => type))
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
29
42
|
attr_reader :name
|
30
43
|
attr_accessor :teaser, :regexp, :captures
|
31
44
|
attr_accessor :header, :footer
|
@@ -47,6 +60,12 @@ module RequestLogAnalyzer
|
|
47
60
|
yield(definition) if block_given?
|
48
61
|
return definition
|
49
62
|
end
|
63
|
+
|
64
|
+
def capture(name)
|
65
|
+
new_capture_hash = { :name => name, :type => :string}
|
66
|
+
captures << new_capture_hash
|
67
|
+
CaptureDefiner.new(new_capture_hash)
|
68
|
+
end
|
50
69
|
|
51
70
|
# Checks whether a given line matches this definition.
|
52
71
|
# It will return false if a line does not match. If the line matches, a hash is returned
|
@@ -25,7 +25,25 @@ module RequestLogAnalyzer::Output
|
|
25
25
|
def report_hourly_spread(tracker)
|
26
26
|
title tracker.title
|
27
27
|
puts tag(:img, nil, :width => '700', :height => '120', :src =>
|
28
|
-
Gchart.sparkline(:data => tracker.hour_frequencies, :size => '700x120', :line_colors => '0077CC'
|
28
|
+
Gchart.sparkline(:data => tracker.hour_frequencies, :size => '700x120', :line_colors => '0077CC',
|
29
|
+
:axis_with_labels => 'x,y', :axis_labels => [x_axis_labels(tracker),y_axis_labels(tracker)]))
|
30
|
+
end
|
31
|
+
|
32
|
+
def x_axis_labels(tracker)
|
33
|
+
frmt = '%H:%M'
|
34
|
+
x_axis_labels = []
|
35
|
+
num_labels = 5
|
36
|
+
start = tracker.first_timestamp
|
37
|
+
step = tracker.timespan / (num_labels - 1)
|
38
|
+
for i in 0...num_labels do
|
39
|
+
x_axis_labels << (start + step * i).strftime(frmt)
|
40
|
+
end
|
41
|
+
x_axis_labels
|
42
|
+
end
|
43
|
+
|
44
|
+
def y_axis_labels(tracker)
|
45
|
+
sorted_frequencies = tracker.hour_frequencies.sort
|
46
|
+
[sorted_frequencies.first, sorted_frequencies.last]
|
29
47
|
end
|
30
48
|
end
|
31
49
|
end
|
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.name = "request-log-analyzer"
|
3
3
|
|
4
4
|
# Do not set the version and date field manually, this is done by the release script
|
5
|
-
s.version = "1.6.
|
6
|
-
s.date = "2010-
|
5
|
+
s.version = "1.6.3"
|
6
|
+
s.date = "2010-03-19"
|
7
7
|
|
8
8
|
s.rubyforge_project = 'r-l-a'
|
9
9
|
|
@@ -36,6 +36,6 @@ Gem::Specification.new do |s|
|
|
36
36
|
|
37
37
|
# The files and test_files directives are set automatically by the release script.
|
38
38
|
# Do not change them by hand, but make sure to add the files to the git repository.
|
39
|
-
s.files = %w(spec/unit/tracker/hourly_spread_spec.rb lib/request_log_analyzer/output/html.rb DESIGN.rdoc spec/fixtures/rails_unordered.log spec/fixtures/multiple_files_1.log lib/request_log_analyzer/database/source.rb README.rdoc spec/unit/file_format/amazon_s3_format_spec.rb lib/request_log_analyzer/file_format/rails_development.rb spec/fixtures/rails_22.log spec/fixtures/test_order.log spec/unit/database/base_class_spec.rb lib/request_log_analyzer/database/connection.rb lib/request_log_analyzer/aggregator.rb spec/fixtures/decompression.log lib/request_log_analyzer/file_format/apache.rb spec/unit/file_format/rack_format_spec.rb spec/fixtures/decompression.log.gz lib/request_log_analyzer/tracker/frequency.rb lib/request_log_analyzer/tracker/duration.rb tasks/github-gem.rake
|
40
|
-
s.test_files = %w(spec/unit/tracker/hourly_spread_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/database/base_class_spec.rb spec/unit/file_format/rack_format_spec.rb spec/unit/filter/filter_spec.rb spec/unit/database/connection_spec.rb spec/integration/scout_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/integration/mailer_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/apache_format_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/unit/file_format/delayed_job_format_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/file_format/rails_format_spec.rb spec/integration/command_line_usage_spec.rb spec/unit/request_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/filter/anonymize_filter_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/file_format/mysql_format_spec.rb spec/unit/mailer_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/traffic_tracker_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/controller/controller_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/database/database_spec.rb)
|
39
|
+
s.files = %w(spec/unit/tracker/hourly_spread_spec.rb lib/request_log_analyzer/output/html.rb DESIGN.rdoc spec/fixtures/rails_unordered.log spec/fixtures/multiple_files_1.log lib/request_log_analyzer/database/source.rb README.rdoc spec/unit/file_format/amazon_s3_format_spec.rb lib/request_log_analyzer/file_format/rails_development.rb spec/fixtures/rails_22.log spec/fixtures/test_order.log spec/unit/database/base_class_spec.rb lib/request_log_analyzer/database/connection.rb lib/request_log_analyzer/aggregator.rb spec/fixtures/decompression.log lib/request_log_analyzer/file_format/apache.rb spec/unit/file_format/rack_format_spec.rb spec/fixtures/decompression.log.gz lib/request_log_analyzer/tracker/frequency.rb lib/request_log_analyzer/tracker/duration.rb tasks/github-gem.rake spec/unit/filter/filter_spec.rb .gitignore spec/lib/macros.rb spec/spec_helper.rb spec/fixtures/decompression.log.bz2 spec/unit/database/connection_spec.rb lib/request_log_analyzer/filter.rb spec/integration/scout_spec.rb spec/fixtures/test_file_format.log spec/unit/filter/timespan_filter_spec.rb lib/request_log_analyzer/tracker/traffic.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/file_format_api_spec.rb lib/request_log_analyzer/filter/field.rb lib/request_log_analyzer/file_format/merb.rb lib/request_log_analyzer/filter/anonymize.rb lib/request_log_analyzer/file_format/amazon_s3.rb lib/cli/database_console.rb spec/integration/mailer_spec.rb lib/request_log_analyzer/line_definition.rb spec/unit/tracker/frequency_tracker_spec.rb spec/fixtures/postgresql.log spec/fixtures/multiple_files_2.log spec/lib/mocks.rb spec/unit/file_format/apache_format_spec.rb spec/fixtures/syslog_1x.log spec/unit/file_format/rails3_format_spec.rb spec/integration/munin_plugins_rails_spec.rb lib/request_log_analyzer/file_format/rails3.rb spec/lib/helpers.rb spec/unit/file_format/delayed_job_format_spec.rb spec/fixtures/rails.db spec/unit/source/log_parser_spec.rb lib/request_log_analyzer/aggregator/database_inserter.rb spec/fixtures/header_and_footer.log spec/lib/testing_format.rb lib/request_log_analyzer/database.rb spec/unit/file_format/rails_format_spec.rb lib/request_log_analyzer/request.rb lib/request_log_analyzer/output/fixed_width.rb spec/integration/command_line_usage_spec.rb lib/request_log_analyzer/file_format/rack.rb lib/request_log_analyzer/tracker/numeric_value.rb spec/fixtures/test_language_combined.log spec/unit/request_spec.rb lib/cli/command_line_arguments.rb lib/request_log_analyzer.rb spec/database.yml lib/request_log_analyzer/database/base.rb spec/unit/aggregator/database_inserter_spec.rb lib/request_log_analyzer/database/request.rb lib/request_log_analyzer/output/fancy_html.rb lib/cli/database_console_init.rb lib/cli/progressbar.rb lib/request_log_analyzer/database/warning.rb spec/unit/filter/anonymize_filter_spec.rb spec/fixtures/apache_combined.log spec/unit/tracker/duration_tracker_spec.rb spec/fixtures/rails_22_cached.log lib/request_log_analyzer/aggregator/summarizer.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/fixtures/rails_1x.log lib/request_log_analyzer/file_format/delayed_job.rb lib/request_log_analyzer/output.rb spec/unit/file_format/line_definition_spec.rb lib/request_log_analyzer/file_format/mysql.rb spec/unit/file_format/mysql_format_spec.rb request-log-analyzer.gemspec spec/fixtures/apache_common.log spec/unit/mailer_spec.rb lib/request_log_analyzer/file_format/rails.rb Rakefile lib/request_log_analyzer/tracker/hourly_spread.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/traffic_tracker_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb lib/request_log_analyzer/file_format/postgresql.rb lib/request_log_analyzer/tracker/timespan.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/field_filter_spec.rb spec/fixtures/sinatra.log spec/fixtures/merb_prefixed.log lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/filter/timespan.rb spec/unit/controller/controller_spec.rb lib/request_log_analyzer/mailer.rb lib/cli/tools.rb spec/fixtures/decompression.tar.gz spec/unit/tracker/timespan_tracker_spec.rb spec/lib/matchers.rb lib/request_log_analyzer/controller.rb spec/unit/tracker/tracker_api_spec.rb lib/request_log_analyzer/source/database_loader.rb spec/fixtures/merb.log LICENSE lib/request_log_analyzer/file_format.rb tasks/request_log_analyzer.rake spec/unit/database/database_spec.rb spec/fixtures/decompression.log.zip spec/fixtures/decompression.tgz bin/request-log-analyzer lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/source.rb spec/fixtures/mysql_slow_query.log lib/request_log_analyzer/source/log_parser.rb lib/request_log_analyzer/aggregator/echo.rb)
|
40
|
+
s.test_files = %w(spec/unit/tracker/hourly_spread_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/database/base_class_spec.rb spec/unit/file_format/rack_format_spec.rb spec/unit/filter/filter_spec.rb spec/unit/database/connection_spec.rb spec/integration/scout_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/integration/mailer_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/apache_format_spec.rb spec/unit/file_format/rails3_format_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/unit/file_format/delayed_job_format_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/file_format/rails_format_spec.rb spec/integration/command_line_usage_spec.rb spec/unit/request_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/filter/anonymize_filter_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/file_format/mysql_format_spec.rb spec/unit/mailer_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/traffic_tracker_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/controller/controller_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/database/database_spec.rb)
|
41
41
|
end
|
@@ -46,4 +46,22 @@ describe RequestLogAnalyzer::FileFormat::AmazonS3 do
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
it "should parse a COPY request correctly" do
|
50
|
+
line = '09216466b5571a8db0bf5abca72041fd3fc163e5eb83c51159735353ac6a2b9a testbucket [03/Mar/2010:23:04:59 +0000] 174.119.31.76 09216466b5571a8db0bf5abca72041fd3fc163e5eb83c51159735353ac6a2b9a ACCC34B843C87BC9 REST.COPY.OBJECT files/image.png "PUT /files/image.png HTTP/1.1" 200 - 234 65957 365 319 "-" "" -'
|
51
|
+
@file_format.should parse_line(line).as(:access).and_capture(
|
52
|
+
:bucket_owner => '09216466b5571a8db0bf5abca72041fd3fc163e5eb83c51159735353ac6a2b9a',
|
53
|
+
:bucket => 'testbucket',
|
54
|
+
:timestamp => 20100303230459,
|
55
|
+
:remote_ip => '174.119.31.76',
|
56
|
+
:requester => '09216466b5571a8db0bf5abca72041fd3fc163e5eb83c51159735353ac6a2b9a',
|
57
|
+
:key => 'files/image.png',
|
58
|
+
:operation => 'REST.COPY.OBJECT',
|
59
|
+
:total_time => 0.365,
|
60
|
+
:turnaround_time => 0.319,
|
61
|
+
:bytes_sent => 234,
|
62
|
+
:object_size => 65957,
|
63
|
+
:referer => nil,
|
64
|
+
:user_agent => '')
|
65
|
+
end
|
66
|
+
|
49
67
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::FileFormat::Rails do
|
4
|
+
|
5
|
+
it "should be a valid file format" do
|
6
|
+
RequestLogAnalyzer::FileFormat.load(:rails3).should be_valid
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#parse_line' do
|
10
|
+
before(:each) { @file_format = RequestLogAnalyzer::FileFormat.load(:rails3) }
|
11
|
+
|
12
|
+
it "should parse :started lines correctly" do
|
13
|
+
line = 'Started GET "/queries" for 127.0.0.1 at 2010-02-25 16:15:18'
|
14
|
+
@file_format.should parse_line(line).as(:started).and_capture(:method => 'GET',
|
15
|
+
:path => '/queries', :ip => '127.0.0.1', :timestamp => 20100225161518)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse :processing lines correctly" do
|
19
|
+
line = ' Processing by QueriesController#index as HTML'
|
20
|
+
@file_format.should parse_line(line).as(:processing).and_capture(
|
21
|
+
:controller => 'QueriesController', :action => 'index', :format => 'HTML')
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# it "should parse beta :completed lines correctly" do
|
26
|
+
# line = 'Completed in 9ms (Views: 4.9ms | ActiveRecord: 0.5ms) with 200'
|
27
|
+
# @file_format.should parse_line(line).as(:completed).and_capture(
|
28
|
+
# :duration => 0.009, :status => 200)
|
29
|
+
# end
|
30
|
+
|
31
|
+
it "should parse :completed lines correctly" do
|
32
|
+
line = 'Completed 200 OK in 170ms (Views: 78.4ms | ActiveRecord: 48.2ms)'
|
33
|
+
@file_format.should parse_line(line).as(:completed).and_capture(
|
34
|
+
:duration => 0.170, :status => 200)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should pase :failure lines correctly" do
|
38
|
+
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:"
|
39
|
+
@file_format.should parse_line(line).as(:failure).and_capture(:line => 3,
|
40
|
+
:error => 'ActionView::Template::Error',
|
41
|
+
:message => "undefined local variable or method `field' for #<Class>",
|
42
|
+
:file => '/Users/willem/Code/warehouse/app/views/queries/execute.csv.erb')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#parse_io' do
|
47
|
+
before(:each) do
|
48
|
+
@log_parser = RequestLogAnalyzer::Source::LogParser.new(RequestLogAnalyzer::FileFormat.load(:rails3))
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should parse a successful request correctly" do
|
52
|
+
log = <<-EOLOG
|
53
|
+
Started GET "/" for 127.0.0.1 at 2010-03-19 06:40:41
|
54
|
+
Processing by QueriesController#index as HTML
|
55
|
+
SQL (16.3ms) SHOW TABLES
|
56
|
+
Query Load (32.0ms) SELECT `queries`.* FROM `queries`
|
57
|
+
Rendered queries/index.html.erb within layouts/default (40.9ms)
|
58
|
+
Completed 200 OK in 170ms (Views: 78.4ms | ActiveRecord: 48.2ms)
|
59
|
+
EOLOG
|
60
|
+
|
61
|
+
request_counter.should_receive(:hit!).once
|
62
|
+
@log_parser.should_not_receive(:warn)
|
63
|
+
|
64
|
+
@log_parser.parse_io(StringIO.new(log)) do |request|
|
65
|
+
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should parse an unroutable request correctly" do
|
70
|
+
log = <<-EOLOG
|
71
|
+
Started GET "/404" for 127.0.0.1 at 2010-03-19 06:40:57
|
72
|
+
|
73
|
+
ActionController::RoutingError (No route matches "/404"):
|
74
|
+
|
75
|
+
|
76
|
+
Rendered /Users/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.0ms)
|
77
|
+
|
78
|
+
EOLOG
|
79
|
+
|
80
|
+
request_counter.should_receive(:hit!).once
|
81
|
+
@log_parser.should_not_receive(:warn)
|
82
|
+
|
83
|
+
@log_parser.parse_io(StringIO.new(log)) do |request|
|
84
|
+
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should parse a failing request correctly" do
|
89
|
+
log = <<-EOLOG
|
90
|
+
Started POST "/queries/397638749/execute.csv" for 127.0.0.1 at 2010-03-01 18:44:33
|
91
|
+
Processing by QueriesController#execute as CSV
|
92
|
+
Parameters: {"commit"=>"Run query", "authenticity_token"=>"pz9WcxkcrlG/43eg6BgSAnJL7yIsaffuHbYxPHUsUzQ=", "id"=>"397638749"}
|
93
|
+
|
94
|
+
ActionView::Template::Error (undefined local variable or method `field' for #<Class>) on line #3 of /Users/application/app/views/queries/execute.csv.erb:
|
95
|
+
1: <%=raw @result.fields.map { |f| f.humanize.to_json }.join(',') %>
|
96
|
+
2: <% @result.each do |record| %>
|
97
|
+
3: <%=raw @result.fields.map { |f| record[field].to_s }.join(",") %>
|
98
|
+
4: <% end %>
|
99
|
+
|
100
|
+
app/views/queries/execute.csv.erb:3:in `_render_template__652100315_2182241460_0'
|
101
|
+
app/views/queries/execute.csv.erb:3:in `map'
|
102
|
+
app/views/queries/execute.csv.erb:3:in `_render_template__652100315_2182241460_0'
|
103
|
+
app/views/queries/execute.csv.erb:2:in `_render_template__652100315_2182241460_0'
|
104
|
+
app/controllers/queries_controller.rb:34:in `execute'
|
105
|
+
|
106
|
+
Rendered /rails/actionpack-3.0.0.beta/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
|
107
|
+
Rendered /rails/actionpack-3.0.0.beta/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (9.7ms)
|
108
|
+
Rendered /rails/actionpack-3.0.0.beta/lib/action_dispatch/middleware/templates/rescues/template_error.erb within /Users/willem/.rvm/gems/ruby-1.8.7-p248/gems/actionpack-3.0.0.beta/lib/action_dispatch/middleware/templates/rescues/layout.erb (20.4ms)
|
109
|
+
|
110
|
+
EOLOG
|
111
|
+
|
112
|
+
request_counter.should_receive(:hit!).once
|
113
|
+
@log_parser.should_not_receive(:warn)
|
114
|
+
|
115
|
+
@log_parser.parse_io(StringIO.new(log)) do |request|
|
116
|
+
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/tasks/github-gem.rake
CHANGED
@@ -119,19 +119,19 @@ module GithubGem
|
|
119
119
|
checks = [:check_current_branch, :check_clean_status, :check_not_diverged, :check_version]
|
120
120
|
checks.unshift('spec:basic') if has_specs?
|
121
121
|
checks.unshift('test:basic') if has_tests?
|
122
|
-
checks.push << [:check_rubyforge] if gemspec.rubyforge_project
|
122
|
+
# checks.push << [:check_rubyforge] if gemspec.rubyforge_project
|
123
123
|
|
124
124
|
desc "Perform all checks that would occur before a release"
|
125
125
|
task(:release_checks => checks)
|
126
126
|
|
127
127
|
release_tasks = [:release_checks, :set_version, :build, :github_release, :gemcutter_release]
|
128
|
-
release_tasks << [:rubyforge_release] if gemspec.rubyforge_project
|
128
|
+
# release_tasks << [:rubyforge_release] if gemspec.rubyforge_project
|
129
129
|
|
130
130
|
desc "Release a new verison of the gem"
|
131
131
|
task(:release => release_tasks) { release_task }
|
132
132
|
|
133
|
-
task(:check_rubyforge) { check_rubyforge_task }
|
134
|
-
task(:rubyforge_release) { rubyforge_release_task }
|
133
|
+
# task(:check_rubyforge) { check_rubyforge_task }
|
134
|
+
# task(:rubyforge_release) { rubyforge_release_task }
|
135
135
|
task(:gemcutter_release) { gemcutter_release_task }
|
136
136
|
task(:github_release => [:commit_modified_files, :tag_version]) { github_release_task }
|
137
137
|
task(:tag_version) { tag_version_task }
|
@@ -216,19 +216,19 @@ module GithubGem
|
|
216
216
|
git.push(remote, remote_branch, true)
|
217
217
|
end
|
218
218
|
|
219
|
-
# Checks whether Rubyforge is configured properly
|
220
|
-
def check_rubyforge_task
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
end
|
227
|
-
|
228
|
-
# Task to release the .gem file toRubyforge.
|
229
|
-
def rubyforge_release_task
|
230
|
-
|
231
|
-
end
|
219
|
+
# # Checks whether Rubyforge is configured properly
|
220
|
+
# def check_rubyforge_task
|
221
|
+
# # Login no longer necessary when using rubyforge 2.0.0 gem
|
222
|
+
# # raise "Could not login on rubyforge!" unless `rubyforge login 2>&1`.strip.empty?
|
223
|
+
# output = `rubyforge names`.split("\n")
|
224
|
+
# raise "Rubyforge group not found!" unless output.any? { |line| %r[^groups\s*\:.*\b#{Regexp.quote(gemspec.rubyforge_project)}\b.*] =~ line }
|
225
|
+
# raise "Rubyforge package not found!" unless output.any? { |line| %r[^packages\s*\:.*\b#{Regexp.quote(gemspec.name)}\b.*] =~ line }
|
226
|
+
# end
|
227
|
+
|
228
|
+
# # Task to release the .gem file toRubyforge.
|
229
|
+
# def rubyforge_release_task
|
230
|
+
# sh 'rubyforge', 'add_release', gemspec.rubyforge_project, gemspec.name, gemspec.version.to_s, "pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
231
|
+
# end
|
232
232
|
|
233
233
|
def gemcutter_release_task
|
234
234
|
sh "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: request-log-analyzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 6
|
8
|
+
- 3
|
9
|
+
version: 1.6.3
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Willem van Bergen
|
@@ -10,29 +15,37 @@ autorequire:
|
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
17
|
|
13
|
-
date: 2010-
|
18
|
+
date: 2010-03-19 00:00:00 -04:00
|
14
19
|
default_executable: request-log-analyzer
|
15
20
|
dependencies:
|
16
21
|
- !ruby/object:Gem::Dependency
|
17
22
|
name: rspec
|
18
|
-
|
19
|
-
|
20
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
21
25
|
requirements:
|
22
26
|
- - ">="
|
23
27
|
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 2
|
31
|
+
- 4
|
24
32
|
version: 1.2.4
|
25
|
-
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
26
35
|
- !ruby/object:Gem::Dependency
|
27
36
|
name: git
|
28
|
-
|
29
|
-
|
30
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
39
|
requirements:
|
32
40
|
- - ">="
|
33
41
|
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 1
|
44
|
+
- 1
|
45
|
+
- 0
|
34
46
|
version: 1.1.0
|
35
|
-
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
36
49
|
description: " Request log analyzer's purpose is to find out how your web application is being used, how it performs and to\n focus your optimization efforts. This tool will parse all requests in the application's log file and aggregate the \n information. Once it is finished parsing the log file(s), it will show the requests that take op most server time \n using various metrics. It can also insert all parsed request information into a database so you can roll your own\n analysis. It supports Rails-, Merb- and Rack-based applications logs, Apache and Amazon S3 access logs and MySQL \n slow query logs out of the box, but file formats of other applications can easily be supported by supplying an \n easy to write log file format definition.\n"
|
37
50
|
email:
|
38
51
|
- willem@railsdoctors.com
|
@@ -65,8 +78,8 @@ files:
|
|
65
78
|
- lib/request_log_analyzer/tracker/frequency.rb
|
66
79
|
- lib/request_log_analyzer/tracker/duration.rb
|
67
80
|
- tasks/github-gem.rake
|
68
|
-
- .gitignore
|
69
81
|
- spec/unit/filter/filter_spec.rb
|
82
|
+
- .gitignore
|
70
83
|
- spec/lib/macros.rb
|
71
84
|
- spec/spec_helper.rb
|
72
85
|
- spec/fixtures/decompression.log.bz2
|
@@ -92,7 +105,9 @@ files:
|
|
92
105
|
- spec/lib/mocks.rb
|
93
106
|
- spec/unit/file_format/apache_format_spec.rb
|
94
107
|
- spec/fixtures/syslog_1x.log
|
108
|
+
- spec/unit/file_format/rails3_format_spec.rb
|
95
109
|
- spec/integration/munin_plugins_rails_spec.rb
|
110
|
+
- lib/request_log_analyzer/file_format/rails3.rb
|
96
111
|
- spec/lib/helpers.rb
|
97
112
|
- spec/unit/file_format/delayed_job_format_spec.rb
|
98
113
|
- spec/fixtures/rails.db
|
@@ -144,8 +159,8 @@ files:
|
|
144
159
|
- lib/request_log_analyzer/file_format/postgresql.rb
|
145
160
|
- lib/request_log_analyzer/tracker/timespan.rb
|
146
161
|
- spec/unit/controller/log_processor_spec.rb
|
147
|
-
- spec/fixtures/sinatra.log
|
148
162
|
- spec/unit/filter/field_filter_spec.rb
|
163
|
+
- spec/fixtures/sinatra.log
|
149
164
|
- spec/fixtures/merb_prefixed.log
|
150
165
|
- lib/request_log_analyzer/log_processor.rb
|
151
166
|
- lib/request_log_analyzer/filter/timespan.rb
|
@@ -189,18 +204,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
189
204
|
requirements:
|
190
205
|
- - ">="
|
191
206
|
- !ruby/object:Gem::Version
|
207
|
+
segments:
|
208
|
+
- 0
|
192
209
|
version: "0"
|
193
|
-
version:
|
194
210
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
211
|
requirements:
|
196
212
|
- - ">="
|
197
213
|
- !ruby/object:Gem::Version
|
214
|
+
segments:
|
215
|
+
- 0
|
198
216
|
version: "0"
|
199
|
-
version:
|
200
217
|
requirements:
|
201
218
|
- To use the database inserter, ActiveRecord and an appropriate database adapter are required.
|
202
219
|
rubyforge_project: r-l-a
|
203
|
-
rubygems_version: 1.3.
|
220
|
+
rubygems_version: 1.3.6
|
204
221
|
signing_key:
|
205
222
|
specification_version: 3
|
206
223
|
summary: A command line tool to analyze request logs for Apache, Rails, Merb, MySQL and other web application servers
|
@@ -219,6 +236,7 @@ test_files:
|
|
219
236
|
- spec/integration/mailer_spec.rb
|
220
237
|
- spec/unit/tracker/frequency_tracker_spec.rb
|
221
238
|
- spec/unit/file_format/apache_format_spec.rb
|
239
|
+
- spec/unit/file_format/rails3_format_spec.rb
|
222
240
|
- spec/integration/munin_plugins_rails_spec.rb
|
223
241
|
- spec/unit/file_format/delayed_job_format_spec.rb
|
224
242
|
- spec/unit/source/log_parser_spec.rb
|