request-log-analyzer 1.3.5 → 1.3.6
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/lib/cli/database_console_init.rb +2 -1
- data/lib/request_log_analyzer.rb +1 -1
- data/lib/request_log_analyzer/aggregator.rb +1 -5
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +4 -5
- data/lib/request_log_analyzer/controller.rb +10 -21
- data/lib/request_log_analyzer/database.rb +16 -91
- data/lib/request_log_analyzer/database/base.rb +4 -4
- data/lib/request_log_analyzer/database/request.rb +22 -0
- data/lib/request_log_analyzer/database/source.rb +13 -0
- data/lib/request_log_analyzer/database/warning.rb +14 -0
- data/lib/request_log_analyzer/file_format.rb +1 -13
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +1 -2
- data/lib/request_log_analyzer/file_format/apache.rb +8 -10
- data/lib/request_log_analyzer/file_format/merb.rb +21 -5
- data/lib/request_log_analyzer/file_format/rails.rb +8 -14
- data/lib/request_log_analyzer/filter.rb +6 -10
- data/lib/request_log_analyzer/filter/anonymize.rb +2 -1
- data/lib/request_log_analyzer/log_processor.rb +6 -8
- data/lib/request_log_analyzer/request.rb +47 -35
- data/lib/request_log_analyzer/source.rb +4 -6
- data/lib/request_log_analyzer/source/database_loader.rb +3 -7
- data/lib/request_log_analyzer/source/log_parser.rb +3 -6
- data/lib/request_log_analyzer/tracker.rb +12 -19
- data/lib/request_log_analyzer/tracker/hourly_spread.rb +1 -2
- data/request-log-analyzer.gemspec +3 -3
- data/spec/database.yml +6 -0
- data/spec/unit/aggregator/database_inserter_spec.rb +3 -3
- data/spec/unit/database/base_class_spec.rb +9 -16
- data/spec/unit/database/database_spec.rb +9 -14
- data/spec/unit/tracker/tracker_api_spec.rb +111 -36
- metadata +7 -4
| @@ -3,6 +3,7 @@ $:.unshift(File.dirname(__FILE__) + '/..') | |
| 3 3 |  | 
| 4 4 | 
             
            $database = RequestLogAnalyzer::Database.new(ENV['RLA_DBCONSOLE_DATABASE'])
         | 
| 5 5 | 
             
            $database.load_database_schema!
         | 
| 6 | 
            +
            $database.register_default_orm_classes!
         | 
| 6 7 |  | 
| 7 8 | 
             
            require 'cli/tools'
         | 
| 8 9 |  | 
| @@ -39,4 +40,4 @@ end | |
| 39 40 | 
             
            puts "request-log-analyzer database console"
         | 
| 40 41 | 
             
            puts "-------------------------------------"
         | 
| 41 42 | 
             
            puts "The following ActiveRecord classes are available:"
         | 
| 42 | 
            -
            puts $database.orm_classes.join(", ")
         | 
| 43 | 
            +
            puts $database.orm_classes.map { |k| k.name.split('::').last }.join(", ")
         | 
    
        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 | 
             
              # This will be diplayed in output reports etc.
         | 
| 14 | 
            -
              VERSION = "1.3. | 
| 14 | 
            +
              VERSION = "1.3.6"
         | 
| 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.
         | 
| @@ -8,16 +8,12 @@ module RequestLogAnalyzer::Aggregator | |
| 8 8 | 
             
              # every aggregator should comply (by simply subclassing this class).
         | 
| 9 9 | 
             
              class Base
         | 
| 10 10 |  | 
| 11 | 
            -
                 | 
| 12 | 
            -
                
         | 
| 13 | 
            -
                attr_reader :options
         | 
| 14 | 
            -
                attr_reader :source
         | 
| 11 | 
            +
                attr_reader :options, :source
         | 
| 15 12 |  | 
| 16 13 | 
             
                # Intializes a new RequestLogAnalyzer::Aggregator::Base instance
         | 
| 17 14 | 
             
                # It will include the specific file format module.
         | 
| 18 15 | 
             
                def initialize(source, options = {})
         | 
| 19 16 | 
             
                  @source = source
         | 
| 20 | 
            -
                  self.register_file_format(source.file_format)
         | 
| 21 17 | 
             
                  @options = options
         | 
| 22 18 | 
             
                end
         | 
