apachecrunch 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/bin/apachecrunch CHANGED
@@ -60,11 +60,11 @@ end
60
60
 
61
61
  options = parse_args
62
62
 
63
- format_string = FormatStringFinder.new.find(options[:format])
63
+ format_def = ApacheCrunch::FormatDefinitionFinder.new.find(options[:format])
64
64
  progress_meter = ProgressMeterFactory.from_options(options)
65
- log_parser = LogParserFactory.log_parser(
66
- format_string=format_string,
67
- path=options[:logfile],
68
- progress_meter=progress_meter)
65
+ log_parser = ApacheCrunch::LogParserFactory.log_parser(
66
+ format_def,
67
+ options[:logfile],
68
+ progress_meter)
69
69
  proc_env = ProcedureEnvironment.new(log_parser)
70
70
  proc_env.eval_procedure(open(options[:procedure]).read())
data/lib/apachecrunch.rb CHANGED
@@ -1,320 +1,22 @@
1
1
  require "date"
2
2
  require "tempfile"
3
3
 
4
+ require 'config'
5
+ require 'entry'
6
+ require 'format'
7
+ require 'log_parser'
4
8
  require 'log_element'
5
9
 
6
-
7
- # A parsed entry from the log.
8
- #
9
- # Acts like a hash, in that you get at the log elements (e.g. "url_path", "remote_host") by
10
- # as entry[name].
11
- class LogEntry
12
- def initialize(derivation_map)
13
- @_derivation_map = derivation_map
14
- @_attributes = {}
15
- end
16
-
17
- def []=(name, value)
18
- @_attributes[name] = value
19
- end
20
-
21
- def [](name)
22
- return @_attributes[name] if @_attributes.key?(name)
23
-
24
- derived_from_cls = @_derivation_map[name]
25
- return nil if derived_from_cls.nil?
26
-
27
- derived_from_cls.derive(name, @_attributes[derived_from_cls.name])
28
- end
29
-
30
- def merge!(hsh)
31
- @_attributes.merge!(hsh)
32
- end
33
- end
34
-
35
-
36
- # A bare string in a log format
37
- #
38
- # Exposes 'regex' for consistency with LogFormatElement, but there shouldn't be anything other
39
- # than one-to-one character matching in there.
40
- class LogFormatString
41
- attr_accessor :regex
42
-
43
- def initialize(regex)
44
- @regex = regex
45
- end
46
- end
47
-
48
-
49
- # Represents a particular Apache log format
50
- class LogFormat
51
- attr_accessor :format_string, :tokens
52
-
53
- def initialize
54
- @tokens = []
55
- @_regex = nil
56
- end
57
-
58
- # Appends a given token (a LogFormatElement or LogFormatString) to the tokens list
59
- def append(token)
60
- @tokens << token
61
- end
62
-
63
- # Returns a compiled regex to match a log line in this format
64
- def regex
65
- return @_regex unless @_regex.nil?
66
-
67
- r = "^"
68
- @tokens.each do |tok|
69
- # We only care to remember the LogFormatElements. No need to put parentheses
70
- # around LogFormatString shit.
71
- if tok.respond_to?(:name)
72
- r += "(" + tok.regex + ")"
73
- else
74
- r += tok.regex
75
- end
76
- end
77
- r += "$"
78
-
79
- @_regex = Regexp.compile(r)
80
- @_regex
81
- end
82
-
83
- # Returns the list of LogFormatElements, in order, of the interpolated things in the format.
10
+ class ApacheCrunch
11
+ # A bare string in a log format
84
12
  #
