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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module RequestLogAnalyzer::Tracker
|
|
2
|
-
|
|
3
2
|
# Analyze the average and total traffic of requests
|
|
4
3
|
#
|
|
5
4
|
# === Options
|
|
@@ -10,16 +9,15 @@ module RequestLogAnalyzer::Tracker
|
|
|
10
9
|
# * <tt>:title</tt> Title do be displayed above the report
|
|
11
10
|
# * <tt>:unless</tt> Handle request if this proc is false for the handled request.
|
|
12
11
|
class Traffic < NumericValue
|
|
13
|
-
|
|
14
12
|
# Check if duration and catagory option have been received,
|
|
15
13
|
def prepare
|
|
16
14
|
options[:value] = options[:traffic] if options[:traffic]
|
|
17
15
|
options[:total] = true
|
|
18
16
|
super
|
|
19
|
-
|
|
17
|
+
|
|
20
18
|
@number_of_buckets = options[:number_of_buckets] || 1000
|
|
21
19
|
@min_bucket_value = options[:min_bucket_value] ? options[:min_bucket_value].to_f : 1
|
|
22
|
-
@max_bucket_value = options[:max_bucket_value] ? options[:max_bucket_value].to_f :
|
|
20
|
+
@max_bucket_value = options[:max_bucket_value] ? options[:max_bucket_value].to_f : 1_000_000_000_000
|
|
23
21
|
|
|
24
22
|
# precalculate the bucket size
|
|
25
23
|
@bucket_size = (Math.log(@max_bucket_value) - Math.log(@min_bucket_value)) / @number_of_buckets.to_f
|
|
@@ -27,15 +25,15 @@ module RequestLogAnalyzer::Tracker
|
|
|
27
25
|
|
|
28
26
|
# Formats the traffic number using x B/kB/MB/GB etc notation
|
|
29
27
|
def display_value(bytes)
|
|
30
|
-
return
|
|
31
|
-
return
|
|
32
|
-
|
|
28
|
+
return '-' if bytes.nil?
|
|
29
|
+
return '0 B' if bytes.zero?
|
|
30
|
+
|
|
33
31
|
case [Math.log10(bytes.abs).floor, 0].max
|
|
34
32
|
when 0...4 then '%d B' % bytes
|
|
35
33
|
when 4...7 then '%d kB' % (bytes / 1000)
|
|
36
|
-
when 7...10 then '%d MB' % (bytes /
|
|
37
|
-
when 10...13 then '%d GB' % (bytes /
|
|
38
|
-
else '%d TB' % (bytes /
|
|
34
|
+
when 7...10 then '%d MB' % (bytes / 1_000_000)
|
|
35
|
+
when 10...13 then '%d GB' % (bytes / 1_000_000_000)
|
|
36
|
+
else '%d TB' % (bytes / 1_000_000_000_000)
|
|
39
37
|
end
|
|
40
38
|
end
|
|
41
39
|
|
|
@@ -17,11 +17,11 @@ Gem::Specification.new do |gem|
|
|
|
17
17
|
gem.summary = "A command line tool to analyze request logs for Apache, Rails, Merb, MySQL and other web application servers"
|
|
18
18
|
gem.description = <<-eos
|
|
19
19
|
Request log analyzer's purpose is to find out how your web application is being used, how it performs and to
|
|
20
|
-
focus your optimization efforts. This tool will parse all requests in the application's log file and aggregate the
|
|
21
|
-
information. Once it is finished parsing the log file(s), it will show the requests that take op most server time
|
|
20
|
+
focus your optimization efforts. This tool will parse all requests in the application's log file and aggregate the
|
|
21
|
+
information. Once it is finished parsing the log file(s), it will show the requests that take op most server time
|
|
22
22
|
using various metrics. It can also insert all parsed request information into a database so you can roll your own
|
|
23
|
-
analysis. It supports Rails-, Merb- and Rack-based applications logs, Apache and Amazon S3 access logs and MySQL
|
|
24
|
-
slow query logs out of the box, but file formats of other applications can easily be supported by supplying an
|
|
23
|
+
analysis. It supports Rails-, Merb- and Rack-based applications logs, Apache and Amazon S3 access logs and MySQL
|
|
24
|
+
slow query logs out of the box, but file formats of other applications can easily be supported by supplying an
|
|
25
25
|
easy to write log file format definition.
|
|
26
26
|
eos
|
|
27
27
|
|
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |gem|
|
|
|
32
32
|
gem.required_ruby_version = '>= 1.9.3'
|
|
33
33
|
|
|
34
34
|
gem.add_development_dependency('rake')
|
|
35
|
-
gem.add_development_dependency('rspec', '~>
|
|
35
|
+
gem.add_development_dependency('rspec', '~> 3')
|
|
36
36
|
gem.add_development_dependency('activerecord')
|
|
37
37
|
if defined?(JRUBY_VERSION)
|
|
38
38
|
gem.add_development_dependency('jdbc-sqlite3')
|
|
@@ -46,7 +46,7 @@ Gem::Specification.new do |gem|
|
|
|
46
46
|
gem.add_development_dependency('mysql2')
|
|
47
47
|
gem.add_development_dependency('pg')
|
|
48
48
|
end
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
gem.files = `git ls-files`.split($/)
|
|
51
51
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
52
52
|
|
|
@@ -10,85 +10,85 @@ describe RequestLogAnalyzer, 'running from command line' do
|
|
|
10
10
|
cleanup_temp_files!
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
it
|
|
13
|
+
it 'should find 4 requests in default mode' do
|
|
14
14
|
output = run("#{log_fixture(:rails_1x)}")
|
|
15
|
-
output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should
|
|
15
|
+
output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should == true
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
it
|
|
18
|
+
it 'should find 2 requests when parsing a compressed file' do
|
|
19
19
|
output = run("#{log_fixture(:decompression, :tgz)}")
|
|
20
|
-
output.any? { |line| /^Parsed requests\:\s*2\s/ =~ line }.should
|
|
20
|
+
output.any? { |line| /^Parsed requests\:\s*2\s/ =~ line }.should == true
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
it
|
|
23
|
+
it 'should skip 1 requests with a --select option' do
|
|
24
24
|
output = run("#{log_fixture(:rails_1x)} --select controller PeopleController")
|
|
25
|
-
output.any? { |line| /^Skipped requests\:\s*1\s/ =~ line }.should
|
|
25
|
+
output.any? { |line| /^Skipped requests\:\s*1\s/ =~ line }.should == true
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
it
|
|
28
|
+
it 'should skip 3 requests with a --reject option' do
|
|
29
29
|
output = run("#{log_fixture(:rails_1x)} --reject controller PeopleController")
|
|
30
|
-
output.any? { |line| /^Skipped requests\:\s*3\s/ =~ line }.should
|
|
30
|
+
output.any? { |line| /^Skipped requests\:\s*3\s/ =~ line }.should == true
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
it
|
|
33
|
+
it 'should not write output with the --silent option' do
|
|
34
34
|
output = run("#{log_fixture(:rails_1x)} --silent --file #{temp_output_file(:report)}")
|
|
35
35
|
output.should be_empty
|
|
36
|
-
File.exist?(temp_output_file(:report)).should
|
|
36
|
+
File.exist?(temp_output_file(:report)).should == true
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
it
|
|
39
|
+
it 'should write output to a file with the --file option' do
|
|
40
40
|
run("#{log_fixture(:rails_1x)} --file #{temp_output_file(:report)}")
|
|
41
|
-
File.exist?(temp_output_file(:report)).should
|
|
41
|
+
File.exist?(temp_output_file(:report)).should == true
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
it
|
|
44
|
+
it 'should write only ASCII characters to a file with the --file option' do
|
|
45
45
|
run("#{log_fixture(:rails_1x)} --file #{temp_output_file(:report)}")
|
|
46
46
|
/^[\x00-\x7F]*$/.match(File.read(temp_output_file(:report))).should_not be_nil
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
it
|
|
49
|
+
it 'should write HTML if --output HTML is provided' do
|
|
50
50
|
output = run("#{log_fixture(:rails_1x)} --output HTML")
|
|
51
|
-
output.any? { |line| /<html[^>]*>/ =~ line}.should
|
|
51
|
+
output.any? { |line| /<html[^>]*>/ =~ line }.should == true
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
it
|
|
54
|
+
it 'should run with the --database option' do
|
|
55
55
|
run("#{log_fixture(:rails_1x)} --database #{temp_output_file(:database)}")
|
|
56
|
-
File.exist?(temp_output_file(:database)).should
|
|
56
|
+
File.exist?(temp_output_file(:database)).should == true
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
it
|
|
59
|
+
it 'should use no colors in the report with the --boring option' do
|
|
60
60
|
output = run("#{log_fixture(:rails_1x)} --boring --format rails")
|
|
61
|
-
output.any? { |line| /\e/ =~ line }.should
|
|
61
|
+
output.any? { |line| /\e/ =~ line }.should == false
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
it
|
|
64
|
+
it 'should use only ASCII characters in the report with the --boring option' do
|
|
65
65
|
output = run("#{log_fixture(:rails_1x)} --boring")
|
|
66
|
-
output.all? { |line| /^[\x00-\x7F]*$/ =~ line }.should
|
|
66
|
+
output.all? { |line| /^[\x00-\x7F]*$/ =~ line }.should == true
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
it
|
|
69
|
+
it 'should parse a Merb file if --format merb is set' do
|
|
70
70
|
output = run("#{log_fixture(:merb)} --format merb")
|
|
71
|
-
output.any? { |line| /Parsed requests\:\s*11/ =~ line }.should
|
|
71
|
+
output.any? { |line| /Parsed requests\:\s*11/ =~ line }.should == true
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
it
|
|
74
|
+
it 'should parse a Apache access log file if --apache-format is set' do
|
|
75
75
|
output = run("#{log_fixture(:apache_combined)} --apache-format combined")
|
|
76
|
-
output.any? { |line| /Parsed requests\:\s*5/ =~ line }.should
|
|
76
|
+
output.any? { |line| /Parsed requests\:\s*5/ =~ line }.should == true
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
it
|
|
79
|
+
it 'should dump the results to a YAML file' do
|
|
80
80
|
run("#{log_fixture(:rails_1x)} --yaml #{temp_output_file(:yaml)}")
|
|
81
|
-
File.exist?(temp_output_file(:yaml)).should
|
|
82
|
-
YAML.load(File.read(temp_output_file(:yaml))).should
|
|
81
|
+
File.exist?(temp_output_file(:yaml)).should == true
|
|
82
|
+
YAML.load(File.read(temp_output_file(:yaml))).length.should be >= 1
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
it
|
|
85
|
+
it 'should parse 4 requests from the standard input' do
|
|
86
86
|
output = run("--format rails - < #{log_fixture(:rails_1x)}")
|
|
87
|
-
output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should
|
|
87
|
+
output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should == true
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
it
|
|
91
|
-
output = run("#{log_directory_fixture(
|
|
92
|
-
output.any? { |line| /^Parsed requests:\s*8\s/ =~ line }.should
|
|
90
|
+
it 'should accept a directory as a commandline option' do
|
|
91
|
+
output = run("#{log_directory_fixture('s3_logs')} --format amazon_s3")
|
|
92
|
+
output.any? { |line| /^Parsed requests:\s*8\s/ =~ line }.should == true
|
|
93
93
|
end
|
|
94
94
|
end
|
|
@@ -1,230 +1,226 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'socket'
|
|
3
3
|
|
|
4
|
-
unless defined?(JRUBY_VERSION) #No Fork on JRUBY
|
|
4
|
+
unless defined?(JRUBY_VERSION) # No Fork on JRUBY
|
|
5
5
|
|
|
6
|
-
describe RequestLogAnalyzer, 'running mailer integration' do
|
|
6
|
+
describe RequestLogAnalyzer, 'running mailer integration' do
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
before(:each) do
|
|
9
|
+
@log_file = temp_output_file('mailtrap.log')
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
Process.fork do
|
|
12
|
+
Mailtrap.new('localhost', 2525, true, @log_file)
|
|
13
|
+
Process.exit! # Do not call rspec after exit hook!
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
after(:each) do
|
|
18
|
+
cleanup_temp_files!
|
|
19
|
+
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
21
|
+
it 'should send plaintext mail' do
|
|
22
|
+
RequestLogAnalyzer::Controller.build(
|
|
23
|
+
mail: 'root@localhost',
|
|
24
|
+
mailhost: 'localhost:2525',
|
|
25
|
+
source_files: log_fixture(:rails_1x),
|
|
26
|
+
format: RequestLogAnalyzer::FileFormat::Rails,
|
|
27
|
+
no_progress: true
|
|
28
|
+
).run!
|
|
29
|
+
|
|
30
|
+
Process.wait # Wait for mailer to complete
|
|
31
|
+
|
|
32
|
+
find_string_in_file('From: <contact@railsdoctors.com>', @log_file).should_not be_nil
|
|
33
|
+
find_string_in_file('To: <root@localhost>', @log_file).should_not be_nil
|
|
34
|
+
find_string_in_file('From: Request-log-analyzer reporter <contact@railsdoctors.com>', @log_file).should_not be_nil
|
|
35
|
+
find_string_in_file('Subject: Request log analyzer report - generated on', @log_file).should_not be_nil
|
|
36
|
+
find_string_in_file('Request summary', @log_file).should_not be_nil
|
|
37
|
+
find_string_in_file('PeopleControll | 1 | 40ms | 40ms | 0ms | 40ms | 40ms | 40ms-41ms', @log_file).should_not be_nil
|
|
38
|
+
end
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
it 'should allow a custom mail subject' do
|
|
41
|
+
RequestLogAnalyzer::Controller.build(
|
|
42
|
+
mail: 'root@localhost',
|
|
43
|
+
mailhost: 'localhost:2525',
|
|
44
|
+
mailsubject: 'TESTSUBJECT',
|
|
45
|
+
source_files: log_fixture(:rails_1x),
|
|
46
|
+
format: RequestLogAnalyzer::FileFormat::Rails,
|
|
47
|
+
no_progress: true
|
|
48
|
+
).run!
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
Process.wait # Wait for mailer to complete
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
find_string_in_file('Subject: TESTSUBJECT', @log_file).should_not be_nil
|
|
53
|
+
end
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
it 'should allow a custom mail sender address' do
|
|
56
|
+
RequestLogAnalyzer::Controller.build(
|
|
57
|
+
mail: 'root@localhost',
|
|
58
|
+
mailhost: 'localhost:2525',
|
|
59
|
+
mailfrom: 'customaddr@example.com',
|
|
60
|
+
source_files: log_fixture(:rails_1x),
|
|
61
|
+
format: RequestLogAnalyzer::FileFormat::Rails,
|
|
62
|
+
no_progress: true
|
|
63
|
+
).run!
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Process.wait # Wait for mailer to complete
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
find_string_in_file('From: Request-log-analyzer reporter <customaddr@example.com>', @log_file).should_not be_nil
|
|
68
|
+
end
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
it 'should allow a custom mail sender name' do
|
|
71
|
+
RequestLogAnalyzer::Controller.build(
|
|
72
|
+
mail: 'root@localhost',
|
|
73
|
+
mailhost: 'localhost:2525',
|
|
74
|
+
mailfrom_name: 'Custom Name',
|
|
75
|
+
source_files: log_fixture(:rails_1x),
|
|
76
|
+
format: RequestLogAnalyzer::FileFormat::Rails,
|
|
77
|
+
no_progress: true
|
|
78
|
+
).run!
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
Process.wait # Wait for mailer to complete
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
find_string_in_file('From: Custom Name <contact@railsdoctors.com>', @log_file).should_not be_nil
|
|
83
|
+
end
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
85
|
+
it 'should send html mail' do
|
|
86
|
+
RequestLogAnalyzer::Controller.build(
|
|
87
|
+
output: 'HTML',
|
|
88
|
+
mail: 'root@localhost',
|
|
89
|
+
mailhost: 'localhost:2525',
|
|
90
|
+
source_files: log_fixture(:rails_1x),
|
|
91
|
+
format: RequestLogAnalyzer::FileFormat::Rails,
|
|
92
|
+
no_progress: true
|
|
93
|
+
).run!
|
|
94
|
+
|
|
95
|
+
Process.wait # Wait for mailer to complete
|
|
96
|
+
|
|
97
|
+
find_string_in_file('From: <contact@railsdoctors.com>', @log_file).should_not be_nil
|
|
98
|
+
find_string_in_file('To: <root@localhost>', @log_file).should_not be_nil
|
|
99
|
+
find_string_in_file('From: Request-log-analyzer reporter <contact@railsdoctors.com>', @log_file).should_not be_nil
|
|
100
|
+
find_string_in_file('<h1>Request-log-analyzer summary report</h1>', @log_file).should_not be_nil
|
|
101
|
+
find_string_in_file('<td class="alt">287ms-296ms</td></tr><tr><td>DashboardController#index.html [GET]</td>', @log_file).should_not be_nil
|
|
102
|
+
end
|
|
102
103
|
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
104
|
|
|
105
|
+
# Mailtrap
|
|
106
|
+
# by Matt Mower <self@mattmower.com>
|
|
107
|
+
# http://matt.blogs.it/
|
|
108
|
+
#
|
|
109
|
+
# Included in RLA because original mailtrap puts anoying stuff when called
|
|
110
|
+
# through ruby.
|
|
111
|
+
#
|
|
112
|
+
# Mailtrap creates a TCP server that listens on a specified port for SMTP
|
|
113
|
+
# clients. Accepts the connection and talks just enough of the SMTP protocol
|
|
114
|
+
# for them to deliver a message which it writes to disk.
|
|
115
|
+
#
|
|
116
|
+
class Mailtrap
|
|
117
|
+
VERSION = '0.2.1'
|
|
118
|
+
|
|
119
|
+
# Create a new Mailtrap on the specified host:port. If once it true it
|
|
120
|
+
# will listen for one message then exit. Specify the msgdir where messages
|
|
121
|
+
# are written.
|
|
122
|
+
def initialize(host, port, once, msgfile)
|
|
123
|
+
@host = host
|
|
124
|
+
@port = port
|
|
125
|
+
@once = once
|
|
126
|
+
@msgfile = msgfile
|
|
127
|
+
|
|
128
|
+
File.open(@msgfile, 'a') do |file|
|
|
129
|
+
file.puts "\n* Mailtrap started at #{@host}:#{port}\n"
|
|
130
|
+
end
|
|
106
131
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# http://matt.blogs.it/
|
|
110
|
-
#
|
|
111
|
-
# Included in RLA because original mailtrap puts anoying stuff when called
|
|
112
|
-
# through ruby.
|
|
113
|
-
#
|
|
114
|
-
# Mailtrap creates a TCP server that listens on a specified port for SMTP
|
|
115
|
-
# clients. Accepts the connection and talks just enough of the SMTP protocol
|
|
116
|
-
# for them to deliver a message which it writes to disk.
|
|
117
|
-
#
|
|
118
|
-
class Mailtrap
|
|
119
|
-
VERSION = '0.2.1'
|
|
120
|
-
|
|
121
|
-
# Create a new Mailtrap on the specified host:port. If once it true it
|
|
122
|
-
# will listen for one message then exit. Specify the msgdir where messages
|
|
123
|
-
# are written.
|
|
124
|
-
def initialize( host, port, once, msgfile )
|
|
125
|
-
@host = host
|
|
126
|
-
@port = port
|
|
127
|
-
@once = once
|
|
128
|
-
@msgfile = msgfile
|
|
129
|
-
|
|
130
|
-
File.open( @msgfile, "a" ) do |file|
|
|
131
|
-
file.puts "\n* Mailtrap started at #{@host}:#{port}\n"
|
|
132
|
+
service = TCPServer.new(@host, @port)
|
|
133
|
+
accept(service)
|
|
132
134
|
end
|
|
133
135
|
|
|
134
|
-
|
|
135
|
-
accept(
|
|
136
|
-
|
|
136
|
+
# Service one or more SMTP client connections
|
|
137
|
+
def accept(service)
|
|
138
|
+
while session = service.accept
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
class << session
|
|
141
|
+
def get_line
|
|
142
|
+
line = gets
|
|
143
|
+
line.chomp! unless line.nil?
|
|
144
|
+
line
|
|
145
|
+
end
|
|
146
|
+
end
|
|
141
147
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
line.chomp! unless line.nil?
|
|
146
|
-
line
|
|
148
|
+
begin
|
|
149
|
+
serve(session)
|
|
150
|
+
rescue => e
|
|
147
151
|
end
|
|
148
|
-
end
|
|
149
152
|
|
|
150
|
-
|
|
151
|
-
serve( session )
|
|
152
|
-
rescue Exception => e
|
|
153
|
+
break if @once
|
|
153
154
|
end
|
|
154
|
-
|
|
155
|
-
break if @once
|
|
156
155
|
end
|
|
157
|
-
end
|
|
158
156
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
157
|
+
# Write a plain text dump of the incoming email to a text
|
|
158
|
+
# file. The file will be in the @msgdir folder and will
|
|
159
|
+
# be called smtp0001.msg, smtp0002.msg, and so on.
|
|
160
|
+
def write(from, to_list, message)
|
|
161
|
+
# Strip SMTP commands from To: and From:
|
|
162
|
+
from.gsub!(/MAIL FROM:\s*/, '')
|
|
163
|
+
to_list = to_list.map { |to| to.gsub(/RCPT TO:\s*/, '') }
|
|
164
|
+
|
|
165
|
+
# Append to the end of the messages file
|
|
166
|
+
File.open(@msgfile, 'a') do |file|
|
|
167
|
+
file.puts '* Message begins'
|
|
168
|
+
file.puts "From: #{from}"
|
|
169
|
+
file.puts "To: #{to_list.join(', ')}"
|
|
170
|
+
file.puts 'Body:'
|
|
171
|
+
file.puts message
|
|
172
|
+
file.puts "\n* Message ends"
|
|
173
|
+
end
|
|
176
174
|
end
|
|
177
175
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
connection.puts( "220 #{@host} MailTrap ready ESTMP" )
|
|
184
|
-
helo = connection.get_line # whoever they are
|
|
176
|
+
# Talk pidgeon-SMTP to the client to get them to hand over the message
|
|
177
|
+
# and go away.
|
|
178
|
+
def serve(connection)
|
|
179
|
+
connection.puts("220 #{@host} MailTrap ready ESTMP")
|
|
180
|
+
helo = connection.get_line # whoever they are
|
|
185
181
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
182
|
+
if helo =~ /^EHLO\s+/
|
|
183
|
+
connection.puts "250-#{@host} offers just ONE extension my pretty"
|
|
184
|
+
connection.puts '250 HELP'
|
|
185
|
+
end
|
|
190
186
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
187
|
+
# Accept MAIL FROM:
|
|
188
|
+
from = connection.get_line
|
|
189
|
+
connection.puts('250 OK')
|
|
194
190
|
|
|
195
|
-
|
|
191
|
+
to_list = []
|
|
196
192
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
193
|
+
# Accept RCPT TO: until we see DATA
|
|
194
|
+
loop do
|
|
195
|
+
to = connection.get_line
|
|
196
|
+
break if to.nil?
|
|
201
197
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
198
|
+
if to =~ /^DATA/
|
|
199
|
+
connection.puts('354 Start your message')
|
|
200
|
+
break
|
|
201
|
+
else
|
|
202
|
+
to_list << to
|
|
203
|
+
connection.puts('250 OK')
|
|
204
|
+
end
|
|
208
205
|
end
|
|
209
|
-
end
|
|
210
206
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
207
|
+
# Capture the message body terminated by <CR>.<CR>
|
|
208
|
+
lines = []
|
|
209
|
+
loop do
|
|
210
|
+
line = connection.get_line
|
|
211
|
+
break if line.nil? || line == '.'
|
|
212
|
+
lines << line
|
|
213
|
+
end
|
|
218
214
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
215
|
+
# We expect the client will go away now
|
|
216
|
+
connection.puts('250 OK')
|
|
217
|
+
connection.gets # Quit
|
|
218
|
+
connection.puts '221 Seeya'
|
|
219
|
+
connection.close
|
|
224
220
|
|
|
225
|
-
|
|
221
|
+
write(from, to_list, lines.join("\n"))
|
|
222
|
+
end
|
|
226
223
|
end
|
|
227
|
-
end
|
|
228
224
|
|
|
229
225
|
else
|
|
230
226
|
p 'Skipping mailer integration specs, because of missing Process.fork()'
|