| 23 19 |  | 
| @@ -31,7 +31,7 @@ module RequestLogAnalyzer::Aggregator | |
| 31 31 | 
             
                # This will create a record in the requests table and create a record for every line that has been parsed,
         | 
| 32 32 | 
             
                # in which the captured values will be stored.
         | 
| 33 33 | 
             
                def aggregate(request)
         | 
| 34 | 
            -
                  @request_object =  | 
| 34 | 
            +
                  @request_object = RequestLogAnalyzer::Database::Request.new(:first_lineno => request.first_lineno, :last_lineno => request.last_lineno)
         | 
| 35 35 | 
             
                  request.lines.each do |line|
         | 
| 36 36 | 
             
                    class_columns = database.get_class(line[:line_type]).column_names.reject { |column| ['id', 'source_id', 'request_id'].include?(column) }
         | 
| 37 37 | 
             
                    attributes = Hash[*line.select { |(k, v)| class_columns.include?(k.to_s) }.flatten]
         | 
| @@ -45,14 +45,14 @@ module RequestLogAnalyzer::Aggregator | |
| 45 45 |  | 
| 46 46 | 
             
                # Finalizes the aggregator by closing the connection to the database
         | 
| 47 47 | 
             
                def finalize
         | 
| 48 | 
            -
                  @request_count =  | 
| 48 | 
            +
                  @request_count = RequestLogAnalyzer::Database::Request.count
         | 
| 49 49 | 
             
                  database.disconnect
         | 
| 50 50 | 
             
                  database.remove_orm_classes!
         | 
| 51 51 | 
             
                end
         | 
| 52 52 |  | 
| 53 53 | 
             
                # Records w warining in the warnings table.
         | 
| 54 54 | 
             
                def warning(type, message, lineno)
         | 
| 55 | 
            -
                   | 
| 55 | 
            +
                  RequestLogAnalyzer::Database::Warning.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
         | 
| 56 56 | 
             
                end
         | 
| 57 57 |  | 
| 58 58 | 
             
                # Records source changes in the sources table
         | 
| @@ -60,8 +60,7 @@ module RequestLogAnalyzer::Aggregator | |
| 60 60 | 
             
                  if File.exist?(filename)
         | 
| 61 61 | 
             
                    case change
         | 
| 62 62 | 
             
                    when :started
         | 
| 63 | 
            -
                       | 
| 64 | 
            -
                      @sources[filename] = database.source_class.create!(:filename => filename)
         | 
| 63 | 
            +
                      @sources[filename] = RequestLogAnalyzer::Database::Source.create!(:filename => filename)
         | 
| 65 64 | 
             
                    when :finished
         | 
| 66 65 | 
             
                      @sources[filename].update_attributes!(:filesize => File.size(filename), :mtime => File.mtime(filename))
         | 
| 67 66 | 
             
                    end
         | 
| @@ -17,14 +17,7 @@ module RequestLogAnalyzer | |
| 17 17 | 
             
              # from several logrotated log files.
         | 
| 18 18 | 
             
              class Controller
         | 
| 19 19 |  | 
| 20 | 
            -
                 | 
| 21 | 
            -
                
         | 
| 22 | 
            -
                attr_reader :aggregators
         | 
| 23 | 
            -
                attr_reader :filters
         | 
| 24 | 
            -
                attr_reader :log_parser
         | 
| 25 | 
            -
                attr_reader :source
         | 
| 26 | 
            -
                attr_reader :output
         | 
| 27 | 
            -
                attr_reader :options
         | 
| 20 | 
            +
                attr_reader :source, :filters, :aggregators, :output, :options
         | 
| 28 21 |  | 
| 29 22 | 
             
                # Builds a RequestLogAnalyzer::Controller given parsed command line arguments
         | 
| 30 23 | 
             
                # <tt>arguments<tt> A CommandLine::Arguments hash containing parsed commandline parameters.
         | 
| @@ -35,8 +28,8 @@ module RequestLogAnalyzer | |
| 35 28 | 
             
                  # Database command line options
         | 
| 36 29 | 
             
                  options[:database]       = arguments[:database] if arguments[:database]
         | 
| 37 30 | 
             
                  options[:reset_database] = arguments[:reset_database]
         | 
| 38 | 
            -
                  options[:debug] | 
| 39 | 
            -
                  options[:dump] | 
| 31 | 
            +
                  options[:debug]          = arguments[:debug]
         | 
