Class: Indy::Source
- Inherits:
-
Object
- Object
- Indy::Source
- Defined in:
- lib/indy/source.rb
Overview
A StringIO interface to the underlying log source.
Defined Under Namespace
Classes: FieldMismatchException, Invalid
Instance Attribute Summary collapse
-
#connection ⇒ Object
readonly
log source connection string (cmd, filename or log data).
-
#io ⇒ Object
readonly
the StringIO object.
-
#log_definition ⇒ Object
log definition.
-
#type ⇒ Object
readonly
log source type.
Instance Method Summary collapse
-
#discover_connection(param) ⇒ Object
Support source being passed in without key indicating type.
-
#entries ⇒ Object
array of log lines from source.
-
#exec_command(command_string) ⇒ Object
Execute the source’s connection string, returning an IO object.
-
#find(boundary, value, start, stop) ⇒ Object
Binary search for a time condition.
-
#find_adjacent(boundary, value, start, stop, mid_index) ⇒ Object
Step forward or backward by one, looking for the boundary of the value.
-
#find_first(value, start, stop) ⇒ Object
find index of first record to match value.
-
#find_last(value, start, stop) ⇒ Object
find index of last record to match value.
-
#find_middle(start, stop) ⇒ Object
Find index and time at mid point.
-
#initialize(param, log_definition = nil) ⇒ Source
constructor
Creates a Source object.
-
#load_data ⇒ Object
read source data and populate instance variables.
-
#num_entries ⇒ Object
the number of lines in the source.
-
#open(time_boundaries = nil) ⇒ Object
Return a StringIO object to provide access to the underlying log source.
- #open_cmd ⇒ Object
- #open_file ⇒ Object
- #open_or_return_file(param) ⇒ Object
- #open_string ⇒ Object
-
#scope_by_time(time_boundaries) ⇒ Object
Return entries that meet time criteria.
-
#set_connection(type, value) ⇒ Object
set the source connection type and connection_string.
-
#time_at(index, delta = 0) ⇒ Object
Return the time of a log entry index, with an optional offset.
Constructor Details
#initialize(param, log_definition = nil) ⇒ Source
Creates a Source object.
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/indy/source.rb', line 31 def initialize(param,log_definition=nil) raise Indy::Source::Invalid, "No source specified." if param.nil? self.log_definition = log_definition || LogDefinition.new() return discover_connection(param) unless param.respond_to?(:keys) if param[:cmd] set_connection(:cmd, param[:cmd]) elsif param[:file] set_connection(:file, open_or_return_file(param[:file])) elsif param[:string] set_connection(:string, param[:string]) end end |
Instance Attribute Details
#connection ⇒ Object (readonly)
log source connection string (cmd, filename or log data)
18 19 20 |
# File 'lib/indy/source.rb', line 18 def connection @connection end |
#io ⇒ Object (readonly)
the StringIO object
21 22 23 |
# File 'lib/indy/source.rb', line 21 def io @io end |
#log_definition ⇒ Object
log definition
12 13 14 |
# File 'lib/indy/source.rb', line 12 def log_definition @log_definition end |
#type ⇒ Object (readonly)
log source type. :cmd, :file, or :string
15 16 17 |
# File 'lib/indy/source.rb', line 15 def type @type end |
Instance Method Details
#discover_connection(param) ⇒ Object
Support source being passed in without key indicating type
47 48 49 50 51 52 53 54 55 |
# File 'lib/indy/source.rb', line 47 def discover_connection(param) if param.respond_to?(:read) and param.respond_to?(:rewind) set_connection(:file, param) elsif param.respond_to?(:to_s) and param.respond_to?(:length) set_connection(:string, param) else raise Indy::Source::Invalid end end |
#entries ⇒ Object
array of log lines from source
216 217 218 219 |
# File 'lib/indy/source.rb', line 216 def entries load_data unless @entries @entries end |
#exec_command(command_string) ⇒ Object
Execute the source’s connection string, returning an IO object
199 200 201 202 203 |
# File 'lib/indy/source.rb', line 199 def exec_command(command_string) io = IO.popen(command_string) raise Indy::Source::Invalid, "No data returned from command string execution" if io.eof? io end |
#find(boundary, value, start, stop) ⇒ Object
Binary search for a time condition
180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/indy/source.rb', line 180 def find(boundary,value,start,stop) return start if start == stop mid_index, mid_time = find_middle(start,stop) if mid_time == value find_adjacent(boundary,value,start,stop,mid_index) elsif mid_time > value mid_index -= 1 if mid_index == stop find(boundary, value, start, mid_index) elsif mid_time < value mid_index += 1 if mid_index == start find(boundary, value, mid_index, stop) end end |
#find_adjacent(boundary, value, start, stop, mid_index) ⇒ Object
Step forward or backward by one, looking for the boundary of the value
148 149 150 151 152 153 154 155 |
# File 'lib/indy/source.rb', line 148 def find_adjacent(boundary,value,start,stop,mid_index) case boundary when :first (time_at(mid_index,-1) == value) ? find_first(value,start-1,stop) : mid_index when :last (time_at(mid_index,1) == value) ? find_last(value,start,stop+1) : mid_index end end |
#find_first(value, start, stop) ⇒ Object
find index of first record to match value
123 124 125 126 |
# File 'lib/indy/source.rb', line 123 def find_first(value,start,stop) return start if time_at(start) > value find(:first,value,start,stop) end |
#find_last(value, start, stop) ⇒ Object
find index of last record to match value
131 132 133 134 |
# File 'lib/indy/source.rb', line 131 def find_last(value,start,stop) return stop if time_at(stop) < value find(:last,value,start,stop) end |
#find_middle(start, stop) ⇒ Object
Find index and time at mid point
139 140 141 142 143 |
# File 'lib/indy/source.rb', line 139 def find_middle(start, stop) index = ((stop - start) / 2) + start time = time_at(index) [index, time] end |
#load_data ⇒ Object
read source data and populate instance variables
224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/indy/source.rb', line 224 def load_data self.open if @io.nil? if @log_definition.multiline entire_log = @io.read @entries = entire_log.scan(@log_definition.entry_regexp).map{|matchdata|matchdata[0]} else @entries = @io.readlines end @io.rewind @entries.delete_if {|entry| entry.match(/^\s*$/)} @num_entries = @entries.count end |
#num_entries ⇒ Object
the number of lines in the source
208 209 210 211 |
# File 'lib/indy/source.rb', line 208 def num_entries load_data unless @num_entries @num_entries end |
#open(time_boundaries = nil) ⇒ Object
Return a StringIO object to provide access to the underlying log source
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/indy/source.rb', line 75 def open(time_boundaries=nil) begin open_method = ('open_' + @type.to_s).intern self.send(open_method) rescue Exception => e raise Indy::Source::Invalid, "Unable to open log source. (#{e.})" end load_data scope_by_time(time_boundaries) if time_boundaries @entries end |
#open_cmd ⇒ Object
87 88 89 90 |
# File 'lib/indy/source.rb', line 87 def open_cmd @io = StringIO.new(exec_command(@connection).read) raise "Failed to execute command (#{@connection.inspect})" if @io.nil? end |
#open_file ⇒ Object
92 93 94 95 96 |
# File 'lib/indy/source.rb', line 92 def open_file @connection.rewind @io = StringIO.new(@connection.read) raise "Failed to open file: #{@connection.inspect}" if @io.nil? end |
#open_or_return_file(param) ⇒ Object
65 66 67 68 69 70 |
# File 'lib/indy/source.rb', line 65 def open_or_return_file(param) return param if param.respond_to? :pos file = File.open(param, 'r') raise ArgumentError, "Unable to open file parameter: '#{file}'" unless file.respond_to? :pos file end |
#open_string ⇒ Object
98 99 100 101 |
# File 'lib/indy/source.rb', line 98 def open_string @io = StringIO.new(@connection) raise "Failed to create StringIO from source (#{@connection.inspect})" if @io.nil? end |
#scope_by_time(time_boundaries) ⇒ Object
Return entries that meet time criteria
107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/indy/source.rb', line 107 def scope_by_time(time_boundaries) start_time, end_time = time_boundaries scope_end = num_entries - 1 # short circuit the search if possible if (time_at(0) > end_time) or (time_at(-1) < start_time) @entries = [] return @entries end scope_begin = find_first(start_time, 0, scope_end) scope_end = find_last(end_time, scope_begin, scope_end) @entries = @entries[scope_begin..scope_end] end |
#set_connection(type, value) ⇒ Object
set the source connection type and connection_string
60 61 62 63 |
# File 'lib/indy/source.rb', line 60 def set_connection(type, value) @type = type @connection = value end |
#time_at(index, delta = 0) ⇒ Object
Return the time of a log entry index, with an optional offset
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/indy/source.rb', line 160 def time_at(index, delta=0) begin entry = @entries[index + delta] time = @log_definition.parse_entry(entry)[:time] result = Indy::Time.parse_date(time, @log_definition.time_format) rescue FieldMismatchException => fme raise rescue Exception => e msg = "Unable to parse time from entry. Time value was #{time.inspect}. Original exception was:\n#{e.class}\n" raise Indy::Time::ParseException, msg + e. end if result.nil? raise Indy::Time::ParseException, "Unable to parse datetime. Raw value was #{time.inspect}. Entry was #{entry}." end result end |