request-log-analyzer 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README.rdoc +4 -3
  2. data/bin/request-log-analyzer +4 -5
  3. data/lib/cli/command_line_arguments.rb +2 -2
  4. data/lib/request_log_analyzer.rb +28 -6
  5. data/lib/request_log_analyzer/{aggregator/base.rb → aggregator.rb} +5 -1
  6. data/lib/request_log_analyzer/aggregator/summarizer.rb +2 -3
  7. data/lib/request_log_analyzer/controller.rb +11 -16
  8. data/lib/request_log_analyzer/file_format.rb +71 -38
  9. data/lib/request_log_analyzer/file_format/merb.rb +32 -26
  10. data/lib/request_log_analyzer/file_format/rails.rb +73 -71
  11. data/lib/request_log_analyzer/file_format/rails_development.rb +93 -95
  12. data/lib/request_log_analyzer/filter.rb +38 -0
  13. data/lib/request_log_analyzer/filter/anonimize.rb +1 -1
  14. data/lib/request_log_analyzer/line_definition.rb +1 -1
  15. data/lib/request_log_analyzer/output.rb +6 -8
  16. data/lib/request_log_analyzer/output/fixed_width.rb +133 -117
  17. data/lib/request_log_analyzer/output/html.rb +138 -60
  18. data/lib/request_log_analyzer/request.rb +3 -1
  19. data/lib/request_log_analyzer/{source/base.rb → source.rb} +5 -0
  20. data/lib/request_log_analyzer/source/{log_file.rb → log_parser.rb} +15 -6
  21. data/lib/request_log_analyzer/tracker.rb +58 -0
  22. data/lib/request_log_analyzer/tracker/category.rb +7 -8
  23. data/lib/request_log_analyzer/tracker/duration.rb +15 -12
  24. data/lib/request_log_analyzer/tracker/hourly_spread.rb +8 -8
  25. data/lib/request_log_analyzer/tracker/timespan.rb +10 -10
  26. data/spec/controller_spec.rb +5 -4
  27. data/spec/database_inserter_spec.rb +5 -8
  28. data/spec/file_format_spec.rb +2 -2
  29. data/spec/file_formats/spec_format.rb +2 -1
  30. data/spec/filter_spec.rb +0 -3
  31. data/spec/log_parser_spec.rb +6 -6
  32. data/spec/merb_format_spec.rb +38 -38
  33. data/spec/rails_format_spec.rb +2 -2
  34. data/spec/request_spec.rb +2 -2
  35. data/spec/spec_helper.rb +3 -37
  36. data/tasks/github-gem.rake +2 -1
  37. metadata +7 -8
  38. data/lib/request_log_analyzer/filter/base.rb +0 -32
  39. data/lib/request_log_analyzer/log_parser.rb +0 -173
  40. data/lib/request_log_analyzer/tracker/base.rb +0 -54