| 32 | 
            +
                  options[:dump]           = arguments[:dump]
         | 
| 40 33 | 
             
                  options[:parse_strategy] = arguments[:parse_strategy]
         | 
| 41 34 | 
             
                  options[:no_progress]    = arguments[:no_progress]
         | 
| 42 35 |  | 
| @@ -125,17 +118,13 @@ module RequestLogAnalyzer | |
| 125 118 | 
             
                  @filters     = []
         | 
| 126 119 | 
             
                  @output      = options[:output]
         | 
| 127 120 |  | 
| 128 | 
            -
                  #  | 
| 129 | 
            -
                   | 
| 130 | 
            -
                  
         | 
| 131 | 
            -
                  # Pass all warnings to every aggregator so they can do something useful with them.
         | 
| 132 | 
            -
                  @source.warning = lambda { |type, message, lineno|  @aggregators.each { |agg| agg.warning(type, message, lineno) } } if @source
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                  # Handle progress messagess
         | 
| 135 | 
            -
                  @source.progress = lambda { |message, value| handle_progress(message, value) } if @source && !options[:no_progress]
         | 
| 121 | 
            +
                  # Register the request format for this session after checking its validity
         | 
| 122 | 
            +
                  raise "Invalid file format!" unless @source.file_format.valid?
         | 
| 136 123 |  | 
| 137 | 
            -
                  #  | 
| 138 | 
            -
                  @source. | 
| 124 | 
            +
                  # Install event handlers for wrnings, progress updates and source changes
         | 
| 125 | 
            +
                  @source.warning        = lambda { |type, message, lineno|  @aggregators.each { |agg| agg.warning(type, message, lineno) } }
         | 
| 126 | 
            +
                  @source.progress       = lambda { |message, value| handle_progress(message, value) } unless options[:no_progress]
         | 
| 127 | 
            +
                  @source.source_changes = lambda { |change, filename| handle_source_change(change, filename) }
         | 
| 139 128 | 
             
                end
         | 
| 140 129 |  | 
| 141 130 | 
             
                # Progress function.
         | 
| @@ -176,7 +165,7 @@ module RequestLogAnalyzer | |
| 176 165 | 
             
                # Adds a request filter to the controller.
         | 
| 177 166 | 
             
                def add_filter(filter, filter_options = {})
         | 
| 178 167 | 
             
                  filter = RequestLogAnalyzer::Filter.const_get(RequestLogAnalyzer::to_camelcase(filter)) if filter.kind_of?(Symbol)
         | 
| 179 | 
            -
                  @filters << filter.new(file_format, @options.merge(filter_options))
         | 
| 168 | 
            +
                  @filters << filter.new(source.file_format, @options.merge(filter_options))
         | 
| 180 169 | 
             
                end
         | 
| 181 170 |  | 
| 182 171 | 
             
                # Push a request through the entire filterchain (@filters).
         | 
| @@ -10,7 +10,7 @@ class RequestLogAnalyzer::Database | |
| 10 10 | 
             
              include RequestLogAnalyzer::Database::Connection
         | 
| 11 11 |  | 
| 12 12 | 
             
              attr_accessor :file_format
         | 
| 13 | 
            -
              attr_reader : | 
| 13 | 
            +
              attr_reader :line_classes
         | 
| 14 14 |  | 
| 15 15 | 
             
              def initialize(connection_identifier = nil)
         | 
| 16 16 | 
             
                @line_classes = []
         | 
| @@ -24,97 +24,17 @@ class RequestLogAnalyzer::Database | |
| 24 24 | 
             
                Object.const_get("#{line_type}_line".camelize)
         | 
| 25 25 | 
             
              end
         | 
| 26 26 |  | 
| 27 | 
            -
               | 
| 28 | 
            -
             | 
| 29 | 
            -
              # It will create the class if not previously done so. The class will
         | 
| 30 | 
            -
              # include a create_table! method the migrate the database.
         | 
| 31 | 
            -
              def request_class
         | 
| 32 | 
            -
                @request_class ||= begin
         | 
| 33 | 
            -
                  klass = Class.new(RequestLogAnalyzer::Database::Base) do
         | 
| 34 | 
            -
                    
         | 
| 35 | 
            -
                    def lines
         | 
| 36 | 
            -
                      @lines ||= begin
         | 
| 37 | 
            -
                        lines = []
         | 
