request-log-analyzer 1.10.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/bin/request-log-analyzer +0 -1
  2. data/lib/request_log_analyzer.rb +15 -29
  3. data/lib/request_log_analyzer/aggregator.rb +5 -5
  4. data/lib/request_log_analyzer/aggregator/database_inserter.rb +2 -1
  5. data/lib/request_log_analyzer/controller.rb +0 -3
  6. data/lib/request_log_analyzer/database.rb +6 -7
  7. data/lib/request_log_analyzer/file_format.rb +42 -13
  8. data/lib/request_log_analyzer/file_format/apache.rb +1 -1
  9. data/lib/request_log_analyzer/file_format/delayed_job2.rb +2 -2
  10. data/lib/request_log_analyzer/file_format/delayed_job21.rb +2 -2
  11. data/lib/request_log_analyzer/file_format/haproxy.rb +107 -13
  12. data/lib/request_log_analyzer/file_format/mysql.rb +5 -5
  13. data/lib/request_log_analyzer/file_format/rails3.rb +7 -0
  14. data/lib/request_log_analyzer/filter.rb +4 -5
  15. data/lib/request_log_analyzer/line_definition.rb +6 -4
  16. data/lib/request_log_analyzer/output.rb +3 -5
  17. data/lib/request_log_analyzer/source.rb +3 -4
  18. data/lib/request_log_analyzer/source/log_parser.rb +56 -4
  19. data/lib/request_log_analyzer/tracker.rb +8 -8
  20. data/request-log-analyzer.gemspec +3 -3
  21. data/spec/fixtures/mysql_slow_query.log +0 -1
  22. data/spec/integration/command_line_usage_spec.rb +0 -5
  23. data/spec/lib/helpers.rb +2 -2
  24. data/spec/lib/matchers.rb +38 -7
  25. data/spec/lib/mocks.rb +1 -5
  26. data/spec/unit/database/base_class_spec.rb +1 -0
  27. data/spec/unit/file_format/amazon_s3_format_spec.rb +58 -55
  28. data/spec/unit/file_format/apache_format_spec.rb +74 -162
  29. data/spec/unit/file_format/common_regular_expressions_spec.rb +51 -26
  30. data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -31
  31. data/spec/unit/file_format/delayed_job2_format_spec.rb +27 -32
  32. data/spec/unit/file_format/delayed_job_format_spec.rb +44 -63
  33. data/spec/unit/file_format/haproxy_format_spec.rb +69 -71
  34. data/spec/unit/file_format/line_definition_spec.rb +26 -33
  35. data/spec/unit/file_format/merb_format_spec.rb +22 -37
  36. data/spec/unit/file_format/mysql_format_spec.rb +80 -123
  37. data/spec/unit/file_format/oink_format_spec.rb +29 -61
  38. data/spec/unit/file_format/postgresql_format_spec.rb +2 -4
  39. data/spec/unit/file_format/rack_format_spec.rb +49 -44
  40. data/spec/unit/file_format/rails3_format_spec.rb +17 -20
  41. data/spec/unit/file_format/rails_format_spec.rb +52 -68
  42. data/spec/unit/file_format/w3c_format_spec.rb +40 -39
  43. data/spec/unit/source/log_parser_spec.rb +1 -1
  44. metadata +4 -7
  45. data/lib/mixins/gets_memory_protection.rb +0 -80
  46. data/lib/request_log_analyzer/output/fancy_html.rb +0 -44
  47. data/lib/request_log_analyzer/source/database_loader.rb +0 -87
@@ -58,7 +58,6 @@ begin
58
58
 
59
59
  command_line.switch(:debug)
60
60
  command_line.switch(:no_progress)
61
- command_line.switch(:gets_memory_protection)
62
61
  command_line.switch(:silent)
63
62
 
64
63
  command_line.minimum_parameters = 1
@@ -10,36 +10,10 @@ Encoding.default_external = 'binary' if defined? Encoding and Encoding.respond_t
10
10
  # The {RequestLogAnalyzer::VERSION} constant can be used to determine what version of request-log-analyzer
11
11
  # is running.
12
12
  module RequestLogAnalyzer
13
-
13
+
14
14
  # The current version of request-log-analyzer.
15
15
  # Do not change the value by hand; it will be updated automatically by the gem release script.
16
- VERSION = "1.10.1"
17
-
18
-
19
- autoload :Controller, 'request_log_analyzer/controller'
20
- autoload :Aggregator, 'request_log_analyzer/aggregator'
21
- autoload :Database, 'request_log_analyzer/database'
22
- autoload :FileFormat, 'request_log_analyzer/file_format'
23
- autoload :Filter, 'request_log_analyzer/filter'
24
- autoload :LineDefinition, 'request_log_analyzer/line_definition'
25
- autoload :LogProcessor, 'request_log_analyzer/log_processor'
26
- autoload :Mailer, 'request_log_analyzer/mailer'
27
- autoload :Output, 'request_log_analyzer/output'
28
- autoload :Request, 'request_log_analyzer/request'
29
- autoload :Source, 'request_log_analyzer/source'
30
- autoload :Tracker, 'request_log_analyzer/tracker'
31
-
32
- # Loads constants that reside in the RequestLogAnalyzer tree using the constant name and its base
33
- # constant to determine the filename.
34
- # @param [Module] base The base constant to load the constant from. This should be <tt>Foo</tt> when
35
- # the constant <tt>Foo::Bar</tt> is being loaded.
36
- # @param [Symbol] const The constant to load from the base constant as a string or symbol. This
37
- # should be <tt>"Bar"<tt> or <tt>:Bar</tt> when the constant <tt>Foo::Bar</tt> is being loaded.
38
- # @return [Module] The loaded module, nil if it was not found on the expected location.
39
- def self.load_default_class_file(base, const)
40
- require "#{to_underscore("#{base.name}::#{const}")}"
41
- base.const_get(const) if base.const_defined?(const)
42
- end
16
+ VERSION = "1.11.0"
43
17
 
44
18
  # Convert a string/symbol in camelcase ({RequestLogAnalyzer::Controller}) to underscores
45
19
  # (<tt>request_log_analyzer/controller</tt>). This function can be used to load the file (using
@@ -55,9 +29,21 @@ module RequestLogAnalyzer
55
29
  # ({RequestLogAnalyzer::Controller}). This can be used to find the class that is defined in a given
56
30
  # filename.
57
31
  #
58
- # @param [#to_s] str The string-like to convert in the following format: <tt>module_name/class_name</tt>.
32
+ # @param [#to_s] str The string-like to convert in the f`ollowing format: <tt>module_name/class_name</tt>.
59
33
  # @return [String] The input string converted to camelcase form.
60
34
  def self.to_camelcase(str)
61
35
  str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
62
36
  end
63
37
  end
38
+
39
+ require 'request_log_analyzer/controller'
40
+ require 'request_log_analyzer/aggregator'
41
+ require 'request_log_analyzer/file_format'
42
+ require 'request_log_analyzer/filter'
43
+ require 'request_log_analyzer/line_definition'
44
+ require 'request_log_analyzer/log_processor'
45
+ require 'request_log_analyzer/mailer'
46
+ require 'request_log_analyzer/output'
47
+ require 'request_log_analyzer/request'
48
+ require 'request_log_analyzer/source'
49
+ require 'request_log_analyzer/tracker'
@@ -1,9 +1,5 @@
1
1
  module RequestLogAnalyzer::Aggregator
2
2
 
3
- autoload :Echo, 'request_log_analyzer/aggregator/echo'
4
- autoload :Summarizer, 'request_log_analyzer/aggregator/summarizer'
5
- autoload :DatabaseInserter, 'request_log_analyzer/aggregator/database_inserter'
6
-
7
3
  # The base class of an aggregator. This class provides the interface to which
8
4
  # every aggregator should comply (by simply subclassing this class).
9
5
  class Base
@@ -46,4 +42,8 @@ module RequestLogAnalyzer::Aggregator
46
42
  end
47
43
 
48
44
  end
49
- end
45
+ end
46
+
47
+ require 'request_log_analyzer/aggregator/echo'
48
+ require 'request_log_analyzer/aggregator/summarizer'
49
+ require 'request_log_analyzer/aggregator/database_inserter'
@@ -1,4 +1,3 @@
1
-
2
1
  module RequestLogAnalyzer::Aggregator
3
2
 
4
3
  # The database aggregator will create an SQLite3 database with all parsed request information.
@@ -19,6 +18,8 @@ module RequestLogAnalyzer::Aggregator
19
18
  # Establishes a connection to the database and creates the necessary database schema for the
20
19
  # current file format
21
20
  def prepare
21
+ require 'request_log_analyzer/database'
22
+
22
23
  @sources = {}
23
24
  @database = RequestLogAnalyzer::Database.new(options[:database])
24
25
  @database.file_format = source.file_format
@@ -21,8 +21,6 @@ module RequestLogAnalyzer
21
21
  # <tt>arguments<tt> A CommandLine::Arguments hash containing parsed commandline parameters.
22
22
  def self.build_from_arguments(arguments)
23
23
 
24
- require 'mixins/gets_memory_protection' if arguments[:gets_memory_protection]
25
-
26
24
  options = {}
27
25
 
28
26
  # Copy fields
@@ -58,7 +56,6 @@ module RequestLogAnalyzer
58
56
 
59
57
  # Handle output format casing
60
58
  if options[:output].class == String
61
- options[:output] = 'FancyHTML' if options[:output] =~ /^fancy_?html$/i
62
59
  options[:output] = 'HTML' if options[:output] =~ /^html$/i
63
60
  options[:output] = 'FixedWidth' if options[:output] =~ /^fixed_?width$/i
64
61
  end
@@ -3,12 +3,7 @@ require 'active_record'
3
3
 
4
4
  class RequestLogAnalyzer::Database
5
5
 
6
- autoload :Connection, 'request_log_analyzer/database/connection'
7
- autoload :Base, 'request_log_analyzer/database/base'
8
- autoload :Request, 'request_log_analyzer/database/request'
9
- autoload :Source, 'request_log_analyzer/database/source'
10
- autoload :Warning, 'request_log_analyzer/database/warning'
11
-
6
+ require 'request_log_analyzer/database/connection'
12
7
  include RequestLogAnalyzer::Database::Connection
13
8
 
14
9
  attr_accessor :file_format
@@ -100,5 +95,9 @@ class RequestLogAnalyzer::Database
100
95
  end
101
96
  end
102
97
  end
103
-
104
98
  end
99
+
100
+ require 'request_log_analyzer/database/base'
101
+ require 'request_log_analyzer/database/request'
102
+ require 'request_log_analyzer/database/source'
103
+ require 'request_log_analyzer/database/warning'
@@ -121,6 +121,18 @@ module RequestLogAnalyzer::FileFormat
121
121
  'Z' => '(?:[+-]\d{4}|[A-Z]{3,4})',
122
122
  '%' => '%'
123
123
  }
124
+
125
+ # Creates a regular expression to match a hostname
126
+ def hostname(blank = false)
127
+ regexp = /(?:(?:[a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*(?:[A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])/
128
+ add_blank_option(regexp, blank)
129
+ end
130
+
131
+ # Creates a regular expression to match a hostname or ip address
132
+ def hostname_or_ip_address(blank = false)
133
+ regexp = Regexp.union(hostname, ip_address)
134
+ add_blank_option(regexp, blank)
135
+ end
124
136
 
125
137
  # Create a regular expression for a timestamp, generated by a strftime call.
126
138
  # Provide the format string to construct a matching regular expression.
@@ -139,12 +151,7 @@ module RequestLogAnalyzer::FileFormat
139
151
  end
140
152
  end
141
153
 
142
- regexp = Regexp.new(regexp)
143
- return case blank
144
- when String then Regexp.union(regexp, Regexp.new(Regexp.quote(blank)))
145
- when true then Regexp.union(regexp, //)
146
- else regexp
147
- end
154
+ add_blank_option(Regexp.new(regexp), blank)
148
155
  end
149
156
 
150
157
  # Construct a regular expression to parse IPv4 and IPv6 addresses.
@@ -162,12 +169,22 @@ module RequestLogAnalyzer::FileFormat
162
169
  ipv6_regex_compressed_hex_4_dec = /(?:(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::(?:(?:[0-9A-Fa-f]{1,4}:)*)#{ipv4_regexp}/
163
170
  ipv6_regexp = Regexp.union(ipv6_regex_8_hex, ipv6_regex_compressed_hex, ipv6_regex_6_hex_4_dec, ipv6_regex_compressed_hex_4_dec)
164
171
 
165
- # Allow the field to be blank if this option is given. This can be true to
166
- # allow an empty string or a string alternative for the nil value.
167
- ip_regexp = case blank
168
- when String then Regexp.union(ipv4_regexp, ipv6_regexp, Regexp.new(Regexp.quote(blank)))
169
- when true then Regexp.union(ipv4_regexp, ipv6_regexp, //)
170
- else Regexp.union(ipv4_regexp, ipv6_regexp)
172
+ add_blank_option(Regexp.union(ipv4_regexp, ipv6_regexp), blank)
173
+ end
174
+
175
+ def anchored(regexp)
176
+ /^#{regexp}$/
177
+ end
178
+
179
+ protected
180
+
181
+ # Allow the field to be blank if this option is given. This can be true to
182
+ # allow an empty string or a string alternative for the nil value.
183
+ def add_blank_option(regexp, blank)
184
+ case blank
185
+ when String; Regexp.union(regexp, Regexp.new(Regexp.quote(blank)))
186
+ when true; Regexp.union(regexp, //)
187
+ else regexp
171
188
  end
172
189
  end
173
190
  end
@@ -260,9 +277,12 @@ module RequestLogAnalyzer::FileFormat
260
277
  end
261
278
 
262
279
  # Checks whether the file format is valid so it can be safely used with RLA.
263
- def valid?
280
+ def well_formed?
264
281
  valid_line_definitions? && valid_request_class?
265
282
  end
283
+
284
+ alias_method :valid?, :well_formed?
285
+
266
286
 
267
287
  # Checks whether the line definitions form a valid language.
268
288
  # A file format should have at least a header and a footer line type
@@ -294,5 +314,14 @@ module RequestLogAnalyzer::FileFormat
294
314
 
295
315
  return nil
296
316
  end
317
+
318
+ # Returns the max line length for this file format if any.
319
+ def max_line_length
320
+ self.class.const_get(MAX_LINE_LENGTH) if self.class.const_defined?(:MAX_LINE_LENGTH)
321
+ end
322
+
323
+ def line_divider
324
+ self.class.const_get(LINE_DIVIDER) if self.class.const_defined?(:LINE_DIVIDER)
325
+ end
297
326
  end
298
327
  end
@@ -31,7 +31,7 @@ module RequestLogAnalyzer::FileFormat
31
31
  # A hash that defines how the log format directives should be parsed.
32
32
  LOG_DIRECTIVES = {
33
33
  '%' => { nil => { :regexp => '%', :captures => [] } },
34
- 'h' => { nil => { :regexp => '([A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+)', :captures => [{:name => :remote_host, :type => :string}] } },
34
+ 'h' => { nil => { :regexp => "(#{hostname_or_ip_address})", :captures => [{:name => :remote_host, :type => :string}] } },
35
35
  'a' => { nil => { :regexp => "(#{ip_address})", :captures => [{:name => :remote_ip, :type => :string}] } },
36
36
  'b' => { nil => { :regexp => '(\d+|-)', :captures => [{:name => :bytes_sent, :type => :traffic}] } },
37
37
  'c' => { nil => { :regexp => '(\+|\-|\X)', :captures => [{:name => :connection_status, :type => :integer}] } },
@@ -8,7 +8,7 @@ module RequestLogAnalyzer::FileFormat
8
8
 
9
9
  line_definition :job_lock do |line|
10
10
  line.header = true
11
- line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \* \[Worker\(\S+ host:(\S+) pid:(\d+)\)\] acquired lock on (\S+)/
11
+ line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \* \[Worker\(\S+ host:(#{hostname_or_ip_address}) pid:(\d+)\)\] acquired lock on (\S+)/
12
12
 
13
13
  line.capture(:timestamp).as(:timestamp)
14
14
  line.capture(:host)
@@ -18,7 +18,7 @@ module RequestLogAnalyzer::FileFormat
18
18
 
19
19
  line_definition :job_completed do |line|
20
20
  line.footer = true
21
- line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \* \[JOB\] \S+ host:(\S+) pid:(\d+) completed after (\d+\.\d+)/
21
+ line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \* \[JOB\] \S+ host:(#{hostname_or_ip_address}) pid:(\d+) completed after (\d+\.\d+)/
22
22
  line.capture(:timestamp).as(:timestamp)
23
23
  line.capture(:host)
24
24
  line.capture(:pid).as(:integer)
@@ -8,7 +8,7 @@ module RequestLogAnalyzer::FileFormat
8
8
 
9
9
  line_definition :job_lock do |line|
10
10
  line.header = true
11
- line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \[Worker\(\S+ host:(\S+) pid:(\d+)\)\] acquired lock on (\S+)/
11
+ line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \[Worker\(\S+ host:(#{hostname_or_ip_address}) pid:(\d+)\)\] acquired lock on (\S+)/
12
12
 
13
13
  line.capture(:timestamp).as(:timestamp)
14
14
  line.capture(:host)
@@ -18,7 +18,7 @@ module RequestLogAnalyzer::FileFormat
18
18
 
19
19
  line_definition :job_completed do |line|
20
20
  line.footer = true
21
- line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \[Worker\(\S+ host:(\S+) pid:(\d+)\)\] (\S+) completed after (\d+\.\d+)/
21
+ line.regexp = /(#{timestamp('%Y-%m-%dT%H:%M:%S%z')}): \[Worker\(\S+ host:(#{hostname_or_ip_address}) pid:(\d+)\)\] (\S+) completed after (\d+\.\d+)/
22
22
  line.capture(:timestamp).as(:timestamp)
23
23
  line.capture(:host)
24
24
  line.capture(:pid).as(:integer)
@@ -4,31 +4,45 @@ module RequestLogAnalyzer::FileFormat
4
4
 
5
5
  extend CommonRegularExpressions
6
6
 
7
- # Define line types
8
- line_definition :haproxy do |line|
9
- line.header = true
10
- line.footer = true
11
-
12
- line.regexp = %r{
7
+ # substitute version specific parts of the haproxy entry regexp.
8
+ def self.compose_regexp(millisecs, backends, counters, connections, queues)
9
+ %r{
13
10
  (#{ip_address}):\d+\s # client_ip ':' client_port
14
- \[(#{timestamp('%d/%b/%Y:%H:%M:%S')})\.\d{3}\]\s # '[' accept_date ']'
11
+ \[(#{timestamp('%d/%b/%Y:%H:%M:%S')})#{millisecs}\]\s # '[' accept_date ']'
15
12
  (\S+)\s # frontend_name
16
- (\S+)\/(\S+)\s # backend_name '/' server_name
17
- (\d+|-1)\/(\d+|-1)\/(\d+|-1)\/(\d+|-1)\/\+?(\d+)\s # Tq '/' Tw '/' Tc '/' Tr '/' Tt
13
+ #{backends}
14
+ #{counters}
18
15
  (\d+)\s # status_code
19
16
  \+?(\d+)\s # bytes_read
20
17
  (\S+)\s # captured_request_cookie
21
18
  (\S+)\s # captured_response_cookie
22
19
  (\w|-)(\w|-)(\w|-)(\w|-)\s # termination_state
23
- (\d+)\/(\d+)\/(\d+)\/(\d+)\/\+?(\d+)\s # actconn '/' feconn '/' beconn '/' srv_conn '/' retries
24
- (\d+)\/(\d+)\s # srv_queue '/' backend_queue
20
+ #{connections}
21
+ #{queues}
25
22
  (\S*)\s? # captured_request_headers
26
23
  (\S*)\s? # captured_response_headers
27
24
  "([^"]*)" # '"' http_request '"'
28
25
  }x
26
+ end
27
+
28
+ # Define line types
29
+
30
+ # line definition for haproxy 1.3 and higher
31
+ line_definition :haproxy13 do |line|
32
+ line.header = true
33
+ line.footer = true
34
+ line.teaser = /\.\d{3}\] \S+ \S+\/\S+ / # .millisecs] frontend_name backend_name/server_name
35
+
36
+ line.regexp = compose_regexp(
37
+ '\.\d{3}', # millisecs
38
+ '(\S+)\/(\S+)\s', # backend_name '/' server_name
39
+ '(\d+|-1)\/(\d+|-1)\/(\d+|-1)\/(\d+|-1)\/\+?(\d+)\s', # Tq '/' Tw '/' Tc '/' Tr '/' Tt
40
+ '(\d+)\/(\d+)\/(\d+)\/(\d+)\/\+?(\d+)\s', # actconn '/' feconn '/' beconn '/' srv_conn '/' retries
41
+ '(\d+)\/(\d+)\s' # srv_queue '/' backend_queue
42
+ )
29
43
 
30
44
  line.capture(:client_ip).as(:string)
31
- line.capture(:accept_date).as(:timestamp)
45
+ line.capture(:timestamp).as(:timestamp)
32
46
  line.capture(:frontend_name).as(:string)
33
47
  line.capture(:backend_name).as(:string)
34
48
  line.capture(:server_name).as(:string)
@@ -57,9 +71,89 @@ module RequestLogAnalyzer::FileFormat
57
71
  line.capture(:http_request).as(:nillable_string)
58
72
  end
59
73
 
74
+ # haproxy 1.2 has a few fields less than 1.3+
75
+ line_definition :haproxy12 do |line|
76
+ line.header = true
77
+ line.footer = true
78
+ line.teaser = /\.\d{3}\] \S+ \S+ / # .millisecs] frontend_name server_name
79
+
80
+ line.regexp = compose_regexp(
81
+ '\.\d{3}', # millisecs
82
+ '(\S+)\s', # server_name
83
+ '(\d+|-1)\/(\d+|-1)\/(\d+|-1)\/(\d+|-1)\/\+?(\d+)\s', # Tq '/' Tw '/' Tc '/' Tr '/' Tt
84
+ '(\d+)\/(\d+)\/(\d+)\s', # srv_conn '/' listener_conn '/' process_conn
85
+ '(\d+)\/(\d+)\s' # srv_queue '/' backend_queue
86
+ )
87
+
88
+ line.capture(:client_ip).as(:string)
89
+ line.capture(:timestamp).as(:timestamp)
90
+ line.capture(:frontend_name).as(:string)
91
+ line.capture(:server_name).as(:string)
92
+ line.capture(:tq).as(:nillable_duration, :unit => :msec)
93
+ line.capture(:tw).as(:nillable_duration, :unit => :msec)
94
+ line.capture(:tc).as(:nillable_duration, :unit => :msec)
95
+ line.capture(:tr).as(:nillable_duration, :unit => :msec)
96
+ line.capture(:tt).as(:duration, :unit => :msec)
97
+ line.capture(:status_code).as(:integer)
98
+ line.capture(:bytes_read).as(:traffic, :unit => :byte)
99
+ line.capture(:captured_request_cookie).as(:nillable_string)
100
+ line.capture(:captured_response_cookie).as(:nillable_string)
101
+ line.capture(:termination_event_code).as(:nillable_string)
102
+ line.capture(:terminated_session_state).as(:nillable_string)
103
+ line.capture(:clientside_persistence_cookie).as(:nillable_string)
104
+ line.capture(:serverside_persistence_cookie).as(:nillable_string)
105
+ line.capture(:srv_conn).as(:integer)
106
+ line.capture(:listener_conn).as(:integer)
107
+ line.capture(:process_conn).as(:integer)
108
+ line.capture(:srv_queue).as(:integer)
109
+ line.capture(:backend_queue).as(:integer)
110
+ line.capture(:captured_request_headers).as(:nillable_string)
111
+ line.capture(:captured_response_headers).as(:nillable_string)
112
+ line.capture(:http_request).as(:nillable_string)
113
+ end
114
+
115
+ # and haproxy 1.1 has even less fields
116
+ line_definition :haproxy11 do |line|
117
+ line.header = true
118
+ line.footer = true
119
+ line.teaser = /:\d{2}\] \S+ \S+ / # :secs] frontend_name server_name
120
+
121
+ line.regexp = compose_regexp(
122
+ '', # no millisec precision in this version of haproxy
123
+ '(\S+)\s', # server_name
124
+ '(\d+|-1)\/(\d+|-1)\/(\d+|-1)\/\+?(\d+)\s', # Tq '/' Tc '/' Tr '/' Tt
125
+ '(\d+)\/(\d+)\s', # listener_conn '/' process_conn
126
+ '' # no queues in this version of haproxy
127
+ )
128
+
129
+ line.capture(:client_ip).as(:string)
130
+ line.capture(:timestamp).as(:timestamp)
131
+ line.capture(:frontend_name).as(:string)
132
+ line.capture(:server_name).as(:string)
133
+ line.capture(:tq).as(:nillable_duration, :unit => :msec)
134
+ line.capture(:tc).as(:nillable_duration, :unit => :msec)
135
+ line.capture(:tr).as(:nillable_duration, :unit => :msec)
136
+ line.capture(:tt).as(:duration, :unit => :msec)
137
+ line.capture(:status_code).as(:integer)
138
+ line.capture(:bytes_read).as(:traffic, :unit => :byte)
139
+ line.capture(:captured_request_cookie).as(:nillable_string)
140
+ line.capture(:captured_response_cookie).as(:nillable_string)
141
+ line.capture(:termination_event_code).as(:nillable_string)
142
+ line.capture(:terminated_session_state).as(:nillable_string)
143
+ line.capture(:clientside_persistence_cookie).as(:nillable_string)
144
+ line.capture(:serverside_persistence_cookie).as(:nillable_string)
145
+ line.capture(:listener_conn).as(:integer)
146
+ line.capture(:process_conn).as(:integer)
147
+ line.capture(:srv_queue).as(:integer)
148
+ line.capture(:backend_queue).as(:integer)
149
+ line.capture(:captured_request_headers).as(:nillable_string)
150
+ line.capture(:captured_response_headers).as(:nillable_string)
151
+ line.capture(:http_request).as(:nillable_string)
152
+ end
153
+
60
154
  # Define the summary report
61
155
  report do |analyze|
62
- analyze.hourly_spread :field => :accept_date
156
+ analyze.hourly_spread :field => :timestamp
63
157
 
64
158
  analyze.frequency :client_ip,
65
159
  :title => "Hits per IP"
@@ -15,7 +15,7 @@ module RequestLogAnalyzer::FileFormat
15
15
  line_definition :user_host do |line|
16
16
  line.header = :alternative
17
17
  line.teaser = /\# User\@Host\: /
18
- line.regexp = /\# User\@Host\: ([\w-]+)\[[\w-]+\] \@ ([\w\.-]*) \[(#{ip_address(true)})\]/
18
+ line.regexp = /\# User\@Host\: ([\w-]+)\[[\w-]+\] \@ (#{hostname(true)}) \[(#{ip_address(true)})\]/
19
19
 
20
20
  line.capture(:user)
21
21
  line.capture(:host)
@@ -34,18 +34,18 @@ module RequestLogAnalyzer::FileFormat
34
34
  end
35
35
 
36
36
  line_definition :use_database do |line|
37
- line.regexp = /^use (\w+);\s*$/
37
+ line.regexp = /^\s*use (\w+);\s*$/
38
38
  line.capture(:database)
39
39
  end
40
40
 
41
41
  line_definition :query_part do |line|
42
- line.regexp = /^(?!(?:use |\# |SET ))(.*[^;\s])\s*$/
42
+ line.regexp = /^\s*(?!(?:use |\# |SET ))(.*[^;\s])\s*$/
43
43
  line.capture(:query_fragment)
44
44
  end
45
45
 
46
46
  line_definition :query do |line|
47
47
  line.footer = true
48
- line.regexp = /^(?!(?:use |\# |SET ))(.*);\s*$/
48
+ line.regexp = /^(?!\s*(?:use |\# |SET ))(.*);\s*$/
49
49
  line.capture(:query).as(:sql)
50
50
  end
51
51
 
@@ -84,7 +84,7 @@ module RequestLogAnalyzer::FileFormat
84
84
  sql.gsub!(/(:int,)+:int/, ':ints') # replace multiple ints by a list
85
85
  sql.gsub!(/(:string,)+:string/, ':strings') # replace multiple strings by a list
86
86
 
87
- return sql.rstrip
87
+ return sql.strip
88
88
  end
89
89
 
90
90
  def host