indy 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +6 -1
- data/indy.gemspec +3 -1
- data/lib/indy/indy.rb +283 -233
- data/performance/large.log +10000 -0
- data/performance/profile_spec.rb +12 -13
- data/spec/indy_spec.rb +20 -3
- data/spec/result_set_spec.rb +28 -1
- data/spec/search_spec.rb +7 -0
- metadata +49 -16
data/History.txt
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
=== 0.1.
|
1
|
+
=== 0.1.3 / 2011-01-18
|
2
|
+
|
3
|
+
* Faster (than a turtle)
|
4
|
+
* Lighter (than a tank)
|
5
|
+
|
6
|
+
=== 0.1.2 / 2011-01-17
|
2
7
|
|
3
8
|
* Predefined log formats for NCSA Common, NCSA Combined, and Log4r (default)
|
4
9
|
* Source IO is explicitly closed after each #_search
|
data/indy.gemspec
CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.name = 'indy'
|
31
31
|
s.version = ::Indy::VERSION
|
32
32
|
s.authors = ["Franklin Webber","Brandon Faloona"]
|
33
|
-
s.description = %{ Indy is a log archelogy tool
|
33
|
+
s.description = %{ Indy is a log archelogy tool explore logs like objects and search by field and/or time.}
|
34
34
|
s.summary = "Log Search Tool"
|
35
35
|
s.email = 'franklin.webber@gmail.com'
|
36
36
|
s.homepage = "http://github.com/burtlo/Indy"
|
@@ -41,6 +41,8 @@ Gem::Specification.new do |s|
|
|
41
41
|
s.add_dependency('activesupport', '>= 2.3.5')
|
42
42
|
|
43
43
|
s.add_development_dependency('cucumber', '>= 0.9.2')
|
44
|
+
s.add_development_dependency('yard', '>= 0.6.4')
|
45
|
+
s.add_development_dependency('cucumber-in-the-yard', '>= 1.7.7')
|
44
46
|
s.add_development_dependency('rspec', '>= 2.4.0')
|
45
47
|
s.add_development_dependency('rspec-mocks', '>= 2.4.0')
|
46
48
|
s.add_development_dependency('rspec-prof', '>= 0.0.3')
|
data/lib/indy/indy.rb
CHANGED
@@ -3,7 +3,7 @@ require 'active_support/core_ext'
|
|
3
3
|
|
4
4
|
class Indy
|
5
5
|
|
6
|
-
VERSION = "0.1.
|
6
|
+
VERSION = "0.1.3"
|
7
7
|
|
8
8
|
#
|
9
9
|
# hash with one key (:string, :file, or :cmd) set to the string that defines the log
|
@@ -37,15 +37,14 @@ class Indy
|
|
37
37
|
# Indy.new(:time_format => '%m-%d-%Y',:pattern => [LOG_REGEX_PATTERN,:time,:application,:message],:source => LOG_FILENAME)
|
38
38
|
#
|
39
39
|
def initialize(args)
|
40
|
-
@source = @pattern = nil
|
40
|
+
@source = @pattern = @time_format = @log_regexp = @log_fields = nil
|
41
41
|
@source = Hash.new
|
42
42
|
|
43
43
|
while (arg = args.shift) do
|
44
44
|
send("#{arg.first}=",arg.last)
|
45
45
|
end
|
46
46
|
|
47
|
-
@pattern
|
48
|
-
@time_field = ( @pattern[1..-1].include?(:time) ? :time : nil )
|
47
|
+
update_log_pattern(@pattern)
|
49
48
|
|
50
49
|
end
|
51
50
|
|
@@ -98,11 +97,10 @@ class Indy
|
|
98
97
|
# Indy.search(LOG_FILE).with(/^(\d{2}.\d{2}.\d{2})\s*(.+)$/,:time,:message)
|
99
98
|
#
|
100
99
|
def with(pattern_array = :default)
|
101
|
-
|
102
|
-
@time_field = @pattern[1..-1].include?(:time) ? :time : nil
|
100
|
+
update_log_pattern( pattern_array )
|
103
101
|
self
|
104
102
|
end
|
105
|
-
|
103
|
+
|
106
104
|
#
|
107
105
|
# Search the source and make an == comparison
|
108
106
|
#
|
@@ -113,308 +111,360 @@ class Indy
|
|
113
111
|
def for(search_criteria)
|
114
112
|
results = ResultSet.new
|
115
113
|
|
114
|
+
define_struct
|
115
|
+
|
116
116
|
case search_criteria
|
117
117
|
when Enumerable
|
118
118
|
results += _search do |result|
|
119
|
-
|
119
|
+
create_struct(result) if search_criteria.reject {|criteria,value| result[criteria] == value }.empty?
|
120
120
|
end
|
121
|
+
|
121
122
|
when :all
|
122
|
-
results += _search {|result|
|
123
|
+
results += _search {|result| create_struct(result) }
|
123
124
|
end
|
124
125
|
|
125
126
|
results
|
126
127
|
end
|
127
128
|
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
results += _search do |result|
|
143
|
-
OpenStruct.new(result) if search_criteria.reject {|criteria,value| result[criteria] =~ /#{value}/ }.empty?
|
144
|
-
end
|
130
|
+
#
|
131
|
+
# Search the source and make a regular expression comparison
|
132
|
+
#
|
133
|
+
# @param [Hash] search_criteria the field to search for as the key and the
|
134
|
+
# value to compare against the other log messages
|
135
|
+
#
|
136
|
+
# @example For all applications that end with Service
|
137
|
+
#
|
138
|
+
# Indy.search(LOG_FILE).like(:application => '(.+)Service')
|
139
|
+
#
|
140
|
+
def like(search_criteria)
|
141
|
+
results = ResultSet.new
|
142
|
+
define_struct
|
145
143
|
|
146
|
-
|
144
|
+
results += _search do |result|
|
145
|
+
create_struct(result) if search_criteria.reject {|criteria,value| result[criteria] =~ /#{value}/ }.empty?
|
147
146
|
end
|
148
147
|
|
149
|
-
|
148
|
+
results
|
149
|
+
end
|
150
150
|
|
151
|
+
alias_method :matching, :like
|
151
152
|
|
152
|
-
#
|
153
|
-
# After scopes the eventual search to all entries after to this point.
|
154
|
-
#
|
155
|
-
# @param [Hash] scope_criteria the field to scope for as the key and the
|
156
|
-
# value to compare against the other log messages
|
157
|
-
#
|
158
|
-
# @example For all messages after specified date
|
159
|
-
#
|
160
|
-
# Indy.search(LOG_FILE).after(:time => time).for(:all)
|
161
|
-
#
|
162
|
-
def after(scope_criteria)
|
163
|
-
if scope_criteria[:time]
|
164
|
-
time = parse_date(scope_criteria[:time])
|
165
|
-
@inclusive = scope_criteria[:inclusive] || false
|
166
|
-
|
167
|
-
if scope_criteria[:span]
|
168
|
-
span = (scope_criteria[:span].to_i * 60).seconds
|
169
|
-
within(:time => [time, time + span])
|
170
|
-
else
|
171
|
-
@start_time = time
|
172
|
-
end
|
173
|
-
end
|
174
153
|
|
175
|
-
|
154
|
+
#
|
155
|
+
# After scopes the eventual search to all entries after to this point.
|
156
|
+
#
|
157
|
+
# @param [Hash] scope_criteria the field to scope for as the key and the
|
158
|
+
# value to compare against the other log messages
|
159
|
+
#
|
160
|
+
# @example For all messages after specified date
|
161
|
+
#
|
162
|
+
# Indy.search(LOG_FILE).after(:time => time).for(:all)
|
163
|
+
#
|
164
|
+
def after(scope_criteria)
|
165
|
+
if scope_criteria[:time]
|
166
|
+
time = parse_date(scope_criteria[:time])
|
167
|
+
@inclusive = scope_criteria[:inclusive] || false
|
168
|
+
|
169
|
+
if scope_criteria[:span]
|
170
|
+
span = (scope_criteria[:span].to_i * 60).seconds
|
171
|
+
within(:time => [time, time + span])
|
172
|
+
else
|
173
|
+
@start_time = time
|
174
|
+
end
|
176
175
|
end
|
177
176
|
|
178
|
-
|
179
|
-
|
180
|
-
#
|
181
|
-
# @param [Hash] scope_criteria the field to scope for as the key and the
|
182
|
-
# value to compare against the other log messages
|
183
|
-
#
|
184
|
-
# @example For all messages before specified date
|
185
|
-
#
|
186
|
-
# Indy.search(LOG_FILE).before(:time => time).for(:all)
|
187
|
-
# Indy.search(LOG_FILE).before(:time => time, :span => 10).for(:all)
|
188
|
-
#
|
189
|
-
def before(scope_criteria)
|
190
|
-
if scope_criteria[:time]
|
191
|
-
time = parse_date(scope_criteria[:time])
|
192
|
-
@inclusive = scope_criteria[:inclusive] || false
|
193
|
-
|
194
|
-
if scope_criteria[:span]
|
195
|
-
span = (scope_criteria[:span].to_i * 60).seconds
|
196
|
-
within(:time => [time - span, time], :inclusive => scope_criteria[:inclusive])
|
197
|
-
else
|
198
|
-
@end_time = time
|
199
|
-
end
|
200
|
-
end
|
177
|
+
self
|
178
|
+
end
|
201
179
|
|
202
|
-
|
180
|
+
#
|
181
|
+
# Before scopes the eventual search to all entries prior to this point.
|
182
|
+
#
|
183
|
+
# @param [Hash] scope_criteria the field to scope for as the key and the
|
184
|
+
# value to compare against the other log messages
|
185
|
+
#
|
186
|
+
# @example For all messages before specified date
|
187
|
+
#
|
188
|
+
# Indy.search(LOG_FILE).before(:time => time).for(:all)
|
189
|
+
# Indy.search(LOG_FILE).before(:time => time, :span => 10).for(:all)
|
190
|
+
#
|
191
|
+
def before(scope_criteria)
|
192
|
+
if scope_criteria[:time]
|
193
|
+
time = parse_date(scope_criteria[:time])
|
194
|
+
@inclusive = scope_criteria[:inclusive] || false
|
195
|
+
|
196
|
+
if scope_criteria[:span]
|
197
|
+
span = (scope_criteria[:span].to_i * 60).seconds
|
198
|
+
within(:time => [time - span, time], :inclusive => scope_criteria[:inclusive])
|
199
|
+
else
|
200
|
+
@end_time = time
|
201
|
+
end
|
203
202
|
end
|
204
203
|
|
205
|
-
|
206
|
-
|
207
|
-
time = parse_date(scope_criteria[:time])
|
204
|
+
self
|
205
|
+
end
|
208
206
|
|
209
|
-
|
210
|
-
|
207
|
+
def around(scope_criteria)
|
208
|
+
if scope_criteria[:time]
|
209
|
+
time = parse_date(scope_criteria[:time])
|
211
210
|
|
212
|
-
|
213
|
-
|
214
|
-
end
|
211
|
+
# does @inclusive add any real value to the #around method?
|
212
|
+
@inclusive = scope_criteria[:inclusive] || false
|
215
213
|
|
216
|
-
|
214
|
+
half_span = ((scope_criteria[:span].to_i * 60)/2).seconds rescue 300.seconds
|
215
|
+
within(:time => [time - half_span, time + half_span])
|
217
216
|
end
|
218
217
|
|
218
|
+
self
|
219
|
+
end
|
219
220
|
|
220
|
-
#
|
221
|
-
# Within scopes the eventual search to all entries between two points.
|
222
|
-
#
|
223
|
-
# @param [Hash] scope_criteria the field to scope for as the key and the
|
224
|
-
# value to compare against the other log messages
|
225
|
-
#
|
226
|
-
# @example For all messages within the specified dates
|
227
|
-
#
|
228
|
-
# Indy.search(LOG_FILE).within(:time => [start_time,stop_time]).for(:all)
|
229
|
-
#
|
230
|
-
def within(scope_criteria)
|
231
|
-
if scope_criteria[:time]
|
232
|
-
@start_time, @end_time = scope_criteria[:time]
|
233
|
-
@inclusive = scope_criteria[:inclusive] || false
|
234
|
-
end
|
235
221
|
|
236
|
-
|
222
|
+
#
|
223
|
+
# Within scopes the eventual search to all entries between two points.
|
224
|
+
#
|
225
|
+
# @param [Hash] scope_criteria the field to scope for as the key and the
|
226
|
+
# value to compare against the other log messages
|
227
|
+
#
|
228
|
+
# @example For all messages within the specified dates
|
229
|
+
#
|
230
|
+
# Indy.search(LOG_FILE).within(:time => [start_time,stop_time]).for(:all)
|
231
|
+
#
|
232
|
+
def within(scope_criteria)
|
233
|
+
if scope_criteria[:time]
|
234
|
+
@start_time, @end_time = scope_criteria[:time]
|
235
|
+
@inclusive = scope_criteria[:inclusive] || false
|
237
236
|
end
|
238
237
|
|
238
|
+
self
|
239
|
+
end
|
239
240
|
|
240
|
-
private
|
241
241
|
|
242
|
-
|
243
|
-
# Sets the source for the Indy instance.
|
244
|
-
#
|
245
|
-
# @param [String,Hash] source A filename, or log content as a string. Use a Hash with :cmd key to specify a command string.
|
246
|
-
#
|
247
|
-
# @example
|
248
|
-
#
|
249
|
-
# source("apache.log")
|
250
|
-
# source(:cmd => "cat apache.log")
|
251
|
-
# source("INFO 2000-09-07 MyApp - Entering APPLICATION.\nINFO 2000-09-07 MyApp - Entering APPLICATION.")
|
252
|
-
#
|
253
|
-
def source=(param)
|
242
|
+
private
|
254
243
|
|
255
|
-
|
256
|
-
|
244
|
+
#
|
245
|
+
# Sets the source for the Indy instance.
|
246
|
+
#
|
247
|
+
# @param [String,Hash] source A filename, or log content as a string. Use a Hash with :cmd key to specify a command string.
|
248
|
+
#
|
249
|
+
# @example
|
250
|
+
#
|
251
|
+
# source("apache.log")
|
252
|
+
# source(:cmd => "cat apache.log")
|
253
|
+
# source("INFO 2000-09-07 MyApp - Entering APPLICATION.\nINFO 2000-09-07 MyApp - Entering APPLICATION.")
|
254
|
+
#
|
255
|
+
def source=(param)
|
257
256
|
|
258
|
-
|
259
|
-
|
260
|
-
end
|
257
|
+
cmd = param[:cmd] rescue nil
|
258
|
+
@source[:cmd] = param[:cmd] if cmd
|
261
259
|
|
260
|
+
unless cmd
|
261
|
+
File.exist?(param) ? @source[:file] = param : @source[:string] = param
|
262
262
|
end
|
263
263
|
|
264
|
-
|
265
|
-
# Search the @source and yield to the block the line that was found
|
266
|
-
# with @pattern
|
267
|
-
#
|
268
|
-
# This method is supposed to be used internally.
|
269
|
-
#
|
270
|
-
def _search(&block)
|
271
|
-
time_search = use_time_criteria?
|
272
|
-
source_io = open_source
|
264
|
+
end
|
273
265
|
|
274
|
-
|
266
|
+
#
|
267
|
+
# Set @pattern as well as @log_regexp, @log_fields, and @time_field
|
268
|
+
#
|
269
|
+
# @param [Array] pattern_array an Array with the regular expression as the first element
|
270
|
+
# followed by list of fields (Symbols) in the log entry
|
271
|
+
# to use for comparison against each log line.
|
272
|
+
#
|
273
|
+
def update_log_pattern( pattern_array )
|
274
|
+
|
275
|
+
case pattern_array
|
276
|
+
when :default, nil
|
277
|
+
@pattern = DEFAULT_LOG_PATTERN
|
278
|
+
else
|
279
|
+
@pattern = pattern_array
|
280
|
+
end
|
281
|
+
|
282
|
+
@log_regexp, *@log_fields = @pattern
|
275
283
|
|
276
|
-
|
284
|
+
@time_field = ( @log_fields.include?(:time) ? :time : nil )
|
277
285
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
286
|
+
end
|
287
|
+
|
288
|
+
#
|
289
|
+
# Search the @source and yield to the block the line that was found
|
290
|
+
# with @log_regexp and @log_fields
|
291
|
+
#
|
292
|
+
# This method is supposed to be used internally.
|
293
|
+
#
|
294
|
+
def _search(&block)
|
283
295
|
|
284
|
-
|
296
|
+
time_search = use_time_criteria?
|
285
297
|
|
298
|
+
source_io = open_source
|
299
|
+
results = source_io.each.collect do |line|
|
300
|
+
|
301
|
+
hash = parse_line(line)
|
302
|
+
|
303
|
+
if time_search
|
304
|
+
set_time(hash)
|
305
|
+
next unless inside_time_window?(hash)
|
306
|
+
else
|
307
|
+
hash[:_time] = nil if hash
|
286
308
|
end
|
287
309
|
|
288
|
-
|
310
|
+
next unless hash
|
311
|
+
block_given? ? block.call(hash) : nil
|
289
312
|
|
290
|
-
results.compact
|
291
313
|
end
|
292
314
|
|
315
|
+
source_io.close if @source[:file] || @source[:cmd]
|
293
316
|
|
294
|
-
|
295
|
-
|
296
|
-
#
|
297
|
-
def open_source
|
298
|
-
begin
|
317
|
+
results.compact
|
318
|
+
end
|
299
319
|
|
300
|
-
case @source.keys.first # and only
|
301
|
-
when :cmd
|
302
|
-
source_io = exec_command(@source[:cmd])
|
303
|
-
raise "Failed to execute command (#{@source[:cmd]})" if source_io.nil?
|
304
320
|
|
305
|
-
|
306
|
-
|
307
|
-
|
321
|
+
#
|
322
|
+
# Return a log io object
|
323
|
+
#
|
324
|
+
def open_source
|
325
|
+
begin
|
308
326
|
|
309
|
-
|
310
|
-
|
327
|
+
case @source.keys.first # and only
|
328
|
+
when :cmd
|
329
|
+
source_io = exec_command(@source[:cmd])
|
330
|
+
raise "Failed to execute command (#{@source[:cmd]})" if source_io.nil?
|
311
331
|
|
312
|
-
|
313
|
-
|
314
|
-
|
332
|
+
when :file
|
333
|
+
source_io = File.open(@source[:file], 'r')
|
334
|
+
raise "Filed to open file: #{@source[:file]}" if source_io.nil?
|
315
335
|
|
316
|
-
|
317
|
-
|
336
|
+
when :string
|
337
|
+
source_io = StringIO.new( @source[:string] )
|
338
|
+
|
339
|
+
else
|
340
|
+
raise "Unsupported log source: #{@source.inspect}"
|
318
341
|
end
|
319
342
|
|
320
|
-
|
343
|
+
rescue Exception => e
|
344
|
+
raise "Unable to open log source. (#{e.message})"
|
321
345
|
end
|
322
346
|
|
323
|
-
|
324
|
-
|
325
|
-
#
|
326
|
-
# @param [String] line The log line
|
327
|
-
# @param [Array] pattern_array The match regexp string, followed by log fields
|
328
|
-
# see Class method search
|
329
|
-
#
|
330
|
-
def parse_line( line, pattern_array = @pattern)
|
331
|
-
regexp, *fields = pattern_array
|
347
|
+
source_io
|
348
|
+
end
|
332
349
|
|
333
|
-
|
334
|
-
|
335
|
-
|
350
|
+
#
|
351
|
+
# Return a hash of field=>value pairs for the log line
|
352
|
+
#
|
353
|
+
# @param [String] line The log line
|
354
|
+
# @param [Array] pattern_array The match regexp string, followed by log fields
|
355
|
+
# see Class method search
|
356
|
+
#
|
357
|
+
def parse_line( line )
|
336
358
|
|
337
|
-
|
338
|
-
|
359
|
+
if /#{@log_regexp}/.match(line)
|
360
|
+
values = /#{@log_regexp}/.match(line).captures
|
361
|
+
raise "Field mismatch between log pattern and log data. The data is: '#{values.join(':::')}'" unless values.length == @log_fields.length
|
339
362
|
|
340
|
-
|
341
|
-
|
342
|
-
end
|
363
|
+
hash = Hash[ *@log_fields.zip( values ).flatten ]
|
364
|
+
hash[:line] = line.strip
|
343
365
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
def use_time_criteria?
|
348
|
-
if @start_time || @end_time
|
349
|
-
# ensure both boundaries are set
|
350
|
-
@start_time = @start_time || FOREVER_AGO
|
351
|
-
@end_time = @end_time || FOREVER
|
352
|
-
end
|
366
|
+
hash
|
367
|
+
end
|
368
|
+
end
|
353
369
|
|
354
|
-
|
370
|
+
#
|
371
|
+
# Return true if start or end time has been set, and a :time field exists
|
372
|
+
#
|
373
|
+
def use_time_criteria?
|
374
|
+
if @start_time || @end_time
|
375
|
+
# ensure both boundaries are set
|
376
|
+
@start_time = @start_time || FOREVER_AGO
|
377
|
+
@end_time = @end_time || FOREVER
|
355
378
|
end
|
356
379
|
|
380
|
+
return (@time_field && @start_time && @end_time)
|
381
|
+
end
|
357
382
|
|
358
|
-
#
|
359
|
-
# Set the :_time value in the hash
|
360
|
-
#
|
361
|
-
# @param [Hash] hash The log line hash to modify
|
362
|
-
#
|
363
|
-
def set_time(hash)
|
364
|
-
hash[:_time] = parse_date( hash ) if hash
|
365
|
-
end
|
366
383
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
if @inclusive
|
376
|
-
true unless line_hash[:_time] > @end_time or line_hash[:_time] < @start_time
|
377
|
-
else
|
378
|
-
true unless line_hash[:_time] >= @end_time or line_hash[:_time] <= @start_time
|
379
|
-
end
|
380
|
-
end
|
384
|
+
#
|
385
|
+
# Set the :_time value in the hash
|
386
|
+
#
|
387
|
+
# @param [Hash] hash The log line hash to modify
|
388
|
+
#
|
389
|
+
def set_time(hash)
|
390
|
+
hash[:_time] = parse_date( hash ) if hash
|
391
|
+
end
|
381
392
|
|
393
|
+
#
|
394
|
+
# Evaluate if a log line satisfies the configured time conditions
|
395
|
+
#
|
396
|
+
# @param [Hash] line_hash The log line hash to be evaluated
|
397
|
+
#
|
398
|
+
def inside_time_window?( line_hash )
|
399
|
+
|
400
|
+
if line_hash && line_hash[:_time]
|
401
|
+
if @inclusive
|
402
|
+
true unless line_hash[:_time] > @end_time or line_hash[:_time] < @start_time
|
403
|
+
else
|
404
|
+
true unless line_hash[:_time] >= @end_time or line_hash[:_time] <= @start_time
|
405
|
+
end
|
382
406
|
end
|
383
407
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
408
|
+
end
|
409
|
+
|
410
|
+
#
|
411
|
+
# Return a valid DateTime object for the log line or string
|
412
|
+
#
|
413
|
+
# @param [String, Hash] param The log line hash, or string to be evaluated
|
414
|
+
#
|
415
|
+
def parse_date(param)
|
416
|
+
return nil unless @time_field
|
391
417
|
|
392
|
-
|
418
|
+
time_string = param[@time_field] ? param[@time_field] : param
|
393
419
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
end
|
420
|
+
begin
|
421
|
+
# Attempt the appropriate parse method
|
422
|
+
@time_format ? DateTime.strptime(time_string, @time_format) : DateTime.parse(time_string)
|
423
|
+
rescue
|
424
|
+
# If appropriate, fall back to simple parse method
|
425
|
+
DateTime.parse(time_string) if @time_format rescue nil
|
401
426
|
end
|
427
|
+
end
|
402
428
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
429
|
+
#
|
430
|
+
# Try opening the string as a command string, returning an IO object
|
431
|
+
#
|
432
|
+
# @param [String] command_string string of command that will return log contents
|
433
|
+
#
|
434
|
+
def exec_command(command_string)
|
409
435
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
end
|
416
|
-
io
|
436
|
+
begin
|
437
|
+
io = IO.popen(command_string)
|
438
|
+
return nil if io.eof?
|
439
|
+
rescue
|
440
|
+
nil
|
417
441
|
end
|
442
|
+
io
|
443
|
+
end
|
418
444
|
|
445
|
+
#
|
446
|
+
# Define Struct::Line with the fields configured with @pattern
|
447
|
+
#
|
448
|
+
def define_struct
|
449
|
+
fields = (@log_fields + [:_time, :line]).sort_by{|e|e.to_s}
|
450
|
+
|
451
|
+
# suppress Struct 'redefining constant' warning
|
452
|
+
verbose = $VERBOSE
|
453
|
+
$VERBOSE = nil
|
454
|
+
|
455
|
+
Struct.new( "Line", *fields )
|
456
|
+
|
457
|
+
$VERBOSE = verbose
|
458
|
+
end
|
419
459
|
|
460
|
+
#
|
461
|
+
# Return a Struct::Line object populated with the values from the line_hash
|
462
|
+
#
|
463
|
+
# @param [Hash] line_hash a hash of :field_name => value pairs for one log line
|
464
|
+
#
|
465
|
+
def create_struct( line_hash )
|
466
|
+
params = line_hash.keys.sort_by{|e|e.to_s}.collect {|k| line_hash[k]}
|
467
|
+
Struct::Line.new( *params )
|
420
468
|
end
|
469
|
+
|
470
|
+
end
|