| 38 | 
            -
                        self.class.reflections.each { |r, d| lines += self.send(r).all }
         | 
| 39 | 
            -
                        lines.sort
         | 
| 40 | 
            -
                      end
         | 
| 41 | 
            -
                    end
         | 
| 42 | 
            -
                    
         | 
| 43 | 
            -
                    # Creates the requests table
         | 
| 44 | 
            -
                    def self.create_table!
         | 
| 45 | 
            -
                      unless database.connection.table_exists?(:requests)
         | 
| 46 | 
            -
                        database.connection.create_table(:requests) do |t|
         | 
| 47 | 
            -
                          t.column :first_lineno, :integer
         | 
| 48 | 
            -
                          t.column :last_lineno,  :integer
         | 
| 49 | 
            -
                        end
         | 
| 50 | 
            -
                      end
         | 
| 51 | 
            -
                    end
         | 
| 52 | 
            -
                  end
         | 
| 53 | 
            -
                  
         | 
| 54 | 
            -
                  Object.const_set('Request', klass) 
         | 
| 55 | 
            -
                  Object.const_get('Request')
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
              end
         | 
| 58 | 
            -
              
         | 
| 59 | 
            -
              # Returns the Source ORM class for the current database.
         | 
| 60 | 
            -
              #
         | 
| 61 | 
            -
              # It will create the class if not previously done so. The class will
         | 
| 62 | 
            -
              # include a create_table! method the migrate the database.  
         | 
| 63 | 
            -
              def source_class
         | 
| 64 | 
            -
                @source_class ||= begin
         | 
| 65 | 
            -
                  klass = Class.new(RequestLogAnalyzer::Database::Base) do
         | 
| 66 | 
            -
                    
         | 
| 67 | 
            -
                    # Creates the sources table
         | 
| 68 | 
            -
                    def self.create_table!
         | 
| 69 | 
            -
                      unless database.connection.table_exists?(:sources)
         | 
| 70 | 
            -
                        database.connection.create_table(:sources) do |t|
         | 
| 71 | 
            -
                          t.column :filename, :string
         | 
| 72 | 
            -
                          t.column :mtime,    :datetime
         | 
| 73 | 
            -
                          t.column :filesize, :integer
         | 
| 74 | 
            -
                        end
         | 
| 75 | 
            -
                      end
         | 
| 76 | 
            -
                    end
         | 
| 77 | 
            -
                  end
         | 
| 78 | 
            -
                  
         | 
| 79 | 
            -
                  Object.const_set('Source', klass)
         | 
| 80 | 
            -
                  Object.const_get('Source')
         | 
| 81 | 
            -
                end
         | 
| 82 | 
            -
              end
         | 
| 83 | 
            -
              
         | 
| 84 | 
            -
              
         | 
| 85 | 
            -
              # Returns the Warning ORM class for the current database.
         | 
| 86 | 
            -
              #
         | 
| 87 | 
            -
              # It will create the class if not previously done so. The class will
         | 
| 88 | 
            -
              # include a create_table! method the migrate the database.  
         | 
| 89 | 
            -
              def warning_class
         | 
| 90 | 
            -
                @warning_class ||= begin
         | 
| 91 | 
            -
                  klass = Class.new(RequestLogAnalyzer::Database::Base) do
         | 
| 92 | 
            -
                    
         | 
| 93 | 
            -
                    # Creates the warnings table
         | 
| 94 | 
            -
                    def self.create_table!
         | 
| 95 | 
            -
                      unless database.connection.table_exists?(:warnings)
         | 
| 96 | 
            -
                        database.connection.create_table(:warnings) do |t|
         | 
| 97 | 
            -
                          t.column  :warning_type, :string, :limit => 30, :null => false
         | 
| 98 | 
            -
                          t.column  :message, :string
         | 
| 99 | 
            -
                          t.column  :source_id, :integer
         | 
| 100 | 
            -
                          t.column  :lineno, :integer
         | 
| 101 | 
            -
                        end
         | 
| 102 | 
            -
                      end
         | 
| 103 | 
            -
                    end
         | 
| 104 | 
            -
                  end
         | 
| 105 | 
            -
                  
         | 
| 106 | 
            -
                  Object.const_set('Warning', klass)
         | 
| 107 | 
            -
                  Object.const_get('Warning')
         | 
| 108 | 
            -
                end
         | 
| 27 | 
            +
              def default_classes
         | 
