wvanbergen-request-log-analyzer 0.3.3 → 0.3.4
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/Rakefile +2 -2
- data/TODO +0 -1
- data/bin/request-log-analyzer +28 -28
- data/bin/request-log-database +81 -0
- data/lib/base/log_parser.rb +78 -0
- data/lib/base/record_inserter.rb +139 -0
- data/lib/command_line/arguments.rb +2 -15
- data/lib/command_line/flag.rb +0 -12
- data/lib/merb_analyzer/log_parser.rb +26 -0
- data/lib/rails_analyzer/log_parser.rb +35 -0
- data/lib/rails_analyzer/record_inserter.rb +39 -0
- data/lib/request_log_analyzer.rb +161 -5
- data/tasks/test.rake +8 -0
- data/test/log_fragments/fragment_1.log +59 -0
- data/test/log_fragments/fragment_2.log +5 -0
- data/test/log_fragments/fragment_3.log +12 -0
- data/test/log_fragments/fragment_4.log +10 -0
- data/test/log_fragments/fragment_5.log +24 -0
- data/test/log_fragments/merb_1.log +84 -0
- data/test/merb_log_parser_test.rb +39 -0
- data/test/rails_log_parser_test.rb +99 -0
- data/test/record_inserter_test.rb +45 -0
- metadata +23 -16
- data/lib/request_log_analyzer/aggregator/base.rb +0 -34
- data/lib/request_log_analyzer/aggregator/database.rb +0 -86
- data/lib/request_log_analyzer/aggregator/echo.rb +0 -10
- data/lib/request_log_analyzer/aggregator/summarizer.rb +0 -53
- data/lib/request_log_analyzer/controller.rb +0 -90
- data/lib/request_log_analyzer/file_format.rb +0 -91
- data/lib/request_log_analyzer/file_format/merb.rb +0 -30
- data/lib/request_log_analyzer/file_format/rails.rb +0 -84
- data/lib/request_log_analyzer/log_parser.rb +0 -122
- data/lib/request_log_analyzer/request.rb +0 -72
- data/tasks/rspec.rake +0 -6
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require "#{File.dirname(__FILE__)}/../lib/base/log_parser"
|
4
|
+
require "#{File.dirname(__FILE__)}/../lib/merb_analyzer/log_parser"
|
5
|
+
|
6
|
+
class MerbLogParserTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def fragment_file(number)
|
9
|
+
"#{File.dirname(__FILE__)}/log_fragments/merb_#{number}.log"
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_parse_started_merb_fragment
|
13
|
+
requests = []
|
14
|
+
parser = MerbAnalyzer::LogParser.new(fragment_file(1)).each(:started) do |request|
|
15
|
+
requests << request
|
16
|
+
end
|
17
|
+
assert_equal requests[0][:timestamp], "Fri Aug 29 11:10:23 +0200 2008"
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_parse_completed_merb_fragment
|
21
|
+
requests = []
|
22
|
+
parser = MerbAnalyzer::LogParser.new(fragment_file(1)).each(:completed) do |request|
|
23
|
+
requests << request
|
24
|
+
end
|
25
|
+
|
26
|
+
assert_equal requests[0][:action_time], 0.241652
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_parse_params_merb_fragment
|
30
|
+
requests = []
|
31
|
+
parser = MerbAnalyzer::LogParser.new(fragment_file(1)).each(:params) do |request|
|
32
|
+
requests << request
|
33
|
+
end
|
34
|
+
|
35
|
+
assert_match '"controller"=>"session"', requests[0][:raw_hash]
|
36
|
+
assert_match '"action"=>"destroy"', requests[0][:raw_hash]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require "#{File.dirname(__FILE__)}/../lib/request_log_analyzer"
|
4
|
+
|
5
|
+
class RailsLogParserTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def fragment_file(number)
|
8
|
+
"#{File.dirname(__FILE__)}/log_fragments/fragment_#{number}.log"
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def test_rails_22_log_format
|
13
|
+
count = 0
|
14
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(3)).each(:completed) do |request|
|
15
|
+
count += 1
|
16
|
+
assert_equal 0.614, request[:duration] # should be 0.614
|
17
|
+
end
|
18
|
+
assert_equal 1, count
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_progress_messages
|
22
|
+
log_file = fragment_file(1)
|
23
|
+
|
24
|
+
finished_encountered = false
|
25
|
+
file_size = File.size(log_file)
|
26
|
+
|
27
|
+
previous_pos = -1
|
28
|
+
parser = RailsAnalyzer::LogParser.new(log_file)
|
29
|
+
parser.progress do |pos, total|
|
30
|
+
assert_equal file_size, total
|
31
|
+
if pos == :finished
|
32
|
+
finished_encountered = true
|
33
|
+
else
|
34
|
+
assert pos <= total
|
35
|
+
assert pos > previous_pos
|
36
|
+
previous_pos = pos
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# now parse the file
|
41
|
+
parser.each(:started) { }
|
42
|
+
|
43
|
+
assert finished_encountered, "A finished event should have been fired"
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_parse_mongrel_log_fragment
|
47
|
+
count = 0
|
48
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(1)).each(:started) { count += 1 }
|
49
|
+
assert_equal 4, count
|
50
|
+
|
51
|
+
count = 0
|
52
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(1)).each(:completed) { count += 1 }
|
53
|
+
assert_equal 4, count
|
54
|
+
|
55
|
+
count = 0
|
56
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(1)).each(:started, :completed) { count += 1 }
|
57
|
+
assert_equal 8, count
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_parse_syslog_fragment
|
61
|
+
count = 0
|
62
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(2)).each(:started) { count += 1 }
|
63
|
+
assert_equal 1, count
|
64
|
+
|
65
|
+
count = 0
|
66
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(2)).each(:completed) { count += 1 }
|
67
|
+
assert_equal 1, count
|
68
|
+
|
69
|
+
count = 0
|
70
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(2)).each(:started, :completed) { count += 1 }
|
71
|
+
assert_equal 2, count
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_parse_syslog_fragment_content
|
75
|
+
# this test only works because there is only one requests in the fragment
|
76
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(2)).each(:started) do |request|
|
77
|
+
assert_equal "EmployeeController", request[:controller]
|
78
|
+
assert_equal "index", request[:action]
|
79
|
+
assert_equal "GET", request[:method]
|
80
|
+
assert_equal '10.1.1.33', request[:ip]
|
81
|
+
assert_equal '2008-07-13 06:25:58', request[:timestamp]
|
82
|
+
end
|
83
|
+
|
84
|
+
parser = RailsAnalyzer::LogParser.new(fragment_file(2)).each(:completed) do |request|
|
85
|
+
assert_equal "http://example.com/employee.xml", request[:url]
|
86
|
+
assert_equal 200, request[:status]
|
87
|
+
assert_equal 0.21665, request[:duration]
|
88
|
+
assert_equal 0.00926, request[:rendering]
|
89
|
+
assert_equal 0.0, request[:db]
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_virtual_mongrel
|
95
|
+
request_log_analyzer = RequestLogAnalyzer.new()
|
96
|
+
request_log_analyzer.analyze_with_virtual_mongrels([fragment_file(5)])
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require "#{File.dirname(__FILE__)}/../lib/base/log_parser"
|
4
|
+
require "#{File.dirname(__FILE__)}/../lib/base/record_inserter"
|
5
|
+
|
6
|
+
require "#{File.dirname(__FILE__)}/../lib/rails_analyzer/log_parser"
|
7
|
+
require "#{File.dirname(__FILE__)}/../lib/rails_analyzer/record_inserter"
|
8
|
+
|
9
|
+
class RecordInserterTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def fragment_file(number)
|
12
|
+
"#{File.dirname(__FILE__)}/log_fragments/fragment_#{number}.log"
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup
|
16
|
+
File.delete('_tmp.db') if File.exist?('_tmp.db')
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
File.delete('_tmp.db') if File.exist?('_tmp.db')
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_insert_log_fragment
|
24
|
+
|
25
|
+
db = RailsAnalyzer::RecordInserter.insert_batch_into('_tmp.db') do |batch|
|
26
|
+
RailsAnalyzer::LogParser.new(fragment_file(1)).each { |request| batch.insert(request) }
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_equal 4, db.database.get_first_value("SELECT COUNT(*) FROM started_requests").to_i
|
30
|
+
assert_equal 4, db.database.get_first_value("SELECT COUNT(*) FROM completed_requests").to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_insert_multiple_fragments
|
34
|
+
RailsAnalyzer::RecordInserter.insert_batch_into('_tmp.db') do |batch|
|
35
|
+
RailsAnalyzer::LogParser.new(fragment_file(1)).each { |request| batch.insert(request) }
|
36
|
+
end
|
37
|
+
|
38
|
+
db = RailsAnalyzer::RecordInserter.insert_batch_into('_tmp.db') do |batch|
|
39
|
+
RailsAnalyzer::LogParser.new(fragment_file(2)).each { |request| batch.insert(request) }
|
40
|
+
end
|
41
|
+
assert_equal 5, db.database.get_first_value("SELECT COUNT(*) FROM started_requests").to_i
|
42
|
+
assert_equal 5, db.database.get_first_value("SELECT COUNT(*) FROM completed_requests").to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wvanbergen-request-log-analyzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2008-12-
|
13
|
+
date: 2008-12-29 00:00:00 -08:00
|
14
14
|
default_executable: request-log-analyzer
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -18,6 +18,7 @@ description: Rails log analyzer's purpose is to find what actions are best candi
|
|
18
18
|
email: willem@vanbergen.org
|
19
19
|
executables:
|
20
20
|
- request-log-analyzer
|
21
|
+
- request-log-database
|
21
22
|
extensions: []
|
22
23
|
|
23
24
|
extra_rdoc_files: []
|
@@ -29,8 +30,11 @@ files:
|
|
29
30
|
- TODO
|
30
31
|
- bin
|
31
32
|
- bin/request-log-analyzer
|
33
|
+
- bin/request-log-database
|
32
34
|
- lib
|
33
35
|
- lib/base
|
36
|
+
- lib/base/log_parser.rb
|
37
|
+
- lib/base/record_inserter.rb
|
34
38
|
- lib/base/summarizer.rb
|
35
39
|
- lib/bashcolorizer.rb
|
36
40
|
- lib/command_line
|
@@ -38,24 +42,14 @@ files:
|
|
38
42
|
- lib/command_line/exceptions.rb
|
39
43
|
- lib/command_line/flag.rb
|
40
44
|
- lib/merb_analyzer
|
45
|
+
- lib/merb_analyzer/log_parser.rb
|
41
46
|
- lib/merb_analyzer/summarizer.rb
|
42
47
|
- lib/rails_analyzer
|
48
|
+
- lib/rails_analyzer/log_parser.rb
|
49
|
+
- lib/rails_analyzer/record_inserter.rb
|
43
50
|
- lib/rails_analyzer/summarizer.rb
|
44
51
|
- lib/rails_analyzer/virtual_mongrel.rb
|
45
|
-
- lib/request_log_analyzer
|
46
52
|
- lib/request_log_analyzer.rb
|
47
|
-
- lib/request_log_analyzer/aggregator
|
48
|
-
- lib/request_log_analyzer/aggregator/base.rb
|
49
|
-
- lib/request_log_analyzer/aggregator/database.rb
|
50
|
-
- lib/request_log_analyzer/aggregator/echo.rb
|
51
|
-
- lib/request_log_analyzer/aggregator/summarizer.rb
|
52
|
-
- lib/request_log_analyzer/controller.rb
|
53
|
-
- lib/request_log_analyzer/file_format
|
54
|
-
- lib/request_log_analyzer/file_format.rb
|
55
|
-
- lib/request_log_analyzer/file_format/merb.rb
|
56
|
-
- lib/request_log_analyzer/file_format/rails.rb
|
57
|
-
- lib/request_log_analyzer/log_parser.rb
|
58
|
-
- lib/request_log_analyzer/request.rb
|
59
53
|
- lib/ruby-progressbar
|
60
54
|
- lib/ruby-progressbar/progressbar.en.rd
|
61
55
|
- lib/ruby-progressbar/progressbar.ja.rd
|
@@ -97,9 +91,19 @@ files:
|
|
97
91
|
- tasks
|
98
92
|
- tasks/github-gem.rake
|
99
93
|
- tasks/request_log_analyzer.rake
|
100
|
-
- tasks/
|
94
|
+
- tasks/test.rake
|
101
95
|
- test
|
102
96
|
- test/base_summarizer_test.rb
|
97
|
+
- test/log_fragments
|
98
|
+
- test/log_fragments/fragment_1.log
|
99
|
+
- test/log_fragments/fragment_2.log
|
100
|
+
- test/log_fragments/fragment_3.log
|
101
|
+
- test/log_fragments/fragment_4.log
|
102
|
+
- test/log_fragments/fragment_5.log
|
103
|
+
- test/log_fragments/merb_1.log
|
104
|
+
- test/merb_log_parser_test.rb
|
105
|
+
- test/rails_log_parser_test.rb
|
106
|
+
- test/record_inserter_test.rb
|
103
107
|
has_rdoc: false
|
104
108
|
homepage: http://github.com/wvanbergen/request-log-analyzer/wikis
|
105
109
|
post_install_message:
|
@@ -128,3 +132,6 @@ specification_version: 2
|
|
128
132
|
summary: A command line tool to analyze Rails logs
|
129
133
|
test_files:
|
130
134
|
- test/base_summarizer_test.rb
|
135
|
+
- test/merb_log_parser_test.rb
|
136
|
+
- test/rails_log_parser_test.rb
|
137
|
+
- test/record_inserter_test.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module RequestLogAnalyzer::Aggregator
|
2
|
-
|
3
|
-
|
4
|
-
class Base
|
5
|
-
|
6
|
-
include RequestLogAnalyzer::FileFormat
|
7
|
-
|
8
|
-
attr_reader :options
|
9
|
-
|
10
|
-
def initialize(format, options = {})
|
11
|
-
self.register_file_format(format)
|
12
|
-
@options = options
|
13
|
-
end
|
14
|
-
|
15
|
-
def aggregate(request)
|
16
|
-
# implement me!
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
def prepare
|
21
|
-
end
|
22
|
-
|
23
|
-
def finalize
|
24
|
-
end
|
25
|
-
|
26
|
-
def warning(type, message, lineno)
|
27
|
-
end
|
28
|
-
|
29
|
-
def report(color = false)
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'activerecord'
|
3
|
-
|
4
|
-
module RequestLogAnalyzer::Aggregator
|
5
|
-
|
6
|
-
class Database < Base
|
7
|
-
|
8
|
-
attr_reader :request_id
|
9
|
-
|
10
|
-
def prepare
|
11
|
-
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => options[:database])
|
12
|
-
|
13
|
-
File.unlink(options[:database]) if File.exist?(options[:database])
|
14
|
-
create_database_schema!
|
15
|
-
|
16
|
-
@request_id = 0
|
17
|
-
end
|
18
|
-
|
19
|
-
def aggregate(request)
|
20
|
-
@request_id += 1
|
21
|
-
|
22
|
-
request.lines.each do |line|
|
23
|
-
class_name = "#{line[:line_type]}_line".camelize #split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join('')
|
24
|
-
|
25
|
-
attributes = line.reject { |k, v| [:line_type].include?(k) }
|
26
|
-
attributes[:request_id] = @request_id if options[:combined_requests]
|
27
|
-
file_format.const_get(class_name).create!(attributes)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def warning(type, message, lineno)
|
33
|
-
file_format::Warning.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
|
38
|
-
def create_database_table(name, definition)
|
39
|
-
ActiveRecord::Migration.suppress_messages do
|
40
|
-
ActiveRecord::Migration.create_table("#{name}_lines") do |t|
|
41
|
-
t.column(:request_id, :integer) #if options[:combined_requests]
|
42
|
-
t.column(:lineno, :integer)
|
43
|
-
definition.captures.each do |field|
|
44
|
-
# there is only on key/value pait in this hash
|
45
|
-
field.each { |key, capture_type| t.column(key, column_type(capture_type)) }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def create_warning_table_and_class
|
52
|
-
ActiveRecord::Migration.suppress_messages do
|
53
|
-
ActiveRecord::Migration.create_table("warnings") do |t|
|
54
|
-
t.string :warning_type, :limit => 30, :null => false
|
55
|
-
t.string :message
|
56
|
-
t.integer :lineno
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
file_format.const_set('Warning', Class.new(ActiveRecord::Base)) unless file_format.const_defined?('Warning')
|
61
|
-
end
|
62
|
-
|
63
|
-
def create_activerecord_class(name, definition)
|
64
|
-
class_name = "#{name}_line".camelize
|
65
|
-
file_format.const_set(class_name, Class.new(ActiveRecord::Base)) unless file_format.const_defined?(class_name)
|
66
|
-
end
|
67
|
-
|
68
|
-
def create_database_schema!
|
69
|
-
file_format.line_definitions.each do |name, definition|
|
70
|
-
create_database_table(name, definition)
|
71
|
-
create_activerecord_class(name, definition)
|
72
|
-
end
|
73
|
-
|
74
|
-
create_warning_table_and_class
|
75
|
-
end
|
76
|
-
|
77
|
-
def column_type(capture_type)
|
78
|
-
case capture_type
|
79
|
-
when :sec; :double
|
80
|
-
when :msec; :double
|
81
|
-
when :float; :double
|
82
|
-
else capture_type
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module RequestLogAnalyzer::Aggregator
|
2
|
-
|
3
|
-
class Summarizer < Base
|
4
|
-
|
5
|
-
attr_reader :buckets
|
6
|
-
|
7
|
-
def prepare
|
8
|
-
@buckets = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
def aggregate(request)
|
12
|
-
if options[:combined_requests]
|
13
|
-
current_bucket_hash = @buckets
|
14
|
-
else
|
15
|
-
@buckets[request.line_type] ||= {}
|
16
|
-
current_bucket_hash = @buckets[request.line_type]
|
17
|
-
end
|
18
|
-
|
19
|
-
bucket_name = bucket_for(request)
|
20
|
-
current_bucket_hash[bucket_name] ||= default_bucket_content
|
21
|
-
update_bucket(current_bucket_hash[bucket_name], request)
|
22
|
-
end
|
23
|
-
|
24
|
-
def default_bucket_content
|
25
|
-
return { :count => 0 }
|
26
|
-
end
|
27
|
-
|
28
|
-
def update_bucket(bucket, request)
|
29
|
-
bucket[:count] += 1
|
30
|
-
end
|
31
|
-
|
32
|
-
def bucket_for(request)
|
33
|
-
'all'
|
34
|
-
end
|
35
|
-
|
36
|
-
def report(color = false)
|
37
|
-
if options[:combined_requests]
|
38
|
-
@buckets.each do |hash, values|
|
39
|
-
puts " #{hash[0..40].ljust(41)}: #{values[:count]}"
|
40
|
-
end
|
41
|
-
else
|
42
|
-
@buckets.each do |line_type, buckets|
|
43
|
-
puts "Line type #{line_type.inspect}:"
|
44
|
-
buckets.each do |hash, values|
|
45
|
-
puts " #{hash[0..40].ljust(41)}: #{values[:count]}"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|