@@ -1,32 +0,0 @@
1
- module RequestLogAnalyzer
2
- module Filter
3
- # Base filter class used to filter input requests.
4
- # All filters should interit from this base.
5
- class Base
6
-
7
- include RequestLogAnalyzer::FileFormat::Awareness
8
-
9
- attr_reader :log_parser
10
- attr_reader :options
11
-
12
- # Initializer
13
- # <tt>format</tt> The file format
14
- # <tt>options</tt> Are passed to the filters.
15
- def initialize(format, options = {})
16
- @options = options
17
- register_file_format(format)
18
- end
19
-
20
- # Initialize the filter
21
- def prepare
22
- end
23
-
24
- # Return the request if the request should be kept.
25
- # Return nil otherwise.
26
- def filter(request)
27
- return nil unless request
28
- return request
29
- end
30
- end
31
- end
32
- end
@@ -1,173 +0,0 @@
1
- module RequestLogAnalyzer
2
-
3
- # The LogParser class reads log data from a given source and uses a file format definition
4
- # to parse all relevent information about requests from the file. A FileFormat module should
5
- # be provided that contains the definitions of the lines that occur in the log data.
6
- #
7
- # De order in which lines occur is used to combine lines to a single request. If these lines
8
- # are mixed, requests cannot be combined properly. This can be the case if data is written to
9
- # the log file simultaneously by different mongrel processes. This problem is detected by the
10
- # parser, but the requests that are mixed up cannot be parsed. It will emit warnings when this
11
- # occurs.
12
- class LogParser
13
-
14
- include RequestLogAnalyzer::FileFormat::Awareness
15
-
16
- # A hash of options
17
- attr_reader :options
18
-
19
- # The current Request object that is being parsed
20
- attr_reader :current_request
21
-
22
- # The total number of parsed lines
23
- attr_reader :parsed_lines
24
-
25
- # The total number of parsed requests.
26
- attr_reader :parsed_requests
27
-
28
- # The number of skipped requests because of date constraints
29
- attr_reader :skipped_requests
30
-
31
- # Initializes the parser instance.
32
- # It will apply the language specific FileFormat module to this instance. It will use the line
33
- # definitions in this module to parse any input.
34
- def initialize(format, options = {})
35
- @line_definitions = {}
36
- @options = options
37
- @parsed_lines = 0
38
- @parsed_requests = 0
39
- @skipped_requests = 0
40
-
41
- @current_io = nil
42
-
43
- # install the file format module (see RequestLogAnalyzer::FileFormat)
44
- # and register all the line definitions to the parser
45
- self.register_file_format(format)
46
- end
47
-
48
- # Parses a list of consequent files of the same format
49
- def parse_files(files, options = {}, &block)
50
- files.each { |file| parse_file(file, options, &block) }
51
- end
52
-
53
- # Parses a file.
54
- # Creates an IO stream for the provided file, and sends it to parse_io for further handling
55
- def parse_file(file, options = {}, &block)
56
- @progress_handler.call(:started, file) if @progress_handler
57
- File.open(file, 'r') { |f| parse_io(f, options, &block) }
58
- @progress_handler.call(:finished, file) if @progress_handler
59
- end
60
-
61
- def parse_stream(stream, options = {}, &block)
62
- parse_io(stream, options, &block)
63
- end
64
-
65
- # Finds a log line and then parses the information in the line.
66
- # Yields a hash containing the information found.
67
- # <tt>*line_types</tt> The log line types to look for (defaults to LOG_LINES.keys).
68
- # Yeilds a Hash when it encounters a chunk of information.
69
- def parse_io(io, options = {}, &block)
70
-
71
- # parse every line type by default
72
- line_types = options[:line_types] || file_format.line_definitions.keys
73
-
74
- # check whether all provided line types are valid
75
- unknown = line_types.reject { |line_type| file_format.line_definitions.has_key?(line_type) }
76
- raise "Unknown line types: #{unknown.join(', ')}" unless unknown.empty?
77
-
78
- @current_io = io
79
- @current_io.each_line do |line|
80
-
81
- @progress_handler.call(:progress, @current_io.pos) if @progress_handler && @current_io.kind_of?(File)
82
-
83
- request_data = nil
84
- line_types.each do |line_type|
85
- line_type_definition = file_format.line_definitions[line_type]
86
- break if request_data = line_type_definition.matches(line, @current_io.lineno, self)
87
- end
88
-
89
- if request_data
90
- @parsed_lines += 1
91
- update_current_request(request_data, &block)
92
- end
93
- end
94
-
95
- warn(:unfinished_request_on_eof, "End of file reached, but last request was not completed!") unless @current_request.nil?
96
-
97
- @current_io = nil
98
- end
99
-
100
- # Add a block to this method to install a progress handler while parsing
101
- def progress=(proc)
102
- @progress_handler = proc
103
- end
104
-
105
- # Add a block to this method to install a warning handler while parsing
106
- def warning=(proc)
107
- @warning_handler = proc
108
- end
109
-
110
- # This method is called by the parser if it encounteres any problems.
111
- # It will call the warning handler. The default controller will pass all warnings to every
112
- # aggregator that is registered and running
113
- def warn(type, message)
114
- @warning_handler.call(type, message, @current_io.lineno) if @warning_handler
115
- end
116
-
117
- protected
118
-
119
- # Combines the different lines of a request into a single Request object. It will start a
120
- # new request when a header line is encountered en will emit the request when a footer line
121
- # is encountered.
122
- #
123
- # - Every line that is parsed before a header line is ignored as it cannot be included in
124
- # any request. It will emit a :no_current_request warning.
125
- # - A header line that is parsed before a request is closed by a footer line, is a sign of
126
- # an unprpertly ordered file. All data that is gathered for the request until then is
127
- # discarded, the next request is ignored as well and a :unclosed_request warning is
128
- # emitted.
129
- def update_current_request(request_data, &block)
130
- if header_line?(request_data)
131
- unless @current_request.nil?
132
- if options[:assume_correct_order]
133
- handle_request(@current_request, &block)
134
- @current_request = RequestLogAnalyzer::Request.create(@file_format, request_data)
135
- else
136
- warn(:unclosed_request, "Encountered header line, but previous request was not closed!")
137
- @current_request = nil # remove all data that was parsed, skip next request as well.
138
- end
139
- else
140
- @current_request = RequestLogAnalyzer::Request.create(@file_format, request_data)
141
- end
142
- else
143
- unless @current_request.nil?
144
- @current_request << request_data
145
- if footer_line?(request_data)
146
- handle_request(@current_request, &block)
147
- @current_request = nil
148
- end
149
- else
150
- warn(:no_current_request, "Parsebale line found outside of a request!")
151
- end
152
- end
153
- end
154
-
155
- # Handles the parsed request by calling the request handler.
156
- # The default controller will send the request to every running aggegator.
157
- def handle_request(request, &block)
158
- @parsed_requests += 1
159
- accepted = block_given? ? yield(request) : true
160
- @skipped_requests += 1 if !accepted
161
- end
162
-
163
- # Checks whether a given line hash is a header line.
164
- def header_line?(hash)
165
- file_format.line_definitions[hash[:line_type]].header
166
- end
167
-
168
- # Checks whether a given line hash is a footer line.
169
- def footer_line?(hash)
170
- file_format.line_definitions[hash[:line_type]].footer
171
- end
172
- end
173
- end
@@ -1,54 +0,0 @@
1
- module RequestLogAnalyzer
2
- module Tracker
3
-
4
- # Base tracker. All other trackers inherit from this class
5
- #
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
- # * <tt>:output</tt> Direct output here (defaults to STDOUT)
10
- #
11
- # For example :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }
12
- class Base
13
-
14
- attr_reader :options
15
-
16
- def initialize(options ={})
17
- @options = options
18
- end
19
-
20
- def prepare
21
- end
22
-
23
- def update(request)
24
- end
25
-
26
- def finalize
27
- end
28
-
29
- def should_update?(request)
30
- return false if options[:line_type] && !request.has_line_type?(options[:line_type])
31
-
32
- if options[:if].kind_of?(Symbol)
33
- return false unless request[options[:if]]
34
- elsif options[:if].respond_to?(:call)
35
- return false unless options[:if].call(request)
36
- end
37
-
38
- if options[:unless].kind_of?(Symbol)
39
- return false if request[options[:unless]]
40
- elsif options[:unless].respond_to?(:call)
41
- return false if options[:unless].call(request)
42
- end
43
-
44
- return true
45
- end
46
-
47
- def report(output)
48
- output << self.inspect
49
- output << "\n"
50
- end
51
-
52
- end
53
- end
54
- end