85
- # For example, if the log format string were "%h %u %{Referer}i", this would return the
86
- # LogFormatElement instances for "%h", "%u", and "%{Referer}i".
87
- def elements
88
- @tokens.find_all do |tok|
89
- tok.respond_to?(:name)
90
- end
91
- end
92
-
93
- # Returns hash mapping names of elements to the element class from which they can be derived.
94
- def derivation_map
95
- hsh = {}
96
- elements.each do |tok|
97
- tok.derived_elements.each do |derived_element|
98
- hsh[derived_element.name] = tok.class
99
- end
100
- end
101
-
102
- hsh
103
- end
104
- end
105
-
106
-
107
- # Turns a string specifying an Apache log format into a LogFormat instance
108
- class LogFormatFactory
109
- def initialize
110
- @element_factory = LogFormatElementFactory.new
111
- end
112
-
113
- # Constructs and returns a LogFormat instance based on the given Apache log format string
114
- def from_format_string(f_string)
115
- logformat = LogFormat.new
116
- logformat.format_string = f_string
13
+ # Exposes 'regex' for consistency with LogFormatElement, but there shouldn't be anything other
14
+ # than one-to-one character matching in there.
15
+ class LogFormatString
16
+ attr_accessor :regex
117
17
 
118
- until f_string.empty?
119
- token, f_string = _shift_token(f_string)
120
- logformat.append(token)
18
+ def initialize(regex)
19
+ @regex = regex
121
20
  end