| 28 | 
            +
                [RequestLogAnalyzer::Database::Request, RequestLogAnalyzer::Database::Source, RequestLogAnalyzer::Database::Warning]
         | 
| 109 29 | 
             
              end
         | 
| 110 30 |  | 
| 111 31 | 
             
              # Loads the ORM classes by inspecting the tables in the current database
         | 
| 112 32 | 
             
              def load_database_schema!
         | 
| 113 33 | 
             
                connection.tables.map do |table|
         | 
| 114 34 | 
             
                  case table.to_sym
         | 
| 115 | 
            -
                  when :warnings then  | 
| 116 | 
            -
                  when :sources  then  | 
| 117 | 
            -
                  when :requests then  | 
| 35 | 
            +
                  when :warnings then RequestLogAnalyzer::Database::Warning
         | 
| 36 | 
            +
                  when :sources  then RequestLogAnalyzer::Database::Source
         | 
| 37 | 
            +
                  when :requests then RequestLogAnalyzer::Database::Request
         | 
| 118 38 | 
             
                  else load_activerecord_class(table)
         | 
| 119 39 | 
             
                  end
         | 
| 120 40 | 
             
                end
         | 
| @@ -122,7 +42,7 @@ class RequestLogAnalyzer::Database | |
| 122 42 |  | 
| 123 43 | 
             
              # Returns an array of all the ActiveRecord-bases ORM classes for this database
         | 
| 124 44 | 
             
              def orm_classes
         | 
| 125 | 
            -
                 | 
| 45 | 
            +
                default_classes + line_classes
         | 
| 126 46 | 
             
              end
         | 
| 127 47 |  | 
| 128 48 | 
             
              # Loads an ActiveRecord-based class that correspond to the given parameter, which can either be
         | 
| @@ -146,8 +66,6 @@ class RequestLogAnalyzer::Database | |
| 146 66 |  | 
| 147 67 | 
             
              def fileformat_classes
         | 
| 148 68 | 
             
                raise "No file_format provided!" unless file_format
         | 
| 149 | 
            -
                
         | 
| 150 | 
            -
                default_classes = [request_class, source_class, warning_class]
         | 
| 151 69 | 
             
                line_classes    = file_format.line_definitions.map { |(name, definition)| load_activerecord_class(definition) }
         | 
| 152 70 | 
             
                return default_classes + line_classes
         | 
| 153 71 | 
             
              end
         | 
| @@ -164,12 +82,19 @@ class RequestLogAnalyzer::Database | |
| 164 82 | 
             
                remove_orm_classes!
         | 
| 165 83 | 
             
              end
         | 
| 166 84 |  | 
| 85 | 
            +
              # Registers the default ORM classes in the default namespace
         | 
| 86 | 
            +
              def register_default_orm_classes!
         | 
| 87 | 
            +
                Object.const_set('Request', RequestLogAnalyzer::Database::Request)
         | 
| 88 | 
            +
                Object.const_set('Source',  RequestLogAnalyzer::Database::Source)
         | 
| 89 | 
            +
                Object.const_set('Warning', RequestLogAnalyzer::Database::Warning)
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
              
         | 
| 167 92 | 
             
              # Unregisters every ORM class constant
         | 
| 168 93 | 
             
              def remove_orm_classes!
         | 
| 169 94 | 
             
                orm_classes.each do |klass|
         | 
| 170 95 | 
             
                  if klass.respond_to?(:name) && !klass.name.blank?
         | 
| 171 | 
            -
             | 
| 172 | 
            -
                    Object.send(:remove_const,  | 
| 96 | 
            +
                    klass_name = klass.name.split('::').last
         | 
| 97 | 
            +
                    Object.send(:remove_const, klass_name) if Object.const_defined?(klass_name)
         | 
| 173 98 | 
             
                  end
         | 
| 174 99 | 
             
                end
         | 
| 175 100 | 
             
              end
         | 
| @@ -32,8 +32,8 @@ class RequestLogAnalyzer::Database::Base < ActiveRecord::Base | |
| 32 32 | 
             
                  klass.send(:serialize, capture[:name], Hash)
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 | 
            -
                 | 
| 36 | 
            -
                 | 
| 35 | 
            +
                RequestLogAnalyzer::Database::Request.has_many  "#{definition.name}_lines".to_sym
         | 
| 36 | 
            +
                RequestLogAnalyzer::Database::Source.has_many   "#{definition.name}_lines".to_sym
         | 
| 37 37 |  | 
| 38 38 | 
             
                return klass
         | 
| 39 39 | 
             
              end
         | 
| @@ -46,12 +46,12 @@ class RequestLogAnalyzer::Database::Base < ActiveRecord::Base | |
| 46 46 |  | 
| 47 47 | 
             
                if klass.column_names.include?('request_id')
         | 
| 48 48 | 
             
                  klass.belongs_to :request
         | 
| 49 | 
            -
                   | 
| 49 | 
            +
                  RequestLogAnalyzer::Database::Request.has_many table.to_sym
         | 
| 50 50 | 
             
                end
         | 
| 51 51 |  | 
| 52 52 | 
             
                if klass.column_names.include?('source_id')
         | 
| 53 53 | 
             
                  klass.belongs_to :source
         | 
| 54 | 
            -
                   | 
| 54 | 
            +
                  RequestLogAnalyzer::Database::Source.has_many table.to_sym
         | 
| 55 55 | 
             
                end
         | 
| 56 56 |  | 
| 57 57 | 
             
                return klass
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            class RequestLogAnalyzer::Database::Request < RequestLogAnalyzer::Database::Base
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              # Returns an array of all the Line objects of this request in the correct order.
         | 
| 4 | 
            +
              def lines
         | 
| 5 | 
            +
                @lines ||= begin
         | 
| 6 | 
            +
                  lines = []
         | 
| 7 | 
            +
                  self.class.reflections.each { |r, d| lines += self.send(r).all }
         | 
| 8 | 
            +
                  lines.sort
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              # Creates the table to store requests in.
         | 
| 13 | 
            +
              def self.create_table!
         | 
| 14 | 
            +
                unless database.connection.table_exists?(:requests)
         | 
| 15 | 
            +
                  database.connection.create_table(:requests) do |t|
         | 
| 16 | 
            +
                    t.column :first_lineno, :integer
         | 
| 17 | 
            +
                    t.column :last_lineno,  :integer
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            class RequestLogAnalyzer::Database::Source < RequestLogAnalyzer::Database::Base
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              def self.create_table!
         | 
| 4 | 
            +
                unless database.connection.table_exists?(:sources)
         | 
| 5 | 
            +
                  database.connection.create_table(:sources) do |t|
         | 
| 6 | 
            +
                    t.column :filename, :string
         | 
| 7 | 
            +
                    t.column :mtime,    :datetime
         | 
| 8 | 
            +
                    t.column :filesize, :integer
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            class RequestLogAnalyzer::Database::Warning < RequestLogAnalyzer::Database::Base
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              def self.create_table!
         | 
| 4 | 
            +
                unless database.connection.table_exists?(:warnings)
         | 
| 5 | 
            +
                  database.connection.create_table(:warnings) do |t|
         | 
| 6 | 
            +
                    t.column  :warning_type, :string, :limit => 30, :null => false
         | 
| 7 | 
            +
                    t.column  :message, :string
         | 
| 8 | 
            +
                    t.column  :source_id, :integer
         | 
| 9 | 
            +
                    t.column  :lineno, :integer
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            end
         | 
| @@ -42,19 +42,7 @@ module RequestLogAnalyzer::FileFormat | |
| 42 42 | 
             
                raise "Invalid FileFormat class" unless klass.kind_of?(Class) && klass.ancestors.include?(RequestLogAnalyzer::FileFormat::Base)
         | 
| 43 43 |  | 
| 44 44 | 
             
                @current_file_format = klass.create(*args) # return an instance of the class
         | 
| 45 | 
            -
              end | 
| 46 | 
            -
              
         | 
| 47 | 
            -
              # Makes classes aware of a file format by registering the file_format variable
         | 
| 48 | 
            -
              module Awareness
         | 
| 49 | 
            -
                
         | 
| 50 | 
            -
                def self.included(base)
         | 
| 51 | 
            -
                  base.send(:attr_reader, :file_format)
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
                
         | 
| 54 | 
            -
                def register_file_format(format)
         | 
| 55 | 
            -
                  @file_format = format
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
              end  
         | 
| 45 | 
            +
              end
         | 
| 58 46 |  | 
| 59 47 | 
             
              # Base class for all log file format definitions. This class provides functions for subclasses to 
         | 
| 60 48 | 
             
              # define their LineDefinitions and to define a summary report.
         | 
| @@ -48,8 +48,7 @@ module RequestLogAnalyzer::FileFormat | |
| 48 48 | 
             
                  # Do not use DateTime.parse, but parse the timestamp ourselves to return a integer
         | 
| 49 49 | 
             
                  # to speed up parsing.
         | 
| 50 50 | 
             
                  def convert_timestamp(value, definition)
         | 
| 51 | 
            -
                     | 
| 52 | 
            -
                    "#{d[2]}#{MONTHS[d[1]]}#{d[0]}#{d[3]}#{d[4]}#{d[5]}".to_i
         | 
| 51 | 
            +
                    "#{value[7,4]}#{MONTHS[value[3,3]]}#{value[0,2]}#{value[12,2]}#{value[15,2]}#{value[18,2]}".to_i
         | 
| 53 52 | 
             
                  end
         | 
| 54 53 |  | 
| 55 54 | 
             
                  # Make sure that the string '-' is parsed as a nil value.
         | 
| @@ -92,18 +92,13 @@ module RequestLogAnalyzer::FileFormat | |
| 92 92 |  | 
| 93 93 | 
             
                  analyze.frequency :category => :http_method, :amount => 20, :title => "HTTP methods"  if line_definition.captures?(:http_method)
         | 
| 94 94 | 
             
                  analyze.frequency :category => :http_status, :amount => 20, :title => "HTTP statuses" if line_definition.captures?(:http_status)
         | 
| 95 | 
            -
                  analyze.frequency :category =>  | 
| 95 | 
            +
                  analyze.frequency :category => lambda { |r| r.category }, :amount => 20, :title => "Most popular URIs"    if line_definition.captures?(:path)
         | 
| 96 96 |  | 
| 97 97 | 
             
                  analyze.frequency :category => :user_agent, :amount => 20, :title => "User agents"    if line_definition.captures?(:user_agent)
         | 
| 98 98 | 
             
                  analyze.frequency :category => :referer,    :amount => 20, :title => "Referers"       if line_definition.captures?(:referer)
         | 
| 99 99 |  | 
| 100 | 
            -
                   | 
| 101 | 
            -
             | 
| 102 | 
            -
                  end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                  if line_definition.captures?(:path) && line_definition.captures?(:bytes_sent)
         | 
| 105 | 
            -
                    analyze.traffic :traffic => :bytes_sent, :category => :path , :title => 'Traffic'
         | 
| 106 | 
            -
                  end
         | 
| 100 | 
            +
                  analyze.duration :duration => :duration,  :category => lambda { |r| r.category }, :title => 'Request duration' if line_definition.captures?(:duration)
         | 
| 101 | 
            +
                  analyze.traffic  :traffic => :bytes_sent, :category => lambda { |r| r.category }, :title => 'Traffic'          if line_definition.captures?(:bytes_sent)
         | 
| 107 102 |  | 
| 108 103 | 
             
                  return analyze.trackers
         | 
| 109 104 | 
             
                end
         | 
| @@ -111,14 +106,17 @@ module RequestLogAnalyzer::FileFormat | |
| 111 106 | 
             
                # Define a custom Request class for the Apache file format to speed up timestamp handling.
         | 
| 112 107 | 
             
                class Request < RequestLogAnalyzer::Request
         | 
| 113 108 |  | 
| 109 | 
            +
                  def category
         | 
| 110 | 
            +
                    first(:path)
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
                  
         | 
| 114 113 | 
             
                  MONTHS = {'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06',
         | 
| 115 114 | 
             
                            'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' }
         | 
| 116 115 |  | 
| 117 116 | 
             
                  # Do not use DateTime.parse, but parse the timestamp ourselves to return a integer
         | 
| 118 117 | 
             
                  # to speed up parsing.
         | 
| 119 118 | 
             
                  def convert_timestamp(value, definition)
         | 
| 120 | 
            -
                     | 
| 121 | 
            -
                    "#{d[2]}#{MONTHS[d[1]]}#{d[0]}#{d[3]}#{d[4]}#{d[5]}".to_i
         | 
| 119 | 
            +
                    "#{value[7,4]}#{MONTHS[value[3,3]]}#{value[0,2]}#{value[12,2]}#{value[15,2]}#{value[18,2]}".to_i
         | 
| 122 120 | 
             
                  end
         | 
| 123 121 |  | 
| 124 122 | 
             
                  # This function can be overridden to rewrite the path for better categorization in the
         | 
| @@ -1,11 +1,14 @@ | |
| 1 1 | 
             
            module RequestLogAnalyzer::FileFormat
         | 
| 2 2 |  | 
| 3 | 
            +
              # The Merb file format parses the request header with the timestamp, the params line
         | 
| 4 | 
            +
              # with the most important request information and the durations line which contains
         | 
| 5 | 
            +
              # the different request durations that can be used for analysis.
         | 
| 3 6 | 
             
              class Merb < Base
         | 
| 4 7 |  | 
| 5 8 | 
             
                # ~ Started request handling: Fri Aug 29 11:10:23 +0200 2008
         | 
| 6 9 | 
             
                line_definition :started do |line|
         | 
| 7 10 | 
             
                  line.header = true
         | 
| 8 | 
            -
                  line.teaser = /Started/
         | 
| 11 | 
            +
                  # line.teaser = /Started/
         | 
| 9 12 | 
             
                  line.regexp = /Started request handling\:\ (.+)/
         | 
| 10 13 | 
             
                  line.captures << { :name => :timestamp, :type => :timestamp }
         | 
| 11 14 | 
             
                end    
         | 
| @@ -13,7 +16,7 @@ module RequestLogAnalyzer::FileFormat | |
| 13 16 | 
             
                # ~ Params: {"action"=>"create", "controller"=>"session"}
         | 
| 14 17 | 
             
                # ~ Params: {"_method"=>"delete", "authenticity_token"=>"[FILTERED]", "action"=>"d}
         | 
| 15 18 | 
             
                line_definition :params do |line|
         | 
| 16 | 
            -
                  line.teaser = /Params/
         | 
| 19 | 
            +
                  # line.teaser = /Params/
         | 
| 17 20 | 
             
                  line.regexp = /Params\:\ (\{.+\})/
         | 
| 18 21 | 
             
                  line.captures << { :name => :params, :type => :eval, :provides => { 
         | 
| 19 22 | 
             
                        :namespace => :string, :controller => :string, :action => :string, :format => :string, :method => :string } }
         | 
| @@ -36,15 +39,28 @@ module RequestLogAnalyzer::FileFormat | |
| 36 39 | 
             
                end
         | 
| 37 40 |  | 
| 38 41 | 
             
                report do |analyze|
         | 
| 39 | 
            -
                   | 
| 42 | 
            +
                  
         | 
| 43 | 
            +
                  analyze.timespan
         | 
| 44 | 
            +
                  analyze.hourly_spread
         | 
| 45 | 
            +
             | 
| 40 46 | 
             
                  analyze.frequency :category => REQUEST_CATEGORIZER, :amount => 20, :title => "Top 20 by hits"
         | 
| 41 | 
            -
                  analyze.hourly_spread :line_type => :started
         | 
| 42 47 | 
             
                  analyze.duration :dispatch_time, :category => REQUEST_CATEGORIZER, :title => 'Request dispatch duration'
         | 
| 48 | 
            +
                  
         | 
| 43 49 | 
             
                  # analyze.duration :action_time, :category => REQUEST_CATEGORIZER, :title => 'Request action duration'
         | 
| 44 50 | 
             
                  # analyze.duration :after_filters_time, :category => REQUEST_CATEGORIZER, :title => 'Request after_filter duration'
         | 
| 45 51 | 
             
                  # analyze.duration :before_filters_time, :category => REQUEST_CATEGORIZER, :title => 'Request before_filter duration'
         | 
| 46 52 | 
             
                end
         | 
| 47 | 
            -
             | 
| 53 | 
            +
             | 
| 54 | 
            +
                class Request < RequestLogAnalyzer::Request
         | 
| 55 | 
            +
                  
         | 
| 56 | 
            +
                  MONTHS = {'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06',
         | 
| 57 | 
            +
                            'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' }
         | 
| 58 | 
            +
                  
         | 
| 59 | 
            +
                  # Speed up timestamp conversion
         | 
| 60 | 
            +
                  def convert_timestamp(value, definition)
         | 
| 61 | 
            +
                    "#{value[26,4]}#{MONTHS[value[4,3]]}#{value[8,2]}#{value[11,2]}#{value[14,2]}#{value[17,2]}".to_i
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 48 64 | 
             
              end
         | 
| 49 65 |  | 
| 50 66 | 
             
            end
         |