request-log-analyzer 1.4.0 → 1.5.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/LICENSE +1 -1
- data/README.rdoc +19 -24
- data/bin/request-log-analyzer +10 -7
- data/lib/request_log_analyzer/aggregator/summarizer.rb +13 -2
- data/lib/request_log_analyzer/controller.rb +68 -36
- data/lib/request_log_analyzer/file_format/apache.rb +1 -1
- data/lib/request_log_analyzer/file_format/mysql.rb +93 -0
- data/lib/request_log_analyzer/file_format/rails_development.rb +1 -1
- data/lib/request_log_analyzer/file_format.rb +46 -2
- data/lib/request_log_analyzer/mailer.rb +25 -12
- data/lib/request_log_analyzer/output/fixed_width.rb +1 -1
- data/lib/request_log_analyzer/output/html.rb +2 -0
- data/lib/request_log_analyzer/request.rb +5 -0
- data/lib/request_log_analyzer/source/log_parser.rb +33 -10
- data/lib/request_log_analyzer/tracker/count.rb +93 -0
- data/lib/request_log_analyzer.rb +1 -1
- data/request-log-analyzer.gemspec +6 -6
- data/spec/fixtures/mysql_slow_query.log +110 -0
- data/spec/integration/command_line_usage_spec.rb +3 -3
- data/spec/integration/mailer_spec.rb +179 -0
- data/spec/integration/munin_plugins_rails_spec.rb +58 -0
- data/spec/integration/scout_spec.rb +152 -0
- data/spec/lib/helpers.rb +26 -1
- data/spec/lib/mocks.rb +3 -1
- data/spec/unit/file_format/apache_format_spec.rb +102 -95
- data/spec/unit/file_format/format_autodetection_spec.rb +35 -0
- data/spec/unit/file_format/mysql_format_spec.rb +155 -0
- data/spec/unit/file_format/rails_format_spec.rb +9 -12
- data/spec/unit/mailer_spec.rb +12 -0
- data/spec/unit/tracker/count_tracker_spec.rb +123 -0
- data/spec/unit/tracker/tracker_api_spec.rb +1 -1
- metadata +125 -110
|
@@ -20,6 +20,7 @@ module RequestLogAnalyzer::Source
|
|
|
20
20
|
PARSE_STRATEGIES = ['cautious', 'assume-correct']
|
|
21
21
|
|
|
22
22
|
attr_reader :source_files, :current_file, :current_lineno
|
|
23
|
+
attr_reader :warnings, :parsed_lines, :parsed_requests, :skipped_lines, :skipped_requests
|
|
23
24
|
|
|
24
25
|
# Initializes the log file parser instance.
|
|
25
26
|
# It will apply the language specific FileFormat module to this instance. It will use the line
|
|
@@ -29,6 +30,7 @@ module RequestLogAnalyzer::Source
|
|
|
29
30
|
# <tt>options</tt>:: A hash of options that are used by the parser
|
|
30
31
|
def initialize(format, options = {})
|
|
31
32
|
super(format, options)
|
|
33
|
+
@warnings = 0
|
|
32
34
|
@parsed_lines = 0
|
|
33
35
|
@parsed_requests = 0
|
|
34
36
|
@skipped_lines = 0
|
|
@@ -142,21 +144,27 @@ module RequestLogAnalyzer::Source
|
|
|
142
144
|
# <tt>io</tt>:: The IO instance to use as source
|
|
143
145
|
# <tt>options</tt>:: A hash of options that can be used by the parser.
|
|
144
146
|
def parse_io(io, options = {}, &block) # :yields: request
|
|
145
|
-
@current_lineno =
|
|
147
|
+
@current_lineno = 0
|
|
146
148
|
while line = io.gets
|
|
147
|
-
@progress_handler.call(:progress, io.pos) if @progress_handler && @current_lineno % 255 == 0
|
|
148
|
-
|
|
149
|
-
if request_data = file_format.parse_line(line) { |wt, message| warn(wt, message) }
|
|
150
|
-
@parsed_lines += 1
|
|
151
|
-
update_current_request(request_data.merge(:source => @current_source, :lineno => @current_lineno), &block)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
149
|
@current_lineno += 1
|
|
150
|
+
@progress_handler.call(:progress, io.pos) if @progress_handler && @current_lineno % 255 == 0
|
|
151
|
+
parse_line(line, &block)
|
|
155
152
|
end
|
|
156
153
|
|
|
157
154
|
warn(:unfinished_request_on_eof, "End of file reached, but last request was not completed!") unless @current_request.nil?
|
|
158
155
|
@current_lineno = nil
|
|
159
156
|
end
|
|
157
|
+
|
|
158
|
+
# Parses a single line using the current file format. If successful, use the parsed
|
|
159
|
+
# information to build a request
|
|
160
|
+
# <tt>line</tt>:: The line to parse
|
|
161
|
+
# <tt>block</tt>:: The block to send fully parsed requests to.
|
|
162
|
+
def parse_line(line, &block) # :yields: request
|
|
163
|
+
if request_data = file_format.parse_line(line) { |wt, message| warn(wt, message) }
|
|
164
|
+
@parsed_lines += 1
|
|
165
|
+
update_current_request(request_data.merge(:source => @current_source, :lineno => @current_lineno), &block)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
160
168
|
|
|
161
169
|
# Add a block to this method to install a progress handler while parsing.
|
|
162
170
|
# <tt>proc</tt>:: The proc that will be called to handle progress update messages
|
|
@@ -186,6 +194,7 @@ module RequestLogAnalyzer::Source
|
|
|
186
194
|
# <tt>type</tt>:: The warning type (a Symbol)
|
|
187
195
|
# <tt>message</tt>:: A message explaining the warning
|
|
188
196
|
def warn(type, message)
|
|
197
|
+
@warnings += 1
|
|
189
198
|
@warning_handler.call(type, message, @current_lineno) if @warning_handler
|
|
190
199
|
end
|
|
191
200
|
|
|
@@ -214,7 +223,13 @@ module RequestLogAnalyzer::Source
|
|
|
214
223
|
#
|
|
215
224
|
# <tt>request_data</tt>:: A hash of data that was parsed from the last line.
|
|
216
225
|
def update_current_request(request_data, &block) # :yields: request
|
|
217
|
-
if
|
|
226
|
+
if alternative_header_line?(request_data)
|
|
227
|
+
if @current_request
|
|
228
|
+
@current_request << request_data
|
|
229
|
+
else
|
|
230
|
+
@current_request = @file_format.request(request_data)
|
|
231
|
+
end
|
|
232
|
+
elsif header_line?(request_data)
|
|
218
233
|
if @current_request
|
|
219
234
|
case options[:parse_strategy]
|
|
220
235
|
when 'assume-correct'
|
|
@@ -258,10 +273,18 @@ module RequestLogAnalyzer::Source
|
|
|
258
273
|
@skipped_requests += 1 unless accepted
|
|
259
274
|
end
|
|
260
275
|
|
|
276
|
+
|
|
277
|
+
# Checks whether a given line hash is an alternative header line according to the current file format.
|
|
278
|
+
# <tt>hash</tt>:: A hash of data that was parsed from the line.
|
|
279
|
+
def alternative_header_line?(hash)
|
|
280
|
+
hash[:line_definition].header == :alternative
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
|
|
261
284
|
# Checks whether a given line hash is a header line according to the current file format.
|
|
262
285
|
# <tt>hash</tt>:: A hash of data that was parsed from the line.
|
|
263
286
|
def header_line?(hash)
|
|
264
|
-
hash[:line_definition].header
|
|
287
|
+
hash[:line_definition].header == true
|
|
265
288
|
end
|
|
266
289
|
|
|
267
290
|
# Checks whether a given line hash is a footer line according to the current file format.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module RequestLogAnalyzer::Tracker
|
|
2
|
+
|
|
3
|
+
# Get highest count of a specific attribute
|
|
4
|
+
class Count < Base
|
|
5
|
+
|
|
6
|
+
include RequestLogAnalyzer::Tracker::StatisticsTracking
|
|
7
|
+
|
|
8
|
+
attr_reader :categories
|
|
9
|
+
|
|
10
|
+
def prepare
|
|
11
|
+
raise "No categorizer set up for category tracker #{self.inspect}" unless options[:category]
|
|
12
|
+
raise "No field to count has been set up #{self.inspect}" unless options[:field]
|
|
13
|
+
|
|
14
|
+
@categorizer = create_lambda(options[:category])
|
|
15
|
+
@counter = create_lambda(options[:field])
|
|
16
|
+
@categories = {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get the duration information fron the request and store it in the different categories.
|
|
20
|
+
# <tt>request</tt> The request.
|
|
21
|
+
def update(request)
|
|
22
|
+
category = @categorizer.call(request)
|
|
23
|
+
count = @counter.call(request)
|
|
24
|
+
update_statistics(category, count) if count.kind_of?(Numeric) && !category.nil?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def report(output)
|
|
28
|
+
sortings = output.options[:sort] || [:sum, :mean]
|
|
29
|
+
|
|
30
|
+
sortings.each do |report|
|
|
31
|
+
case report
|
|
32
|
+
when :mean
|
|
33
|
+
report_table(output, :mean, :title => "#{title} - sorted by mean")
|
|
34
|
+
when :stddev
|
|
35
|
+
report_table(output, :stddev, :title => "#{title} - sorted by standard deviation")
|
|
36
|
+
when :sum
|
|
37
|
+
report_table(output, :sum, :title => "#{title} - sorted by sum")
|
|
38
|
+
when :hits
|
|
39
|
+
report_table(output, :hits, :title => "#{title} - sorted by hits")
|
|
40
|
+
else
|
|
41
|
+
raise "Unknown duration report specified: #{report}!"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Block function to build a result table using a provided sorting function.
|
|
47
|
+
# <tt>output</tt> The output object.
|
|
48
|
+
# <tt>amount</tt> The number of rows in the report table (default 10).
|
|
49
|
+
# === Options
|
|
50
|
+
# * </tt>:title</tt> The title of the table
|
|
51
|
+
# * </tt>:sort</tt> The key to sort on (:hits, :cumulative, :average, :min or :max)
|
|
52
|
+
def report_table(output, sort, options = {}, &block)
|
|
53
|
+
output.puts
|
|
54
|
+
|
|
55
|
+
top_categories = output.slice_results(sorted_by(sort))
|
|
56
|
+
output.with_style(:top_line => true) do
|
|
57
|
+
output.table(*statistics_header(:title => options[:title],:highlight => sort)) do |rows|
|
|
58
|
+
top_categories.each { |(cat, info)| rows.push(statistics_row(cat)) }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
output.puts
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Format an int to a nice string with decimal seperation.
|
|
65
|
+
# Also see http://en.wikipedia.org/wiki/Terabyte
|
|
66
|
+
# <tt>count</tt> the value to reduce
|
|
67
|
+
def display_value(count)
|
|
68
|
+
return "- " if count.nil?
|
|
69
|
+
return "0 " if count.zero?
|
|
70
|
+
|
|
71
|
+
case Math.log10(count).floor
|
|
72
|
+
when 1...4 then '%d ' % count
|
|
73
|
+
when 4...7 then '%dk' % (count / 1000)
|
|
74
|
+
when 7...10 then '%dM' % (count / 1000_000)
|
|
75
|
+
when 10...13 then '%dG' % (count / 1000_000_000)
|
|
76
|
+
when 13...16 then '%dT' % (count / 1000_000_000_000)
|
|
77
|
+
else '%dP' % (count / 1000_000_000_000_000)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns the title of this tracker for reports
|
|
83
|
+
def title
|
|
84
|
+
options[:title] || 'Total'
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns all the categories and the tracked duration as a hash than can be exported to YAML
|
|
88
|
+
def to_yaml_object
|
|
89
|
+
return nil if @categories.empty?
|
|
90
|
+
@categories
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
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.
|
|
14
|
+
VERSION = "1.5.0"
|
|
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.
|
|
@@ -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
|
-
s.date = "2009-
|
|
5
|
+
s.version = "1.5.0"
|
|
6
|
+
s.date = "2009-11-18"
|
|
7
7
|
|
|
8
8
|
s.rubyforge_project = 'r-l-a'
|
|
9
9
|
|
|
@@ -26,8 +26,8 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
|
|
27
27
|
s.requirements << "To use the database inserter, ActiveRecord and an appropriate database adapter are required."
|
|
28
28
|
|
|
29
|
-
s.add_development_dependency('rspec',
|
|
30
|
-
s.add_development_dependency('git',
|
|
29
|
+
s.add_development_dependency('rspec', '>= 1.2.4')
|
|
30
|
+
s.add_development_dependency('git', '>= 1.1.0')
|
|
31
31
|
|
|
32
32
|
s.authors = ['Willem van Bergen', 'Bart ten Brinke']
|
|
33
33
|
s.email = ['willem@railsdoctors.com', 'bart@railsdoctors.com']
|
|
@@ -35,6 +35,6 @@ Gem::Specification.new do |s|
|
|
|
35
35
|
|
|
36
36
|
# The files and test_files directives are set automatically by the release script.
|
|
37
37
|
# Do not change them by hand, but make sure to add the files to the git repository.
|
|
38
|
-
s.files = %w(spec/unit/
|
|
39
|
-
s.test_files = %w(spec/unit/
|
|
38
|
+
s.files = %w(lib/request_log_analyzer/output/html.rb spec/unit/tracker/hourly_spread_spec.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/fixtures/decompression.log.gz lib/request_log_analyzer/tracker/frequency.rb lib/request_log_analyzer/tracker/duration.rb tasks/github-gem.rake .gitignore spec/unit/filter/filter_spec.rb spec/lib/macros.rb spec/spec_helper.rb spec/unit/tracker/count_tracker_spec.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 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/filter/timespan_filter_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/multiple_files_2.log spec/lib/mocks.rb spec/unit/file_format/apache_format_spec.rb spec/fixtures/syslog_1x.log spec/integration/munin_plugins_rails_spec.rb spec/lib/helpers.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 spec/fixtures/test_language_combined.log lib/cli/command_line_arguments.rb lib/request_log_analyzer.rb spec/database.yml spec/unit/request_spec.rb lib/request_log_analyzer/database/base.rb spec/unit/aggregator/database_inserter_spec.rb lib/request_log_analyzer/database/request.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/fixtures/rails_22_cached.log lib/request_log_analyzer/aggregator/summarizer.rb spec/unit/tracker/duration_tracker_spec.rb spec/fixtures/rails_1x.log lib/request_log_analyzer/tracker/count.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 lib/request_log_analyzer/file_format/rails.rb Rakefile spec/unit/mailer_spec.rb lib/request_log_analyzer/tracker/hourly_spread.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/traffic_tracker_spec.rb lib/request_log_analyzer/tracker/timespan.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/field_filter_spec.rb 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)
|
|
39
|
+
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/filter/filter_spec.rb spec/unit/tracker/count_tracker_spec.rb spec/unit/database/connection_spec.rb spec/integration/scout_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/filter/timespan_filter_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/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/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/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)
|
|
40
40
|
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
2
|
+
# Time: 091112 18:13:56
|
|
3
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
4
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
5
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
6
|
+
# Time: 091112 18:14:07
|
|
7
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
8
|
+
# Query_time: 9 Lock_time: 0 Rows_sent: 258841 Rows_examined: 258841
|
|
9
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `sessions`;
|
|
10
|
+
# Time: 091112 18:14:44
|
|
11
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
12
|
+
# Query_time: 6 Lock_time: 0 Rows_sent: 603732 Rows_examined: 603732
|
|
13
|
+
use sensire_s;
|
|
14
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
15
|
+
# Time: 091112 18:14:56
|
|
16
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
17
|
+
# Query_time: 12 Lock_time: 0 Rows_sent: 1068438 Rows_examined: 1068438
|
|
18
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
19
|
+
# Time: 091112 18:16:18
|
|
20
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
21
|
+
# Query_time: 17 Lock_time: 0 Rows_sent: 1822689 Rows_examined: 1822689
|
|
22
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
23
|
+
# Time: 091112 18:16:28
|
|
24
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
25
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 1113903 Rows_examined: 1113903
|
|
26
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
27
|
+
# Time: 091112 18:17:37
|
|
28
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
29
|
+
# Query_time: 19 Lock_time: 0 Rows_sent: 1631168 Rows_examined: 1631168
|
|
30
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
31
|
+
# Time: 091112 18:17:49
|
|
32
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
33
|
+
# Query_time: 11 Lock_time: 0 Rows_sent: 951103 Rows_examined: 951103
|
|
34
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
35
|
+
# Time: 091112 18:19:31
|
|
36
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
37
|
+
# Query_time: 7 Lock_time: 0 Rows_sent: 747129 Rows_examined: 747129
|
|
38
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
39
|
+
# Time: 091112 18:19:49
|
|
40
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
41
|
+
# Query_time: 17 Lock_time: 0 Rows_sent: 1904679 Rows_examined: 1904679
|
|
42
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
43
|
+
# Time: 091112 18:21:34
|
|
44
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
45
|
+
# Query_time: 59 Lock_time: 0 Rows_sent: 5013829 Rows_examined: 5013829
|
|
46
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
47
|
+
# Time: 091112 18:21:54
|
|
48
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
49
|
+
# Query_time: 20 Lock_time: 0 Rows_sent: 1634467 Rows_examined: 1634467
|
|
50
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
51
|
+
# Time: 091112 18:22:58
|
|
52
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
53
|
+
# Query_time: 5 Lock_time: 0 Rows_sent: 634683 Rows_examined: 634683
|
|
54
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
55
|
+
# Time: 091112 18:23:58
|
|
56
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
57
|
+
# Query_time: 5 Lock_time: 0 Rows_sent: 444697 Rows_examined: 444697
|
|
58
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
59
|
+
# Time: 091112 18:24:34
|
|
60
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
61
|
+
# Query_time: 7 Lock_time: 0 Rows_sent: 669623 Rows_examined: 669623
|
|
62
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
63
|
+
# Time: 091112 18:26:18
|
|
64
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
65
|
+
# Query_time: 27 Lock_time: 0 Rows_sent: 2727395 Rows_examined: 2727395
|
|
66
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
67
|
+
# Time: 091112 18:26:28
|
|
68
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
69
|
+
# Query_time: 10 Lock_time: 0 Rows_sent: 859164 Rows_examined: 859164
|
|
70
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
71
|
+
# Time: 091112 18:27:50
|
|
72
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
73
|
+
# Query_time: 29 Lock_time: 0 Rows_sent: 2607634 Rows_examined: 2607634
|
|
74
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
75
|
+
# Time: 091112 18:27:59
|
|
76
|
+
# User@Host: admin[admin] @ db1 [10.0.0.1]
|
|
77
|
+
# Query_time: 9 Lock_time: 0 Rows_sent: 766241 Rows_examined: 766241
|
|
78
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
79
|
+
# Time: 091112 18:30:39
|
|
80
|
+
# User@Host: user_1[user_1] @ rails1 [10.0.1.3]
|
|
81
|
+
# Query_time: 6 Lock_time: 0 Rows_sent: 0 Rows_examined: 1648536
|
|
82
|
+
SELECT * FROM `clients` WHERE (1=1
|
|
83
|
+
AND clients.valid_from < '2009-12-05' AND (clients.valid_to IS NULL or clients.valid_to > '2009-11-20')
|
|
84
|
+
AND clients.index > 0
|
|
85
|
+
) AND (clients.deleted_at IS NULL);
|
|
86
|
+
# Time: 091112 20:15:16
|
|
87
|
+
# User@Host: user_2[user_2] @ rails1 [10.0.1.3]
|
|
88
|
+
# Query_time: 7 Lock_time: 0 Rows_sent: 796074 Rows_examined: 796074
|
|
89
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
90
|
+
# Time: 091112 20:15:29
|
|
91
|
+
# User@Host: user_2[user_2] @ rails1 [10.0.1.3]
|
|
92
|
+
# Query_time: 12 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
|
|
93
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
94
|
+
# Time: 091112 20:15:45
|
|
95
|
+
# User@Host: user_2[user_2] @ rails1 [10.0.1.3]
|
|
96
|
+
# Query_time: 12 Lock_time: 0 Rows_sent: 259350 Rows_examined: 259350
|
|
97
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `sessions`;
|
|
98
|
+
# Time: 091112 20:18:50
|
|
99
|
+
# User@Host: user_1[user_1] @ rails1 [10.0.1.3]
|
|
100
|
+
# Query_time: 28 Lock_time: 0 Rows_sent: 2727404 Rows_examined: 2727404
|
|
101
|
+
use zuwe_p;
|
|
102
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
|
|
103
|
+
# Time: 091112 20:19:18
|
|
104
|
+
# User@Host: user_1[user_1] @ rails1 [10.0.1.3]
|
|
105
|
+
# Query_time: 28 Lock_time: 0 Rows_sent: 859164 Rows_examined: 859164
|
|
106
|
+
SELECT /*!40001 SQL_NO_CACHE */ * FROM `events`;
|
|
107
|
+
# Time: 091112 20:19:40
|
|
108
|
+
# User@Host: user_1[user_1] @ db1 [10.1.1.178]
|
|
109
|
+
# Query_time: 6 Lock_time: 0 Rows_sent: 33 Rows_examined: 1648542
|
|
110
|
+
SELECT * FROM `clients` WHERE (valid_to IS NULL OR valid_to > '2009-12-12') AND ((`clients`.`deleted` = 1) AND (clients.deleted_at IS NULL));
|
|
@@ -72,9 +72,9 @@ describe RequestLogAnalyzer, 'running from command line' do
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
it "should dump the results to a YAML file" do
|
|
75
|
-
run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:
|
|
76
|
-
File.exist?(temp_output_file(:
|
|
77
|
-
YAML::load(File.read(temp_output_file(:
|
|
75
|
+
run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:yaml)}")
|
|
76
|
+
File.exist?(temp_output_file(:yaml)).should be_true
|
|
77
|
+
YAML::load(File.read(temp_output_file(:yaml))).should have_at_least(1).item
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
it "should parse 4 requests from the standard input" do
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
|
2
|
+
require 'socket'
|
|
3
|
+
|
|
4
|
+
describe RequestLogAnalyzer, 'running mailer integration' do
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
@log_file = temp_output_file('mailtrap.log')
|
|
8
|
+
|
|
9
|
+
Process.fork {
|
|
10
|
+
Mailtrap.new('localhost', 2525, true, @log_file)
|
|
11
|
+
Process.exit! # Do not call rspec after exit hook!
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
after(:each) do
|
|
16
|
+
cleanup_temp_files!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should send plaintext mail" do
|
|
20
|
+
RequestLogAnalyzer::Controller.build(
|
|
21
|
+
:mail => 'root@localhost',
|
|
22
|
+
:mailhost => 'localhost:2525',
|
|
23
|
+
:source_files => log_fixture(:rails_1x),
|
|
24
|
+
:format => RequestLogAnalyzer::FileFormat::Rails,
|
|
25
|
+
:no_progress => true
|
|
26
|
+
).run!
|
|
27
|
+
|
|
28
|
+
Process.wait # Wait for mailer to complete
|
|
29
|
+
|
|
30
|
+
find_string_in_file("From: <contact@railsdoctors.com>", @log_file).should_not be_nil
|
|
31
|
+
find_string_in_file("To: <root@localhost>", @log_file).should_not be_nil
|
|
32
|
+
find_string_in_file("From: Request-log-analyzer reporter <contact@railsdoctors.com>", @log_file).should_not be_nil
|
|
33
|
+
find_string_in_file("Request summary", @log_file).should_not be_nil
|
|
34
|
+
find_string_in_file("PeopleController#show.html [ | 1 | 0.29s | 0.29s | 0.00s | 0.29s | 0.29s", @log_file).should_not be_nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should send html mail" do
|
|
38
|
+
RequestLogAnalyzer::Controller.build(
|
|
39
|
+
:output => 'HTML',
|
|
40
|
+
:mail => 'root@localhost',
|
|
41
|
+
:mailhost => 'localhost:2525',
|
|
42
|
+
:source_files => log_fixture(:rails_1x),
|
|
43
|
+
:format => RequestLogAnalyzer::FileFormat::Rails,
|
|
44
|
+
:no_progress => true
|
|
45
|
+
).run!
|
|
46
|
+
|
|
47
|
+
Process.wait # Wait for mailer to complete
|
|
48
|
+
|
|
49
|
+
find_string_in_file("From: <contact@railsdoctors.com>", @log_file).should_not be_nil
|
|
50
|
+
find_string_in_file("To: <root@localhost>", @log_file).should_not be_nil
|
|
51
|
+
find_string_in_file("From: Request-log-analyzer reporter <contact@railsdoctors.com>", @log_file).should_not be_nil
|
|
52
|
+
find_string_in_file('<h1>Request-log-analyzer summary report</h1>', @log_file).should_not be_nil
|
|
53
|
+
find_string_in_file('<td class="alt">0.29s</td></tr><tr><td>DashboardController#index.html [GET]</td>', @log_file).should_not be_nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Mailtrap
|
|
60
|
+
# by Matt Mower <self@mattmower.com>
|
|
61
|
+
# http://matt.blogs.it/
|
|
62
|
+
#
|
|
63
|
+
# Included in RLA because original mailtrap puts anoying stuff when called
|
|
64
|
+
# through ruby.
|
|
65
|
+
#
|
|
66
|
+
# Mailtrap creates a TCP server that listens on a specified port for SMTP
|
|
67
|
+
# clients. Accepts the connection and talks just enough of the SMTP protocol
|
|
68
|
+
# for them to deliver a message which it writes to disk.
|
|
69
|
+
#
|
|
70
|
+
class Mailtrap
|
|
71
|
+
VERSION = '0.2.1'
|
|
72
|
+
|
|
73
|
+
# Create a new Mailtrap on the specified host:port. If once it true it
|
|
74
|
+
# will listen for one message then exit. Specify the msgdir where messages
|
|
75
|
+
# are written.
|
|
76
|
+
def initialize( host, port, once, msgfile )
|
|
77
|
+
@host = host
|
|
78
|
+
@port = port
|
|
79
|
+
@once = once
|
|
80
|
+
@msgfile = msgfile
|
|
81
|
+
|
|
82
|
+
File.open( @msgfile, "a" ) do |file|
|
|
83
|
+
file.puts "\n* Mailtrap started at #{@host}:#{port}\n"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
service = TCPServer.new( @host, @port )
|
|
87
|
+
accept( service )
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Service one or more SMTP client connections
|
|
91
|
+
def accept( service )
|
|
92
|
+
while session = service.accept
|
|
93
|
+
|
|
94
|
+
class << session
|
|
95
|
+
def get_line
|
|
96
|
+
line = gets
|
|
97
|
+
line.chomp! unless line.nil?
|
|
98
|
+
line
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
begin
|
|
103
|
+
serve( session )
|
|
104
|
+
rescue Exception => e
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
break if @once
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Write a plain text dump of the incoming email to a text
|
|
112
|
+
# file. The file will be in the @msgdir folder and will
|
|
113
|
+
# be called smtp0001.msg, smtp0002.msg, and so on.
|
|
114
|
+
def write( from, to_list, message )
|
|
115
|
+
|
|
116
|
+
# Strip SMTP commands from To: and From:
|
|
117
|
+
from.gsub!( /MAIL FROM:\s*/, "" )
|
|
118
|
+
to_list = to_list.map { |to| to.gsub( /RCPT TO:\s*/, "" ) }
|
|
119
|
+
|
|
120
|
+
# Append to the end of the messages file
|
|
121
|
+
File.open( @msgfile, "a" ) do |file|
|
|
122
|
+
file.puts "* Message begins"
|
|
123
|
+
file.puts "From: #{from}"
|
|
124
|
+
file.puts "To: #{to_list.join(", ")}"
|
|
125
|
+
file.puts "Body:"
|
|
126
|
+
file.puts message
|
|
127
|
+
file.puts "\n* Message ends"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Talk pidgeon-SMTP to the client to get them to hand over the message
|
|
133
|
+
# and go away.
|
|
134
|
+
def serve( connection )
|
|
135
|
+
connection.puts( "220 #{@host} MailTrap ready ESTMP" )
|
|
136
|
+
helo = connection.get_line # whoever they are
|
|
137
|
+
|
|
138
|
+
if helo =~ /^EHLO\s+/
|
|
139
|
+
connection.puts "250-#{@host} offers just ONE extension my pretty"
|
|
140
|
+
connection.puts "250 HELP"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Accept MAIL FROM:
|
|
144
|
+
from = connection.get_line
|
|
145
|
+
connection.puts( "250 OK" )
|
|
146
|
+
|
|
147
|
+
to_list = []
|
|
148
|
+
|
|
149
|
+
# Accept RCPT TO: until we see DATA
|
|
150
|
+
loop do
|
|
151
|
+
to = connection.get_line
|
|
152
|
+
break if to.nil?
|
|
153
|
+
|
|
154
|
+
if to =~ /^DATA/
|
|
155
|
+
connection.puts( "354 Start your message" )
|
|
156
|
+
break
|
|
157
|
+
else
|
|
158
|
+
to_list << to
|
|
159
|
+
connection.puts( "250 OK" )
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Capture the message body terminated by <CR>.<CR>
|
|
164
|
+
lines = []
|
|
165
|
+
loop do
|
|
166
|
+
line = connection.get_line
|
|
167
|
+
break if line.nil? || line == "."
|
|
168
|
+
lines << line
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# We expect the client will go away now
|
|
172
|
+
connection.puts( "250 OK" )
|
|
173
|
+
connection.gets # Quit
|
|
174
|
+
connection.puts "221 Seeya"
|
|
175
|
+
connection.close
|
|
176
|
+
|
|
177
|
+
write( from, to_list, lines.join( "\n" ) )
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
describe RequestLogAnalyzer, 'when harvesting like munin-plugins-rails the YAML output' do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
cleanup_temp_files!
|
|
7
|
+
run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:yaml)}")
|
|
8
|
+
@rla = YAML::load(File.read(temp_output_file(:yaml)))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after(:each) do
|
|
12
|
+
cleanup_temp_files!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should contain database times" do
|
|
16
|
+
@rla["Database time"].each do |item|
|
|
17
|
+
item[1][:min].should_not be_nil
|
|
18
|
+
item[1][:max].should_not be_nil
|
|
19
|
+
item[1][:hits].should_not be_nil
|
|
20
|
+
item[1][:sum].should_not be_nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should contain request times" do
|
|
25
|
+
@rla["Request duration"].each do |item|
|
|
26
|
+
item[1][:min].should_not be_nil
|
|
27
|
+
item[1][:max].should_not be_nil
|
|
28
|
+
item[1][:hits].should_not be_nil
|
|
29
|
+
item[1][:sum].should_not be_nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should contain failed requests" do
|
|
34
|
+
@rla.keys.should include("Failed requests")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should contain Process blockers" do
|
|
38
|
+
@rla.keys.should include("Process blockers (> 1 sec duration)")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should contain HTTP Methods" do
|
|
42
|
+
@rla["HTTP methods"]["GET"].should_not be_nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should contain HTTP Methods" do
|
|
46
|
+
@rla["HTTP methods"]["GET"].should_not be_nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should contain view rendering times" do
|
|
50
|
+
@rla["View rendering time"].each do |item|
|
|
51
|
+
item[1][:min].should_not be_nil
|
|
52
|
+
item[1][:max].should_not be_nil
|
|
53
|
+
item[1][:hits].should_not be_nil
|
|
54
|
+
item[1][:sum].should_not be_nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|