request-log-analyzer 1.5.4 → 1.6.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/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This is a simple command line tool to analyze request log files in various formats to produce a performance report. Its purpose is to find what actions are best candidates for optimization.
4
4
 
5
- * Analyzes Rails request logs, Merb request logs, Apache access logs and more, or parses any other log format you specify.
5
+ * Analyzes log files. Currently supports: Amazon S3, Apache, Delayed::Job, Merb, Mysql, PostgreSQL, Rack, Rails and more.
6
6
  * Combines multiple files and decompresses compressed files, which comes in handy if you are using logrotate.
7
7
  * Uses several metrics, including cumulative request time, mean request time, process blockers, database and rendering time, HTTP methods and statuses, Rails action cache statistics, etc.) (Sample output: http://wiki.github.com/wvanbergen/request-log-analyzer/sample-output)
8
8
  * Low memory footprint and reasonably fast, so it is safe to run on a production server.
@@ -35,5 +35,4 @@ Bergen (willem@railsdoctors.com) or Bart ten Brinke (bart@railsdoctors.com).
35
35
 
36
36
  * Project wiki at GitHub: http://wiki.github.com/wvanbergen/request-log-analyzer
37
37
  * railsdoctors homepage: http://railsdoctors.com
38
- * wvanbergen's blog posts: http://techblog.floorplanner.com/tag/request-log-analyzer
39
- * barttenbrinke's blog posts: http://movesonrails.com/articles/tag/analyzer
38
+ * wvanbergen's blog posts: http://techblog.floorplanner.com/tag/request-log-analyzer
@@ -82,14 +82,13 @@ class RequestLogAnalyzer::Database::Base < ActiveRecord::Base
82
82
  capture[:provides].each { |field, field_type| t.column(field, column_type(field_type)) } if capture[:provides].kind_of?(Hash)
83
83
  end
84
84
  end
85
+
86
+ # Add indices to table for more speedy querying
87
+ database.connection.add_index(self.table_name.to_sym, [:request_id]) # rescue
88
+ database.connection.add_index(self.table_name.to_sym, [:source_id]) # rescue
85
89
  end
86
-
87
- # Add indices to table for more speedy querying
88
- database.connection.add_index(self.table_name.to_sym, [:request_id]) # rescue
89
- database.connection.add_index(self.table_name.to_sym, [:source_id]) # rescue
90
90
  end
91
91
 
92
-
93
92
  # Function to determine the column type for a field
94
93
  # TODO: make more robust / include in file-format definition
95
94
  def self.column_type(type_indicator)
@@ -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
- line.captures << { :name => :bucket_owner, :type => :string } <<
16
- { :name => :bucket, :type => :string } <<
17
- { :name => :timestamp, :type => :timestamp } <<
18
- { :name => :remote_ip, :type => :string } <<
19
- { :name => :requester, :type => :string } <<
20
- { :name => :request_id, :type => :string } <<
21
- { :name => :operation, :type => :string } <<
22
- { :name => :key, :type => :nillable_string } <<
23
- { :name => :request_uri, :type => :string } <<
24
- { :name => :http_status, :type => :integer } <<
25
- { :name => :error_code, :type => :nillable_string } <<
26
- { :name => :bytes_sent, :type => :traffic, :unit => :byte } <<
27
- { :name => :object_size, :type => :traffic, :unit => :byte } <<
28
- { :name => :total_time, :type => :duration, :unit => :msec } <<
29
- { :name => :turnaround_time, :type => :duration, :unit => :msec } <<
30
- { :name => :referer, :type => :referer } <<
31
- { :name => :user_agent, :type => :user_agent }
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
- line.captures << { :name => :job, :type => :string }
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
- line.captures << { :name => :completed_job, :type => :string } <<
17
- { :name => :duration, :type => :duration, :unit => :sec }
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
- line.captures << { :name => :locked_job, :type => :string }
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
- # line.captures << { :name => :total_amount, :type => :integer } <<
40
- # { :name => :mean_duration, :type => :duration, :unit => :sec } <<
41
- # { :name => :failed_amount, :type => :integer }
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
- line.captures << { :name => :timestamp, :type => :timestamp }
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
- line.captures << { :name => :user, :type => :string } <<
19
- { :name => :host, :type => :string } <<
20
- { :name => :ip, :type => :string }
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
- line.captures << { :name => :query_time, :type => :duration, :unit => :sec } <<
28
- { :name => :lock_time, :type => :duration, :unit => :sec } <<
29
- { :name => :rows_sent, :type => :integer } <<
30
- { :name => :rows_examined, :type => :integer }
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.captures << { :name => :database, :type => :string }
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.captures << { :name => :query_fragment, :type => :string }
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
@@ -0,0 +1,68 @@
1
+ module RequestLogAnalyzer::FileFormat
2
+
3
+ class Postgresql < Base
4
+
5
+ extend CommonRegularExpressions
6
+
7
+ line_definition :query do |line|
8
+ line.header = true
9
+ line.teaser = /LOG\: query\:/
10
+ line.regexp = /(#{timestamp('%y-%m-%d %k:%M:%S')})\ LOG: query:\s+(.*)/
11
+
12
+ line.capture(:timestamp).as(:timestamp)
13
+ line.capture(:query_fragment)
14
+ end
15
+
16
+ line_definition :duration do |line|
17
+ line.footer = true
18
+ line.teaser = /duration:/
19
+ line.regexp = /#{timestamp('%y-%m-%d %k:%M:%S')}\ LOG\: duration\: (.*)(\ )sec/
20
+
21
+ line.capture(:query_time).as(:duration, :unit => :sec)
22
+ line.capture(:query).as(:sql) # Hack to gather up fragments
23
+ end
24
+
25
+ line_definition :query_fragment do |line|
26
+ line.regexp = /^(?!.*LOG)\s*(.*)\s*/
27
+ line.capture(:query_fragment)
28
+ end
29
+
30
+ report do |analyze|
31
+ analyze.timespan
32
+ analyze.hourly_spread
33
+ analyze.duration :query_time, :category => :query, :title => 'Query time'
34
+ end
35
+
36
+ class Request < RequestLogAnalyzer::Request
37
+
38
+ def convert_sql(value, definition)
39
+
40
+ # Recreate the full SQL query by joining all the previous parts and this last line
41
+ sql = every(:query_fragment).join("\n") + value
42
+
43
+ # Sanitize an SQL query so that it can be used as a category field.
44
+ # sql.gsub!(/\/\*.*\*\//, '') # remove comments
45
+ sql.gsub!(/\s+/, ' ') # remove excessive whitespace
46
+ sql.gsub!(/"([^"]+)"/, '\1') # remove quotes from field names
47
+ sql.gsub!(/'\d{4}-\d{2}-\d{2}'/, ':date') # replace dates
48
+ sql.gsub!(/'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'/, ':datetime') # replace timestamps
49
+ sql.gsub!(/'[^']*'/, ':string') # replace strings
50
+ sql.gsub!(/\b\d+\b/, ':int') # replace integers
51
+ sql.gsub!(/(:int,)+:int/, ':ints') # replace multiple ints by a list
52
+ sql.gsub!(/(:string,)+:string/, ':strings') # replace multiple strings by a list
53
+
54
+ return sql.lstrip.rstrip
55
+ end
56
+
57
+ def host
58
+ self[:host] == '' || self[:host].nil? ? self[:ip] : self[:host]
59
+ end
60
+
61
+ # Convert the timestamp to an integer
62
+ def convert_timestamp(value, definition)
63
+ all,y,m,d,h,i,s = value.split(/(\d\d)-(\d\d)-(\d\d)\s+(\d?\d):(\d\d):(\d\d)/)
64
+ ('20%s%s%s%s%s%s' % [y,m,d,h.rjust(2, '0'),i,s]).to_i
65
+ end
66
+ end
67
+ end
68
+ end
@@ -119,13 +119,13 @@ module RequestLogAnalyzer::FileFormat
119
119
  { :name => :file, :type => :string }]),