122
-
123
- logformat
124
- end
125
-
126
- # Finds the first token (a LogFormatElement or LogFormatString) in a format string
127
- #
128
- # Returns a list containing the token and the new format string (with the characters that
129
- # correspond to the token removed)
130
- def _shift_token(f_string)
131
- if f_string =~ /^%%(.*)/
132
- # Literal "%"
133
- return [LogFormatString.new("%%"), $1]
134
- elsif f_string =~ /^(%[A-Za-z])(.*)/
135
- # Simple element (e.g. "%h", "%u")
136
- return [@element_factory.from_abbrev($1), $2]
137
- elsif f_string =~ /^%[<>]([A-Za-z])(.*)/
138
- # No idea how to handle mod_log_config's "which request" system yet, so we
139
- # ignore it.
140
- return [@element_factory.from_abbrev("%" + $1), $2]
141
- elsif f_string =~ /^(%\{.+?\}[Ceinor])(.*)/
142
- # "Contents of" element (e.g. "%{Accept}i")
143
- return [@element_factory.from_abbrev($1), $2]
144
- elsif f_string =~ /^(.+?)(%.*|$)/
145
- # Bare string up until the next %, or up until the end of the format string
146
- return [LogFormatString.new($1), $2]
147
- end
148
- end
149
- end
150
-
151
-
152
- # Makes log line hashes based on log file text
153
- class LogLineParser
154
- # Initializes the instance given a LogFormat instance
155
- def initialize(log_format, progress_meter)
156
- @log_format = log_format
157
- @progress_meter = progress_meter
158
-
159
- @_elements = log_format.elements
160
- @_derivation_map = log_format.derivation_map
161
- end
162
-
163
- # Returns a log line hash built from a line of text, or nil if the line was malformatted
164
- #
165
- # The keys of the hash are names of LogFormatElements (e.g. "remote_host", "reqheader_referer")
166
- def from_text(log_text)
167
- match = (log_text =~ @log_format.regex)
168
- if match.nil?
169
- warn "Log line did not match expected format: #{log_text}"
170
- return nil
171
- end
172
-
173
- # Make a hash mapping all parsed elements to their values in the entry
174
- match_groups = Regexp.last_match.to_a
175
- match_groups.shift # First value is the whole matched string, which we do not want
176
- element_values = Hash[*@_elements.zip(match_groups).flatten]
177
-
178
- # Start building the return value
179
- entry = LogEntry.new(@_derivation_map)
180
- entry[:text] = log_text
181
- # Insert all the elements specified in the LogFormat
182
- entry.merge!(_elements_to_hash(element_values))
183
-
184
- @progress_meter.output_progress(entry)
185
- entry
186
- end
187
-
188
- # Returns a hash of "element name" => value pairs based on a hash of element => value pairs.
189
- def _elements_to_hash(element_values)
190
- hsh = {}
191
- element_values.each_pair do |element, value|
192
- hsh[element.name] = value
193
- end
194
-
195
- hsh
196
- end
197
-
198
- # Returns hash of derived "element name" => value pairs from a hash of element => value pairs.
199
- #
200
- # That is, we go through the elements passed and if any offers derived elements, we include
201
- # those in the return value.
202
- def _derived_elements(element_values)
203
- hsh = {}
204
- element_values.each_pair do |element, value|
205
- hsh.merge!(element.derived_values(value))
206
- end
207
-
208
- hsh
209
- end
210
- end
211
-
212
-
213
- # Parses a log file given a path and a LogFormat instance
214
- class LogParser
215
- # Initializes the parser with the path to a log file and a LogLineParser.
216
- def initialize(path, ll_parser)
217
- @path = path
218
- @ll_parser = ll_parser
219
-
220
- @_file = nil
221
- end
222
-
223
- # Returns the next entry in the log file as a hash, or nil if we've reached EOF.
224
- #
225
- # The keys of the hash are names of LogFormatElements (e.g. "remote_host", "reqheader_referer")
226
- def next_entry
227
- @_file = open(@path) if @_file.nil?
228
-
229
- while line_text = @_file.gets
230
- return nil if line_text.nil?
231
- logline = @ll_parser.from_text(line_text)
232
-
233
- # The LogLineFactory returns nil and writes a warning if the line text doesn't
234
- # match our expected format.
235
- next if logline.nil?
236
-
237
- return logline
238
- end
239
- end
240
-
241
- # Resets the LogParser's filehandle so we can start over.
242
- def reset
243
- @_file = nil
244
- end
245
-
246
- # Makes the LogParser close its current log file and start parsing a new one instead
247
- #
248
- # `new_target` is a writable file object that the parser should start parsing, and if
249
- # in_place is true, we actually replace the contents of the current target with those
250
- # of the new target.
251
- def replace_target(new_target, in_place)
252
- new_target.close
253
-
254
- if in_place
255
- old_path = @_file.path
256
- File.rename(new_target.path, old_path)
257
- else
258
- @path = new_target.path
259
- end
260
-
261
- @_file = nil
262
- end
263
- end
264
-
265
- # Makes a LogParser given the parameters we want to work with.
266
- #
267
- # This is the class that most external code should instatiate to begin using this library.
268
- class LogParserFactory
269
- # Returns a new LogParser instance for the given log file, which should have the given Apache
270
- # log format.
271
- def self.log_parser(format_string, path, progress_meter)
272
- # First we generate a LogFormat instance based on the format string we were given
273
- format_factory = LogFormatFactory.new
274
- log_format = format_factory.from_format_string(format_string)
275
-
276
- # Now we generate a line parser
277
- log_line_parser = LogLineParser.new(log_format, progress_meter)
278
-
279
- # And now we can instantiate and return a LogParser
280
- return LogParser.new(path, log_line_parser)
281
- end
282
- end
283
-
284
-
285
- # Finds a named log format string in the configuration file(s)
286
- class FormatStringFinder
287
- @@FILE_NAME = "log_formats.rb"
288
- @@DEFAULT_FORMATS = {
289
- :ncsa => %q!%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"!,
290
- :ubuntu => %q!%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"!
291
- }
292
-
293
- # Finds the given format string in the configuration file(s)
294
- #
295
- # If none exists, returns nil.
296
- def find(format_name)
297
- name_as_symbol = format_name.to_sym
298
-
299
- formats = @@DEFAULT_FORMATS.clone
300
- _search_path.each do |dir|
301
- config_path = File.join(dir, @@FILE_NAME)
302
- if File.readable?(config_path)
303
- config_file = open(File.join(dir, @@FILE_NAME))
304
- eval config_file.read
305
- end
306
-
307
- if formats.key?(format_name.to_sym)
308
- return formats[format_name.to_sym].gsub(/\\"/, '"')
309
- end
310
- end
311
-
312
- raise "Failed to find the format '#{format_name}' in the search path: #{_search_path.inspect}"
313
- end
314
-
315
- def _search_path
316
- [".", "./etc",
317
- File.join(ENV["HOME"], ".apachecrunch"),
318
- "/etc/apachecrunch"]
319
21
  end
320
22
  end
data/lib/config.rb ADDED
@@ -0,0 +1,44 @@
1
+ class ApacheCrunch
2
+ # Finds a named log format string in the configuration file(s)
3
+ class FormatDefinitionFinder
4
+ @@FILE_NAME = "log_formats.rb"
5
+ @@DEFAULT_FORMATS = {
6
+ :ncsa => %q!%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"!,
7
+ :ubuntu => %q!%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"!
8
+ }
9
+
10
+ # Initializes the FormatStringFinder.
11
+ def initialize(file_cls=File, env=ENV)
12
+ @_file_cls=file_cls
13
+ @_env=env
14
+ end
15
+
16
+ # Finds the given format string in the configuration file(s)
17
+ #
18
+ # If none exists, returns nil.
19
+ def find(format_name)
20
+ name_as_symbol = format_name.to_sym
21
+
22
+ formats = @@DEFAULT_FORMATS.clone
23
+ _search_path.each do |dir|
24
+ config_path = @_file_cls.join(dir, @@FILE_NAME)
25
+ if @_file_cls.readable?(config_path)
26
+ config_file = @_file_cls.open(@_file_cls.join(dir, @@FILE_NAME))
27
+ eval config_file.read
28
+ end
29
+
30
+ if formats.key?(format_name.to_sym)
31
+ return formats[format_name.to_sym].gsub(/\\"/, '"')
32
+ end
33
+ end
34
+
35
+ raise "Failed to find the format '#{format_name}' in the search path: #{_search_path.inspect}"
36
+ end
37
+
38
+ def _search_path
39
+ [".", "./etc",
40
+ @_file_cls.join(@_env["HOME"], ".apachecrunch"),
41
+ "/etc/apachecrunch"]
42
+ end
43
+ end
44
+ end
data/lib/entry.rb ADDED
@@ -0,0 +1,90 @@
1
+ class ApacheCrunch
2
+ # A parsed entry from the log.
3
+ #
4
+ # Acts like a hash, in that you get at the log elements (e.g. "url_path", "remote_host") by
5
+ # as entry[name].
6
+ class Entry
7
+ def initialize(derivation_map)
8
+ @_derivation_map = derivation_map
9
+ @_attributes = {}
10
+ end
11
+
12
+ def []=(name, value)
13
+ @_attributes[name] = value
14
+ end
15
+
16
+ def [](name)
17
+ return @_attributes[name] if @_attributes.key?(name)
18
+
19
+ derived_from_cls = @_derivation_map[name]
20
+ return nil if derived_from_cls.nil?
21
+
22
+ derived_from_cls.derive(name, @_attributes[derived_from_cls.name])
23
+ end
24
+
25
+ def merge!(hsh)
26
+ @_attributes.merge!(hsh)
27
+ end
28
+ end
29
+
30
+
31
+ # Makes Entry instances based on log file text
32
+ class EntryParser
33
+ # Initializes the instance given a LogFormat instance
34
+ def initialize(log_format, progress_meter)
35
+ @log_format = log_format
36
+ @progress_meter = progress_meter
37
+
38
+ @_elements = log_format.elements
39
+ @_derivation_map = log_format.derivation_map
40
+ end
41
+
42
+ # Returns a log line hash built from a line of text, or nil if the line was malformatted
43
+ #
44
+ # The keys of the hash are names of LogFormatElements (e.g. "remote_host", "reqheader_referer")
45
+ def from_text(log_text)
46
+ match = (log_text =~ @log_format.regex)
47
+ if match.nil?
48
+ warn "Log line did not match expected format: #{log_text}"
49
+ return nil
50
+ end
51
+
52
+ # Make a hash mapping all parsed elements to their values in the entry
53
+ match_groups = Regexp.last_match.to_a
54
+ match_groups.shift # First value is the whole matched string, which we do not want
55
+ element_values = Hash[*@_elements.zip(match_groups).flatten]
56
+
57
+ # Start building the return value
58
+ entry = Entry.new(@_derivation_map)
59
+ entry[:text] = log_text
60
+ # Insert all the elements specified in the LogFormat
61
+ entry.merge!(_elements_to_hash(element_values))
62
+
63
+ @progress_meter.output_progress(entry)
64
+ entry
65
+ end
66
+
67
+ # Returns a hash of "element name" => value pairs based on a hash of element => value pairs.
68
+ def _elements_to_hash(element_values)
69
+ hsh = {}
70
+ element_values.each_pair do |element, value|
71
+ hsh[element.name] = value
72
+ end
73
+
74
+ hsh
75
+ end
76
+
77
+ # Returns hash of derived "element name" => value pairs from a hash of element => value pairs.
78
+ #
79
+ # That is, we go through the elements passed and if any offers derived elements, we include
80
+ # those in the return value.
81
+ def _derived_elements(element_values)
82
+ hsh = {}
83
+ element_values.each_pair do |element, value|
84
+ hsh.merge!(element.derived_values(value))
85
+ end
86
+
87
+ hsh
88
+ end
89
+ end
90
+ end
data/lib/format.rb ADDED
@@ -0,0 +1,128 @@
1
+ class ApacheCrunch
2
+ # Represents a particular Apache log format
3
+ class Format
4
+ attr_accessor :format_def, :tokens
5
+
6
+ def initialize
7
+ @tokens = []
8
+ @_regex = nil
9
+ end
10
+
11
+ # Appends a given token (a LogFormatElement or LogFormatString) to the tokens list
12
+ def append(token)
13
+ @tokens << token
14
+ end
15
+
16
+ # Returns a compiled regex to match a log line in this format
17
+ #
18
+ # Each group matched will correspond to an element in the log format.
19
+ def regex
20
+ return @_regex unless @_regex.nil?
21
+
22
+ r = "^"
23
+ @tokens.each do |tok|
24
+ # We only care to remember the LogFormatElements. No need to put parentheses
25
+ # around LogFormatString shit.
26
+ if tok.respond_to?(:name)
27
+ r += "(" + tok.regex + ")"
28
+ else
29
+ r += tok.regex
30
+ end
31
+ end
32
+ r += "$"
33
+
34
+ @_regex = Regexp.compile(r)
35
+ @_regex
36
+ end
37
+
38
+ # Returns the list of LogFormatElements, in order, of the interpolated things in the format.
39
+ #
40
+ # For example, if the log format definition were "%h %u %{Referer}i", this would return the
41
+ # LogFormatElement instances for "%h", "%u", and "%{Referer}i".
42
+ def elements
43
+ @tokens.find_all do |tok|
44
+ tok.respond_to?(:name)
45
+ end
46
+ end
47
+
48
+ # Returns hash mapping names of elements to the element class from which they can be derived.
49
+ def derivation_map
50
+ hsh = {}
51
+ elements.each do |tok|
52
+ tok.derived_elements.each do |derived_element|
53
+ hsh[derived_element.name] = tok.class
54
+ end
55
+ end
56
+
57
+ hsh
58
+ end
59
+ end
60
+
61
+ # Parses a log format definition
62
+ class FormatParser
63
+ # Initializes the FormatParser
64
+ #
65
+ # Takes a FormatElementFactory instance, and you can inject a replacement for the
66
+ # LogFormatString class.
67
+ def initialize(format_element_factory, format_string_cls=LogFormatString)
68
+ @_element_factory = format_element_factory
69
+ @_format_string_cls = format_string_cls
70
+ end
71
+
72
+ # Parses the given format_def (e.g. "%h %u %s #{Referer}i") and returns a list of tokens.
73
+ #
74
+ # These tokens are all instances of LogFormatString or LogFormatElement.
75
+ def parse_def(format_def)
76
+ s = format_def
77
+ tokens = []
78
+
79
+ until s.empty?
80
+ token, s = _shift_token(s)
81
+ tokens << token
82
+ end
83
+
84
+ tokens
85
+ end
86
+
87
+ # Finds the first token (a LogFormatElement or LogFormatString) in a format definition
88
+ #
89
+ # Returns a list containing the token and the new format definition (with the characters
90
+ # that correspond to the token removed)
91
+ def _shift_token(format_def)
92
+ if format_def =~ /^%%(.*)/
93
+ # Literal "%"
94
+ return [@_format_string_cls.new("%%"), $1]
95
+ elsif format_def =~ /^(%[A-Za-z])(.*)/
96
+ # Simple element (e.g. "%h", "%u")
97
+ return [@_element_factory.from_abbrev($1), $2]
98
+ elsif format_def =~ /^%[<>]([A-Za-z])(.*)/
99
+ # No idea how to handle mod_log_config's "which request" system yet, so we
100
+ # ignore it.
101
+ return [@_element_factory.from_abbrev("%" + $1), $2]
102
+ elsif format_def =~ /^(%\{.+?\}[Ceinor])(.*)/
103
+ # "Contents of" element (e.g. "%{Accept}i")
104
+ return [@_element_factory.from_abbrev($1), $2]
105
+ elsif format_def =~ /^(.+?)(%.*|$)/
106
+ # Bare string up until the next %, or up until the end of the format definition
107
+ return [@_format_string_cls.new($1), $2]
108
+ end
109
+ end
110
+ end
111
+
112
+
113
+ # Turns a string specifying an Apache log format into a Format instance
114
+ class FormatFactory
115
+ # Constructs and returns a Format instance based on the given Apache log format string
116
+ def self.from_format_def(format_def)
117
+ logformat = Format.new
118
+ logformat.format_def = format_def
119
+
120
+ element_factory = LogFormatElementFactory.new
121
+
122
+ format_parser = FormatParser.new(element_factory)
123
+ logformat.tokens = format_parser.parse_def(format_def)
124
+
125
+ logformat
126
+ end
127
+ end
128
+ end
data/lib/log_parser.rb ADDED
@@ -0,0 +1,74 @@
1
+ class ApacheCrunch
2
+ # Parses a log file given a path and a Format instance
3
+ class LogParser
4
+ # Initializes the parser with the path to a log file and a EntryParser.
5
+ def initialize(path, entry_parser, file_cls=File)
6
+ @path = path
7
+ @entry_parser = entry_parser
8
+
9
+ @_file_cls = file_cls
10
+ @_file = nil
11
+ end
12
+
13
+ # Returns the next entry in the log file as a hash, or nil if we've reached EOF.
14
+ #
15
+ # The keys of the hash are names of LogFormatElements (e.g. :remote_host,
16
+ # :reqheader_referer)
17
+ def next_entry
18
+ @_file = @_file_cls.open(@path) if @_file.nil?
19
+
20
+ while line_text = @_file.gets
21
+ return nil if line_text.nil?
22
+ logline = @entry_parser.from_text(line_text)
23
+
24
+ # The EntryParser returns nil and writes a warning if the line text doesn't
25
+ # match our expected format.
26
+ next if logline.nil?
27
+
28
+ return logline
29
+ end
30
+ end
31
+
32
+ # Resets the LogParser's filehandle so we can start over.
33
+ def reset
34
+ @_file = nil
35
+ end
36
+
37
+ # Makes the LogParser close its current log file and start parsing a new one instead
38
+ #
39
+ # `new_target` is a writable file object that the parser should start parsing, and if
40
+ # in_place is true, we actually replace the contents of the current target with those
41
+ # of the new target.
42
+ def replace_target(new_target, in_place)
43
+ new_target.close
44
+
45
+ if in_place
46
+ old_path = @_file.path
47
+ @_file_cls.rename(new_target.path, old_path)
48
+ else
49
+ @path = new_target.path
50
+ end
51
+
52
+ @_file = nil
53
+ end
54
+ end
55
+
56
+
57
+ # Makes a LogParser given the parameters we want to work with.
58
+ #
59
+ # This is the class that most external code should instatiate to begin using this library.
60
+ class LogParserFactory
61
+ # Returns a new LogParser instance for the given log file, which should have the given
62
+ # Apache log format.
63
+ def self.log_parser(format_def, path, progress_meter)
64
+ # First we generate a Format instance based on the format definition we were given
65
+ log_format = FormatFactory.from_format_def(format_def)
66
+
67
+ # Now we generate a line parser
68
+ log_line_parser = EntryParser.new(log_format, progress_meter)
69
+
70
+ # And now we can instantiate and return a LogParser
71
+ return LogParser.new(path, log_line_parser)
72
+ end
73
+ end
74
+ end
data/lib/progress.rb CHANGED
@@ -39,7 +39,7 @@ class TimeProgressMeter < ProgressMeter
39
39
  def output_progress(entry)
40
40
  @_entry_count += 1
41
41
  if @_entry_count % @_period == 0
42
- puts "Processed through %s" % [entry["time"]]
42
+ puts "Processed through %s" % [entry[:time]]
43
43
  end
44
44
  end
45
45
  end
data/test/runner.rb ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+
4
+ $: << ".."
5
+ $: << "./lib"
6
+ require 'apachecrunch'
7
+
8
+ class AllTests
9
+ def self.run
10
+ Dir.glob("test/test_*.rb").each do |test_file|
11
+ require test_file
12
+ end
13
+ end
14
+ end
15
+
16
+ AllTests.run
data/test/stub.rb ADDED
@@ -0,0 +1,56 @@
1
+ class StubFormatElement < LogFormatElement
2
+ @abbrev = "%z"
3
+ @name = :stub
4
+ @regex = %q!.*!
5
+ end
6
+
7
+ class StubAlphanumericFormatElement < LogFormatElement
8
+ @abbrev = "%Z"
9
+ @name = :alnum
10
+ @regex = %q![A-Za-z0-9]+!
11
+ end
12
+
13
+ class StubNumericFormatElement < LogFormatElement
14
+ @abbrev = "%y"
15
+ @name = :num
16
+ @regex = %q!\d+!
17
+ end
18
+
19
+ class StubFormatString
20
+ attr_accessor :regex
21
+ def initialize(regex)
22
+ @regex = regex
23
+ end
24
+ end
25
+
26
+ class StubDerivedElement < LogFormatElement
27
+ @abbrev = ""
28
+ @name = :derived
29
+ @regex = %q!.*!
30
+ end
31
+
32
+ class StubDerivationSourceElement < LogFormatElement
33
+ @name = :derivation_source
34
+
35
+ def derived_elements
36
+ [StubDerivedElement]
37
+ end
38
+
39
+ def self.derive(name, our_own_value)
40
+ if name == :derived
41
+ return "derived from #{our_own_value}"
42
+ end
43
+
44
+ nil
45
+ end
46
+ end
47
+
48
+ class StubLogFormatElementFactory
49
+ def from_abbrev(abbrev)
50
+ if abbrev =~ /^%/
51
+ return StubFormatElement.new
52
+ else
53
+ return StubFormatString.new
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ require 'test/stub'
2
+
3
+ class TestEntry < Test::Unit::TestCase
4
+ def setup
5
+ @inst = ApacheCrunch::Entry.new({:derived => StubDerivationSourceElement})
6
+ end
7
+
8
+ def teardown
9
+ @inst = nil
10
+ end
11
+
12
+ # Tests direct assignment of an element.
13
+ def test_assign
14
+ @inst[:bar] = "test_value"
15
+ assert_equal(@inst[:bar], "test_value")
16
+ end
17
+
18
+ # Tests derivation of one element from another.
19
+ def test_derive
20
+ @inst[:derivation_source] = "source text"
21
+ assert_equal(@inst[:derived], "derived from source text")
22
+ end
23
+
24
+ # Tests access to an absent element.
25
+ def test_access_absent
26
+ assert_nil(@inst[:nonexistent])
27
+ end
28
+ end
@@ -0,0 +1,63 @@
1
+ require 'test/stub'
2
+
3
+ class TestFormat < Test::Unit::TestCase
4
+ def setup
5
+ @inst = ApacheCrunch::Format.new
6
+ end
7
+
8
+ def teardown
9
+ @inst = nil
10
+ end
11
+
12
+ # Tests appending an element to the format
13
+ def test_append
14
+ format_element = StubFormatElement.new
15
+ @inst.append(format_element)
16
+ assert_same(@inst.tokens[-1], format_element)
17
+ end
18
+
19
+ # Tests regex compilation for a simple format
20
+ def test_regex_simple
21
+ @inst.append(StubAlphanumericFormatElement.new)
22
+ "abc123\n" =~ @inst.regex
23
+ assert_equal($1, "abc123")
24
+
25
+ "!abc123\n" =~ @inst.regex
26
+ assert_nil($1)
27
+ end
28
+
29
+ # Tests regex compilation for a more complex format
30
+ def test_regex_complex
31
+ @inst.append(StubNumericFormatElement.new)
32
+ @inst.append(StubFormatString.new(' \(some stuff\) '))
33
+ @inst.append(StubAlphanumericFormatElement.new)
34
+
35
+ "54321 (some stuff) alphaNumericStuff" =~ @inst.regex
36
+ assert_equal([Regexp.last_match(1), Regexp.last_match(2)],
37
+ ["54321", "alphaNumericStuff"])
38
+
39
+ "54321 (doesn't match) alphaNumericStuff" =~ @inst.regex
40
+ assert_equal([Regexp.last_match(1), Regexp.last_match(2)],
41
+ [nil, nil])
42
+ end
43
+
44
+ # Tests the list of matchable elements
45
+ def test_elements
46
+ num_element = StubNumericFormatElement.new
47
+ alnum_element = StubAlphanumericFormatElement.new
48
+ @inst.append(num_element)
49
+ @inst.append(StubFormatString.new(' \(some stuff\) '))
50
+ @inst.append(alnum_element)
51
+
52
+ assert_equal(@inst.elements, [num_element, alnum_element])
53
+ end
54
+
55
+ # Tests the derivation map
56
+ def test_derivation_map
57
+ @inst.append(StubNumericFormatElement.new)
58
+ @inst.append(StubFormatString.new(' \(some stuff\) '))
59
+ @inst.append(StubDerivationSourceElement.new)
60
+
61
+ assert(@inst.derivation_map, {:derived => StubDerivationSourceElement})
62
+ end
63
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/stub'
2
+
3
+ class TestFormatParser < Test::Unit::TestCase
4
+ def setup
5
+ @inst = ApacheCrunch::FormatParser.new(StubLogFormatElementFactory.new,
6
+ StubFormatString)
7
+ end
8
+
9
+ def teardown
10
+ @inst = nil
11
+ end
12
+
13
+ def test_parse_simple
14
+ tokens = @inst.parse_def("%Z %z")
15
+ [StubFormatElement, StubFormatString, StubFormatElement].each_with_index do |c,i|
16
+ assert_instance_of(c, tokens[i])
17
+ end
18
+ end
19
+
20
+ def test_parse_complex
21
+ tokens = @inst.parse_def("%{Foo-Bar}i %{baz:\d+}r")
22
+ [StubFormatElement, StubFormatString, StubFormatElement].each_with_index do |c,i|
23
+ assert_instance_of(c, tokens[i])
24
+ end
25
+ end
26
+ end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apachecrunch
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
9
- version: "0.3"
8
+ - 4
9
+ version: "0.4"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Dan Slimmon
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-07-10 00:00:00 -04:00
17
+ date: 2011-07-12 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -31,11 +31,20 @@ extra_rdoc_files: []
31
31
 
32
32
  files:
33
33
  - lib/apachecrunch.rb
34
+ - lib/config.rb
35
+ - lib/entry.rb
36
+ - lib/format.rb
34
37
  - lib/log_element.rb
38
+ - lib/log_parser.rb
35
39
  - lib/procedure_dsl.rb
36
40
  - lib/progress.rb
37
41
  - bin/apachecrunch
38
42
  - LICENSE
43
+ - test/runner.rb
44
+ - test/stub.rb
45
+ - test/test_entry.rb
46
+ - test/test_format.rb
47
+ - test/test_format_parser.rb
39
48
  has_rdoc: true
40
49
  homepage: https://github.com/danslimmon/apachecrunch/
41
50
  licenses: