request-log-analyzer 1.0.2 → 1.6.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.
Files changed (144) hide show
  1. data/.gitignore +10 -0
  2. data/DESIGN.rdoc +41 -0
  3. data/LICENSE +4 -4
  4. data/README.rdoc +38 -0
  5. data/Rakefile +6 -3
  6. data/bin/request-log-analyzer +70 -72
  7. data/lib/cli/command_line_arguments.rb +53 -53
  8. data/lib/cli/database_console.rb +26 -0
  9. data/lib/cli/database_console_init.rb +43 -0
  10. data/lib/cli/progressbar.rb +166 -189
  11. data/lib/cli/tools.rb +49 -0
  12. data/lib/request_log_analyzer/aggregator/database_inserter.rb +83 -0
  13. data/lib/request_log_analyzer/aggregator/echo.rb +17 -12
  14. data/lib/request_log_analyzer/aggregator/summarizer.rb +101 -63
  15. data/lib/request_log_analyzer/{aggregator/base.rb → aggregator.rb} +17 -13
  16. data/lib/request_log_analyzer/controller.rb +251 -98
  17. data/lib/request_log_analyzer/database/base.rb +114 -0
  18. data/lib/request_log_analyzer/database/connection.rb +38 -0
  19. data/lib/request_log_analyzer/database/request.rb +22 -0
  20. data/lib/request_log_analyzer/database/source.rb +13 -0
  21. data/lib/request_log_analyzer/database/warning.rb +14 -0
  22. data/lib/request_log_analyzer/database.rb +102 -0
  23. data/lib/request_log_analyzer/file_format/amazon_s3.rb +74 -0
  24. data/lib/request_log_analyzer/file_format/apache.rb +147 -0
  25. data/lib/request_log_analyzer/file_format/delayed_job.rb +55 -0
  26. data/lib/request_log_analyzer/file_format/merb.rb +65 -29
  27. data/lib/request_log_analyzer/file_format/mysql.rb +101 -0
  28. data/lib/request_log_analyzer/file_format/postgresql.rb +68 -0
  29. data/lib/request_log_analyzer/file_format/rack.rb +9 -0
  30. data/lib/request_log_analyzer/file_format/rails.rb +164 -78
  31. data/lib/request_log_analyzer/file_format/rails3.rb +86 -0
  32. data/lib/request_log_analyzer/file_format/rails_development.rb +12 -0
  33. data/lib/request_log_analyzer/file_format.rb +252 -58
  34. data/lib/request_log_analyzer/filter/anonymize.rb +39 -0
  35. data/lib/request_log_analyzer/filter/field.rb +19 -13
  36. data/lib/request_log_analyzer/filter/timespan.rb +25 -12
  37. data/lib/request_log_analyzer/filter.rb +30 -0
  38. data/lib/request_log_analyzer/line_definition.rb +69 -96
  39. data/lib/request_log_analyzer/log_processor.rb +31 -53
  40. data/lib/request_log_analyzer/mailer.rb +65 -0
  41. data/lib/request_log_analyzer/output/fancy_html.rb +49 -0
  42. data/lib/request_log_analyzer/output/fixed_width.rb +220 -0
  43. data/lib/request_log_analyzer/output/html.rb +187 -0
  44. data/lib/request_log_analyzer/output.rb +117 -0
  45. data/lib/request_log_analyzer/request.rb +125 -40
  46. data/lib/request_log_analyzer/source/database_loader.rb +87 -0
  47. data/lib/request_log_analyzer/source/log_parser.rb +297 -0
  48. data/lib/request_log_analyzer/source.rb +72 -0
  49. data/lib/request_log_analyzer/tracker/duration.rb +28 -64
  50. data/lib/request_log_analyzer/tracker/frequency.rb +108 -0
  51. data/lib/request_log_analyzer/tracker/hourly_spread.rb +76 -49
  52. data/lib/request_log_analyzer/tracker/numeric_value.rb +223 -0
  53. data/lib/request_log_analyzer/tracker/timespan.rb +54 -27
  54. data/lib/request_log_analyzer/tracker/traffic.rb +40 -0
  55. data/lib/request_log_analyzer/tracker.rb +101 -0
  56. data/lib/request_log_analyzer.rb +43 -13
  57. data/request-log-analyzer.gemspec +41 -0
  58. data/spec/database.yml +23 -0
  59. data/spec/fixtures/apache_combined.log +5 -0
  60. data/spec/fixtures/apache_common.log +10 -0
  61. data/spec/fixtures/decompression.log +12 -0
  62. data/spec/fixtures/decompression.log.bz2 +0 -0
  63. data/spec/fixtures/decompression.log.gz +0 -0
  64. data/spec/fixtures/decompression.log.zip +0 -0
  65. data/spec/fixtures/decompression.tar.gz +0 -0
  66. data/spec/fixtures/decompression.tgz +0 -0
  67. data/spec/fixtures/header_and_footer.log +6 -0
  68. data/spec/fixtures/merb_prefixed.log +9 -0
  69. data/spec/fixtures/mysql_slow_query.log +110 -0
  70. data/spec/fixtures/postgresql.log +2980 -0
  71. data/spec/fixtures/rails.db +0 -0
  72. data/spec/fixtures/rails_22.log +1 -1
  73. data/spec/fixtures/sinatra.log +99 -0
  74. data/spec/integration/command_line_usage_spec.rb +84 -0
  75. data/spec/integration/mailer_spec.rb +179 -0
  76. data/spec/integration/munin_plugins_rails_spec.rb +58 -0
  77. data/spec/integration/scout_spec.rb +152 -0
  78. data/spec/lib/helpers.rb +72 -0
  79. data/spec/lib/macros.rb +18 -0
  80. data/spec/lib/matchers.rb +77 -0
  81. data/spec/lib/mocks.rb +77 -0
  82. data/spec/lib/testing_format.rb +46 -0
  83. data/spec/spec_helper.rb +16 -59
  84. data/spec/unit/aggregator/database_inserter_spec.rb +93 -0
  85. data/spec/unit/aggregator/summarizer_spec.rb +26 -0
  86. data/spec/unit/controller/controller_spec.rb +41 -0
  87. data/spec/unit/controller/log_processor_spec.rb +18 -0
  88. data/spec/unit/database/base_class_spec.rb +183 -0
  89. data/spec/unit/database/connection_spec.rb +34 -0
  90. data/spec/unit/database/database_spec.rb +133 -0
  91. data/spec/unit/file_format/amazon_s3_format_spec.rb +67 -0
  92. data/spec/unit/file_format/apache_format_spec.rb +203 -0
  93. data/spec/unit/file_format/common_regular_expressions_spec.rb +53 -0
  94. data/spec/unit/file_format/delayed_job_format_spec.rb +83 -0
  95. data/spec/unit/file_format/file_format_api_spec.rb +69 -0
  96. data/spec/unit/file_format/format_autodetection_spec.rb +40 -0
  97. data/spec/unit/file_format/line_definition_spec.rb +75 -0
  98. data/spec/unit/file_format/merb_format_spec.rb +52 -0
  99. data/spec/unit/file_format/mysql_format_spec.rb +154 -0
  100. data/spec/unit/file_format/postgresql_format_spec.rb +65 -0
  101. data/spec/unit/file_format/rack_format_spec.rb +50 -0
  102. data/spec/unit/file_format/rails3_format_spec.rb +120 -0
  103. data/spec/unit/file_format/rails_format_spec.rb +180 -0
  104. data/spec/unit/filter/anonymize_filter_spec.rb +21 -0
  105. data/spec/unit/filter/field_filter_spec.rb +66 -0
  106. data/spec/unit/filter/filter_spec.rb +17 -0
  107. data/spec/unit/filter/timespan_filter_spec.rb +58 -0
  108. data/spec/unit/mailer_spec.rb +42 -0
  109. data/spec/unit/request_spec.rb +111 -0
  110. data/spec/unit/source/log_parser_spec.rb +119 -0
  111. data/spec/unit/tracker/duration_tracker_spec.rb +49 -0
  112. data/spec/unit/tracker/frequency_tracker_spec.rb +88 -0
  113. data/spec/unit/tracker/hourly_spread_spec.rb +79 -0
  114. data/spec/unit/tracker/numeric_value_tracker_spec.rb +166 -0
  115. data/spec/unit/tracker/timespan_tracker_spec.rb +73 -0
  116. data/spec/unit/tracker/tracker_api_spec.rb +125 -0
  117. data/spec/unit/tracker/traffic_tracker_spec.rb +28 -0
  118. data/tasks/github-gem.rake +290 -139
  119. data/tasks/request_log_analyzer.rake +23 -7
  120. metadata +221 -94
  121. data/DESIGN +0 -14
  122. data/HACKING +0 -7
  123. data/README.textile +0 -36
  124. data/lib/cli/bashcolorizer.rb +0 -60
  125. data/lib/request_log_analyzer/aggregator/database.rb +0 -148
  126. data/lib/request_log_analyzer/filter/base.rb +0 -29
  127. data/lib/request_log_analyzer/log_parser.rb +0 -173
  128. data/lib/request_log_analyzer/source/base.rb +0 -42
  129. data/lib/request_log_analyzer/source/log_file.rb +0 -170
  130. data/lib/request_log_analyzer/tracker/base.rb +0 -54
  131. data/lib/request_log_analyzer/tracker/category.rb +0 -71
  132. data/spec/controller_spec.rb +0 -40
  133. data/spec/database_inserter_spec.rb +0 -101
  134. data/spec/file_format_spec.rb +0 -78
  135. data/spec/file_formats/spec_format.rb +0 -26
  136. data/spec/filter_spec.rb +0 -137
  137. data/spec/line_definition_spec.rb +0 -124
  138. data/spec/log_parser_spec.rb +0 -68
  139. data/spec/log_processor_spec.rb +0 -57
  140. data/spec/merb_format_spec.rb +0 -38
  141. data/spec/rails_format_spec.rb +0 -76
  142. data/spec/request_spec.rb +0 -72
  143. data/spec/summarizer_spec.rb +0 -9
  144. data/tasks/rspec.rake +0 -6
@@ -4,10 +4,11 @@ module RequestLogAnalyzer::Tracker
4
4
  # Also determines the amount of days inbetween these.
5
5
  #
6
6
  # Accepts the following options:
7
- # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
8
- # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
9
7
  # * <tt>:field</tt> The timestamp field that is looked at. Defaults to :timestamp.
8
+ # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
9
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
10
10
  # * <tt>:title</tt> Title do be displayed above the report.
11
+ # * <tt>:unless</tt> Proc that has to return nil for a request to be passed to the tracker.
11
12
  #
12
13
  # Expects the following items in the update request hash
13
14
  # * <tt>:timestamp</tt> in YYYYMMDDHHMMSS format.
@@ -16,39 +17,65 @@ module RequestLogAnalyzer::Tracker
16
17
  # First request: 2008-07-13 06:25:06
17
18
  # Last request: 2008-07-20 06:18:06
18
19
  # Total time analyzed: 7 days
19
- class Timespan < RequestLogAnalyzer::Tracker::Base
20
+ class Timespan < Base
21
+
22
+ attr_reader :first, :last
20
23
 
21
- attr_reader :first, :last, :request_time_graph
22
-
24
+ # Check if timestamp field is set in the options.
23
25
  def prepare
24
26
  options[:field] ||= :timestamp
27
+ @first, @last = 99999999999999, 0
25
28
  end
26
-
29
+
30
+ # Check if the timestamp in the request and store it.
31
+ # <tt>request</tt> The request.
27
32
  def update(request)
28
33
  timestamp = request[options[:field]]
34
+ @first = timestamp if timestamp < @first
35
+ @last = timestamp if timestamp > @last
36
+ end
29
37
 
30
- @first = timestamp if @first.nil? || timestamp < @first
31
- @last = timestamp if @last.nil? || timestamp > @last
38
+ # First timestamp encountered
39
+ def first_timestamp
40
+ DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
32
41
  end
33
-
34
- def report(output = STDOUT, report_width = 80, color = false)
35
- if options[:title]
36
- output << "\n#{options[:title]}\n"
37
- output << green('━' * options[:title].length, color) + "\n"
38
- end
39
-
40
- first_date = DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
41
- last_date = DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
42
-
43
- if @last && @first
44
- days = (@last && @first) ? (last_date - first_date).ceil : 1
45
-
46
- output << "First request: #{first_date.strftime('%Y-%m-%d %H:%M:%I')}\n"
47
- output << "Last request: #{last_date.strftime('%Y-%m-%d %H:%M:%I')}\n"
48
- output << "Total time analyzed: #{days} days\n"
42
+
43
+ # Last timestamp encountered
44
+ def last_timestamp
45
+ DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
46
+ end
47
+
48
+ # Difference between last and first timestamp.
49
+ def timespan
50
+ last_timestamp - first_timestamp
51
+ end
52
+
53
+ # Generate an hourly spread report to the given output object.
54
+ # Any options for the report should have been set during initialize.
55
+ # <tt>output</tt> The output object
56
+ def report(output)
57
+ output.title(options[:title]) if options[:title]
58
+
59
+ if @last > 0 && @first < 99999999999999
60
+ output.with_style(:cell_separator => false) do
61
+ output.table({:width => 20}, {}) do |rows|
62
+ rows << ['First request:', first_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
63
+ rows << ['Last request:', last_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
64
+ rows << ['Total time analyzed:', "#{timespan.ceil} days"]
65
+ end
66
+ end
49
67
  end
50
- output << "\n"
51
-
52
68
  end
69
+
70
+ # Returns the title of this tracker for reports
71
+ def title
72
+ options[:title] || 'Request timespan'
73
+ end
74
+
75
+ # A hash that can be exported to YAML with the first and last timestamp encountered.
76
+ def to_yaml_object
77
+ { :first => first_timestamp, :last =>last_timestamp }
78
+ end
79
+
53
80
  end
54
- end
81
+ end
@@ -0,0 +1,40 @@
1
+ module RequestLogAnalyzer::Tracker
2
+
3
+ # Analyze the average and total traffic of requests
4
+ #
5
+ # === Options
6
+ # * <tt>:category</tt> Proc that handles request categorization for given fileformat (REQUEST_CATEGORIZER)
7
+ # * <tt>:traffic</tt> The field containing the duration in the request hash.
8
+ # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
9
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
10
+ # * <tt>:title</tt> Title do be displayed above the report
11
+ # * <tt>:unless</tt> Handle request if this proc is false for the handled request.
12
+ class Traffic < NumericValue
13
+
14
+ # Check if duration and catagory option have been received,
15
+ def prepare
16
+ options[:value] = options[:traffic] if options[:traffic]
17
+ options[:total] = true
18
+ super
19
+ end
20
+
21
+ # Formats the traffic number using x B/kB/MB/GB etc notation
22
+ def display_value(bytes)
23
+ return "-" if bytes.nil?
24
+ return "0 B" if bytes.zero?
25
+
26
+ case [Math.log10(bytes.abs).floor, 0].max
27
+ when 0...4 then '%d B' % bytes
28
+ when 4...7 then '%d kB' % (bytes / 1000)
29
+ when 7...10 then '%d MB' % (bytes / 1000_000)
30
+ when 10...13 then '%d GB' % (bytes / 1000_000_000)
31
+ else '%d TB' % (bytes / 1000_000_000_000)
32
+ end
33
+ end
34
+
35
+ # Returns the title of this tracker for reports
36
+ def title
37
+ options[:title] || 'Request traffic'
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,101 @@
1
+ module RequestLogAnalyzer::Tracker
2
+
3
+ # const_missing: this function is used to load subclasses in the RequestLogAnalyzer::Track namespace.
4
+ # It will automatically load the required file based on the class name
5
+ def self.const_missing(const)
6
+ RequestLogAnalyzer::load_default_class_file(self, const)
7
+ end
8
+
9
+ # Base Tracker class. All other trackers inherit from this class
10
+ #
11
+ # Accepts the following options:
12
+ # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
13
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
14
+ # * <tt>:output</tt> Direct output here (defaults to STDOUT)
15
+ # * <tt>:unless</tt> Proc that has to return nil for a request to be passed to the tracker.
16
+ #
17
+ # For example :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }
18
+ class Base
19
+
20
+ attr_reader :options
21
+
22
+ # Initialize the class
23
+ # Note that the options are only applicable if should_update? is not overwritten
24
+ # by the inheriting class.
25
+ #
26
+ # === Options
27
+ # * <tt>:if</tt> Handle request if this proc is true for the handled request.
28
+ # * <tt>:unless</tt> Handle request if this proc is false for the handled request.
29
+ # * <tt>:line_type</tt> Line type this tracker will accept.
30
+ def initialize(options ={})
31
+ @options = options
32
+ setup_should_update_checks!
33
+ end
34
+
35
+ # Sets up the tracker's should_update? checks.
36
+ def setup_should_update_checks!
37
+ @should_update_checks = []
38
+ @should_update_checks.push( lambda { |request| request.has_line_type?(options[:line_type]) } ) if options[:line_type]
39
+ @should_update_checks.push(options[:if]) if options[:if].respond_to?(:call)
40
+ @should_update_checks.push( lambda { |request| request[options[:if]] }) if options[:if].kind_of?(Symbol)
41
+ @should_update_checks.push( lambda { |request| !options[:unless].call(request) }) if options[:unless].respond_to?(:call)
42
+ @should_update_checks.push( lambda { |request| !request[options[:unless]] }) if options[:unless].kind_of?(Symbol)
43
+ end
44
+
45
+ # Creates a lambda expression to return a static field from a request. If the
46
+ # argument already is a lambda exprssion, it will simply return the argument.
47
+ def create_lambda(arg)
48
+ case arg
49
+ when Proc then arg
50
+ when Symbol then lambda { |request| request[arg] }
51
+ else raise "Canot create a lambda expression from this argument: #{arg.inspect}!"
52
+ end
53
+ end
54
+
55
+ # Hook things that need to be done before running here.
56
+ def prepare
57
+ end
58
+
59
+ # Will be called with each request.
60
+ # <tt>request</tt> The request to track data in.
61
+ def update(request)
62
+ end
63
+
64
+ # Hook things that need to be done after running here.
65
+ def finalize
66
+ end
67
+
68
+ # Determine if we should run the update function at all.
69
+ # Usually the update function will be heavy, so a light check is done here
70
+ # determining if we need to call update at all.
71
+ #
72
+ # Default this checks if defined:
73
+ # * :line_type is also in the request hash.
74
+ # * :if is true for this request.
75
+ # * :unless if false for this request
76
+ #
77
+ # <tt>request</tt> The request object.
78
+ def should_update?(request)
79
+ @should_update_checks.all? { |c| c.call(request) }
80
+ end
81
+
82
+ # Hook report generation here.
83
+ # Defaults to self.inspect
84
+ # <tt>output</tt> The output object the report will be passed to.
85
+ def report(output)
86
+ output << self.inspect
87
+ output << "\n"
88
+ end
89
+
90
+ # The title of this tracker. Used for reporting.
91
+ def title
92
+ self.class.to_s
93
+ end
94
+
95
+ # This method is called by RequestLogAnalyzer::Aggregator:Summarizer to retrieve an
96
+ # object with all the results of this tracker, that can be dumped to YAML format.
97
+ def to_yaml_object
98
+ nil
99
+ end
100
+ end
101
+ end
@@ -1,14 +1,44 @@
1
1
  require 'date'
2
- require File.dirname(__FILE__) + '/cli/progressbar'
3
- require File.dirname(__FILE__) + '/cli/bashcolorizer'
4
-
5
- require File.dirname(__FILE__) + '/request_log_analyzer/file_format'
6
- require File.dirname(__FILE__) + '/request_log_analyzer/line_definition'
7
- require File.dirname(__FILE__) + '/request_log_analyzer/request'
8
- require File.dirname(__FILE__) + '/request_log_analyzer/log_parser'
9
- require File.dirname(__FILE__) + '/request_log_analyzer/aggregator/base'
10
- require File.dirname(__FILE__) + '/request_log_analyzer/aggregator/summarizer'
11
- require File.dirname(__FILE__) + '/request_log_analyzer/filter/base'
12
- require File.dirname(__FILE__) + '/request_log_analyzer/controller'
13
- require File.dirname(__FILE__) + '/request_log_analyzer/source/base'
14
- require File.dirname(__FILE__) + '/request_log_analyzer/source/log_file'
2
+
3
+ # Satisfy ruby 1.9 sensitivity about encoding.
4
+ Encoding.default_external = 'binary' if defined? Encoding and Encoding.respond_to? 'default_external='
5
+
6
+ # RequestLogAnalyzer is the base namespace in which all functionality of RequestLogAnalyzer is implemented.
7
+ #
8
+ # - This module itselfs contains some functions to help with class and source file loading.
9
+ # - The actual application resides in the RequestLogAnalyzer::Controller class.
10
+ module RequestLogAnalyzer
11
+
12
+ # The current version of request-log-analyzer.
13
+ # Do not change the value by hand; it will be updated automatically by the gem release script.
14
+ VERSION = "1.6.3"
15
+
16
+ # Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
17
+ # <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
18
+ def self.const_missing(const)
19
+ load_default_class_file(RequestLogAnalyzer, const)
20
+ end
21
+
22
+ # Loads constants that reside in the RequestLogAnalyzer tree using the constant name
23
+ # and its base constant to determine the filename.
24
+ # <tt>base</tt>:: The base constant to load the constant from. This should be Foo when the constant Foo::Bar is being loaded.
25
+ # <tt>const</tt>:: The constant to load from the base constant as a string or symbol. This should be 'Bar' or :Bar when the constant Foo::Bar is being loaded.
26
+ def self.load_default_class_file(base, const)
27
+ require "#{to_underscore("#{base.name}::#{const}")}"
28
+ base.const_get(const) if base.const_defined?(const)
29
+ end
30
+
31
+ # Convert a string/symbol in camelcase (RequestLogAnalyzer::Controller) to underscores (request_log_analyzer/controller)
32
+ # This function can be used to load the file (using require) in which the given constant is defined.
33
+ # <tt>str</tt>:: The string to convert in the following format: <tt>ModuleName::ClassName</tt>
34
+ def self.to_underscore(str)
35
+ str.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
36
+ end
37
+
38
+ # Convert a string/symbol in underscores (<tt>request_log_analyzer/controller</tt>) to camelcase
39
+ # (<tt>RequestLogAnalyzer::Controller</tt>). This can be used to find the class that is defined in a given filename.
40
+ # <tt>str</tt>:: The string to convert in the following format: <tt>module_name/class_name</tt>
41
+ def self.to_camelcase(str)
42
+ str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "request-log-analyzer"
3
+
4
+ # Do not set the version and date field manually, this is done by the release script
5
+ s.version = "1.6.3"
6
+ s.date = "2010-03-19"
7
+
8
+ s.rubyforge_project = 'r-l-a'
9
+
10
+ s.bindir = 'bin'
11
+ s.executables = ['request-log-analyzer']
12
+ s.default_executable = 'request-log-analyzer'
13
+
14
+ s.summary = "A command line tool to analyze request logs for Apache, Rails, Merb, MySQL and other web application servers"
15
+ s.description = <<-eos
16
+ Request log analyzer's purpose is to find out how your web application is being used, how it performs and to
17
+ focus your optimization efforts. This tool will parse all requests in the application's log file and aggregate the
18
+ information. Once it is finished parsing the log file(s), it will show the requests that take op most server time
19
+ using various metrics. It can also insert all parsed request information into a database so you can roll your own
20
+ analysis. It supports Rails-, Merb- and Rack-based applications logs, Apache and Amazon S3 access logs and MySQL
21
+ slow query logs out of the box, but file formats of other applications can easily be supported by supplying an
22
+ easy to write log file format definition.
23
+ eos
24
+
25
+ s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
26
+ s.extra_rdoc_files = ['README.rdoc']
27
+
28
+ s.requirements << "To use the database inserter, ActiveRecord and an appropriate database adapter are required."
29
+
30
+ s.add_development_dependency('rspec', '>= 1.2.4')
31
+ s.add_development_dependency('git', '>= 1.1.0')
32
+
33
+ s.authors = ['Willem van Bergen', 'Bart ten Brinke']
34
+ s.email = ['willem@railsdoctors.com', 'bart@railsdoctors.com']
35
+ s.homepage = 'http://railsdoctors.com'
36
+
37
+ # The files and test_files directives are set automatically by the release script.
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 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
+ end
data/spec/database.yml ADDED
@@ -0,0 +1,23 @@
1
+ # This file determines what databases are used to test the database
2
+ # functionality of request-log-analyzer. By default, only an SQLite3
3
+ # memory database is enabled.
4
+ #
5
+ # The syntax of this file is exactly the same as Rails's database.yml.
6
+
7
+ sqlite3:
8
+ adapter: "sqlite3"
9
+ database: ":memory:"
10
+
11
+ # mysql:
12
+ # adapter: "mysql"
13
+ # host: "localhost"
14
+ # username: "root"
15
+ # password:
16
+ # database: "rla_test"
17
+
18
+ # postgresql:
19
+ # adapter: "postgresql"
20
+ # host: "localhost"
21
+ # username: "rla"
22
+ # password: "rla"
23
+ # database: "rla_test"
@@ -0,0 +1,5 @@
1
+ 125.76.230.10 - - [02/Sep/2009:03:33:46 +0200] "GET /cart/install.txt HTTP/1.1" 404 214 "-" "Toata dragostea mea pentru diavola"
2
+ 125.76.230.10 - - [02/Sep/2009:03:33:47 +0200] "GET /store/install.txt HTTP/1.1" 404 215 "-" "Toata dragostea mea pentru diavola"
3
+ 10.0.1.1 - - [02/Sep/2009:05:08:33 +0200] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"
4
+ 10.0.1.1 - - [02/Sep/2009:06:41:51 +0200] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"
5
+ 69.41.0.45 - - [02/Sep/2009:12:02:40 +0200] "GET //phpMyAdmin/ HTTP/1.1" 404 209 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
@@ -0,0 +1,10 @@
1
+ 1.56.136.157 - - [08/Sep/2009:07:54:07 -0400] "GET /form_configurations/show.flashxml HTTP/1.1" 304 -
2
+ 1.72.56.31 - - [08/Sep/2009:07:54:07 -0400] "GET /users/M17286/projects.xml?per_page=8000 HTTP/1.1" 404 1
3
+ 1.82.235.29 - - [08/Sep/2009:07:54:05 -0400] "GET /gallery/fresh?page=23&per_page=16 HTTP/1.1" 200 23414
4
+ 1.56.136.157 - - [08/Sep/2009:07:54:08 -0400] "GET /designs/20110457.flashxml HTTP/1.1" 304 -
5
+ 1.56.136.157 - - [08/Sep/2009:07:54:08 -0400] "GET /object_libraries/1.flashxml HTTP/1.1" 304 -
6
+ 1.249.68.72 - - [08/Sep/2009:07:54:09 -0400] "GET /projects/18182835-my-first-project HTTP/1.1" 200 10435
7
+ 1.108.106.20 - - [08/Sep/2009:07:54:09 -0400] "GET /login HTTP/1.1" 200 9522
8
+ 1.129.119.13 - - [08/Sep/2009:07:54:09 -0400] "GET /profile/18543424 HTTP/1.0" 200 8223
9
+ 1.158.151.25 - - [08/Sep/2009:07:54:09 -0400] "GET /projects/18236114-home/floors/18252888-/designs/19406560-home-1 HTTP/1.1" 200 10434
10
+ 1.29.137.1 - - [08/Sep/2009:07:54:10 -0400] "GET /assets/custom/blah/images/print_logo.jpg HTTP/1.1" 200 10604
@@ -0,0 +1,12 @@
1
+ Processing PageController#demo (for 127.0.0.1 at 2008-12-10 16:28:09) [GET]
2
+ Parameters: {"action"=>"demo", "controller"=>"page"}
3
+ Logging in from session data...
4
+ Logged in as test@example.com
5
+ Using locale: en-US, http-accept: ["en-US"], session: , det browser: en-US, det domain:
6
+ Rendering template within layouts/demo
7
+ Rendering page/demo
8
+ Rendered shared/_analytics (0.2ms)
9
+ Rendered layouts/_actions (0.6ms)
10
+ Rendered layouts/_menu (2.2ms)
11
+ Rendered layouts/_tabbar (0.5ms)
12
+ Completed in 614ms (View: 120, DB: 31) | 200 OK [http://www.example.coml/demo]
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,6 @@
1
+ start!
2
+ this is a header and footer line
3
+ blah
4
+
5
+ this is a header and footer line
6
+ blah
@@ -0,0 +1,9 @@
1
+ Aug 31 18:35:23 typekit-web001 merb: ~
2
+ Aug 31 18:35:23 typekit-web001 merb: cache: [GET /] miss
3
+ Aug 31 18:35:24 typekit-web001 merb: ~ Started request handling: Mon Aug 31 18:35:25 +0000 2009
4
+ Aug 31 18:35:24 typekit-web001 merb: ~ Routed to: {"action"=>"index", "controller"=>"home"}
5
+ Aug 31 18:35:24 typekit-web001 merb: ~ Params: {"action"=>"index", "controller"=>"home"}
6
+ Aug 31 18:35:24 typekit-web001 merb: ~ In repository block default
7
+ Aug 31 18:35:24 typekit-web001 merb: ~ (0.000000) SELECT `id`, `created_at`, `updated_at`, `braintree_vault_id`, `cancelled_at` FROM `accounts` WHERE (`id` IN (6214)) ORDER BY `id`
8
+ Aug 31 18:35:24 typekit-web001 merb: ~ Redirecting to: /plans (302)
9
+ Aug 31 18:35:24 typekit-web001 merb: ~ {:after_filters_time=>0.0, :before_filters_time=>0.0, :dispatch_time=>0.012001, :action_time=>0.012001}
@@ -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));