120
120
 
121
121
  :cache_hit => RequestLogAnalyzer::LineDefinition.new(:cache_hit,
122
- :regexp => /Filter chain halted as \[\#<ActionController::Caching::Actions::ActionCacheFilter/),
122
+ :regexp => /Filter chain halted as \[\#<ActionController::Filters::AroundFilter.*\@method=.*(?:Caching::Actions::ActionCacheFilter|action_controller\/caching\/actions\.rb).*\] did_not_yield/),
123
123
 
124
124
  :parameters => RequestLogAnalyzer::LineDefinition.new(:parameters,
125
125
  :teaser => / Parameters:/,
126
126
  :regexp => / Parameters:\s+(\{.*\})/,
127
127
  :captures => [{ :name => :params, :type => :eval }]),
128
-
128
+
129
129
  :rendered => RequestLogAnalyzer::LineDefinition.new(:rendered,
130
130
  :teaser => /Rendered /,
131
131
  :regexp => /Rendered (\w+(?:\/\w+)+) \((\d+\.\d+)ms\)/,
@@ -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
@@ -63,7 +63,7 @@ module RequestLogAnalyzer::FileFormat
63
63
 
64
64
  parsers = all_formats.map { |f| RequestLogAnalyzer::Source::LogParser.new(f, :parse_strategy => 'cautious') }
65
65
 
66
- File.open(file, 'r') do |io|
66
+ File.open(file, 'rb') do |io|
67
67
  while io.lineno < line_count && (line = io.gets)
68
68
  parsers.each { |parser| parser.parse_line(line) }
69
69
  end
@@ -201,7 +201,7 @@ module RequestLogAnalyzer::FileFormat
201
201
 
202
202
  # Specifies a single line defintions.
203
203
  def self.line_definition(name, &block)
204
- @line_definer.send(name, &block)
204
+ @line_definer.define_line(name, &block)
205
205
  end
206
206
 
207
207
  # Specifies multiple line definitions at once using a block
@@ -16,14 +16,31 @@ module RequestLogAnalyzer
16
16
  def initialize_copy(other)
17
17
  @line_definitions = other.line_definitions.dup
18
18
  end
19
-
20
- def method_missing(name, *args, &block)
19
+
20
+ def define_line(name, arg = {}, &block)
21
21
  if block_given?
22
22
  @line_definitions[name] = RequestLogAnalyzer::LineDefinition.define(name, &block)
23
23
  else
24
- @line_definitions[name] = RequestLogAnalyzer::LineDefinition.new(name, args.first)
24
+ @line_definitions[name] = RequestLogAnalyzer::LineDefinition.new(name, arg)
25
25
  end
26
26
  end
27
+
28
+ def method_missing(name, *args, &block)
29
+ define_line(name, args[0], &block)
30
+ end
31
+ end
32
+
33
+ class CaptureDefiner
34
+ attr_accessor :capture_hash
35
+
36
+ def initialize(hash)
37
+ @capture_hash = hash
38
+ end
39
+
40
+ def as(type, type_options = {})
41
+ @capture_hash.merge!(type_options.merge(:type => type))
42
+ return self
43
+ end
27
44
  end
28
45
 
29
46
  attr_reader :name
@@ -47,6 +64,12 @@ module RequestLogAnalyzer
47
64
  yield(definition) if block_given?
48
65
  return definition
49
66
  end
67
+
68
+ def capture(name)
69
+ new_capture_hash = { :name => name, :type => :string}
70
+ captures << new_capture_hash
71
+ CaptureDefiner.new(new_capture_hash)
72
+ end
50
73
 
51
74
  # Checks whether a given line matches this definition.
52
75
  # It will return false if a line does not match. If the line matches, a hash is returned
@@ -66,6 +89,8 @@ module RequestLogAnalyzer
66
89
  else
67
90
  return false
68
91
  end
92
+ rescue
93
+ return false
69
94
  end
70
95
 
71
96
  alias :=~ :matches
@@ -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
@@ -38,7 +38,7 @@ module RequestLogAnalyzer::Output
38
38
  foreground_color = "3#{COLORS[option]}" if COLORS.include?(option)
39
39
  font_style = "#{STYLES[option]};" if STYLES.include?(option)
40
40
  elsif option.kind_of?(Hash)
41
- options.each do |key, value|
41
+ option.each do |key, value|
42
42
  case key
43
43
  when :color; foreground_color = "3#{COLORS[value]}" if COLORS.include?(value)
44
44
  when :background; background_color = "4#{COLORS[value]};" if COLORS.include?(value)
@@ -109,12 +109,12 @@ module RequestLogAnalyzer::Source
109
109
  @progress_handler = @dormant_progress_handler
110
110
  @progress_handler.call(:started, file) if @progress_handler
111
111
 
112
- File.open(file, 'r') { |f| parse_io(f, options, &block) }
112
+ File.open(file, 'rb') { |f| parse_io(f, options, &block) }
113
113
 
114
114
  @progress_handler.call(:finished, file) if @progress_handler
115
115
  @progress_handler = nil
116
116
  else
117
- IO.popen(decompress_file?(file), 'r') { |f| parse_io(f, options, &block) }
117
+ IO.popen(decompress_file?(file), 'rb') { |f| parse_io(f, options, &block) }
118
118
  end
119
119
 
120
120
  @source_changes_handler.call(:finished, @current_source) if @source_changes_handler
@@ -71,7 +71,7 @@ module RequestLogAnalyzer::Tracker
71
71
  return "- " if value.nil?
72
72
  return "0 " if value.zero?
73
73
 
74
- case Math.log10(value).floor
74
+ case [Math.log10(value.abs).floor, 0].max
75
75
  when 0...4 then '%d ' % value
76
76
  when 4...7 then '%dk' % (value / 1000)
77
77
  when 7...10 then '%dM' % (value / 1000_000)
@@ -23,7 +23,7 @@ module RequestLogAnalyzer::Tracker
23
23
  return "-" if bytes.nil?
24
24
  return "0 B" if bytes.zero?
25
25
 
26
- case Math.log10(bytes).floor
26
+ case [Math.log10(bytes.abs).floor, 0].max
27
27
  when 0...4 then '%d B' % bytes
28
28
  when 4...7 then '%d kB' % (bytes / 1000)
29
29
  when 7...10 then '%d MB' % (bytes / 1000_000)
@@ -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.5.4"
14
+ VERSION = "1.6.4"
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.5.4"
6
- s.date = "2009-12-17"
5
+ s.version = "1.6.4"
6
+ s.date = "2010-03-22"
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 .gitignore spec/unit/filter/filter_spec.rb 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 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/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 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/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/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 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 spec/unit/tracker/numeric_value_tracker_spec.rb lib/request_log_analyzer/tracker/timespan.rb spec/unit/controller/log_processor_spec.rb spec/fixtures/sinatra.log 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)
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/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/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/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