ResultsReader
parses Splunk's XML format for results into
Ruby objects.
You can use both Nokogiri and REXML. By default, the
ResultsReader
will try to use Nokogiri, and if it is not
available will fall back to REXML. If you want other behavior, see
xml_shim.rb
for how to set the XML library.
+ResultsReader is an Enumerable
, so it has methods such as
each
and each_with_index
. However, since it's
a stream parser, once you iterate through it once, it will thereafter be
empty.
Do not use ResultsReader
with the results of the
create_export
or create_stream
methods on
Service
or Jobs
. These methods use endpoints
which return a different set of data structures. Use
MultiResultsReader
instead for those cases. If you do use
ResultsReader
, it will return a concatenation of all
non-preview events in the stream, but that behavior should be considered
deprecated, and will result in a warning.
The ResultsReader object has two additional methods:
is_preview?
returns a Boolean value that indicates whether
these results are a preview from an unfinished search or not
fields
returns an array of all the fields that may appear in a
result in this set, in the order they should be displayed (if you're
going to make a table or the like)
The values yielded by calling each
and similar methods on
ResultsReader
are of class Event
, which is a
subclass of Hash
with one extra method,
segmented_raw
. The fields of the event are available as values
in the hash, with no escaped characters and no XML tags. The
_raw
field, however, is returned with extra XML specifying how
terms should be highlighted for display, and this full XML form is
available by called the segmented_raw
method. The XML returned
looks something like:
"<v xml:space=\"preserve\" trunc=\"0\">127.0.0.1 - admin [11/Feb/2013:10:42:49.790 -0800] \"POST /services/search/jobs/export HTTP/1.1\" 200 440404 - - - 257ms</v>"
Example:
require 'splunk-sdk-ruby' service = Splunk::connect(:username => "admin", :password => "changeme") stream = service.jobs.create_oneshot("search index=_internal | head 10") reader = Splunk::ResultsReader.new(stream) puts reader.is_preview? # Prints: false reader.each do |result| puts result # Prints the fields in the result as a Hash puts result.segmented_raw() # Prints the XML version of the _raw field end # Prints a sequence of Hashes containing events.
An Array
of all the fields that may appear in each result.
Note that any given result will contain a subset of these fields.
Returns: an Array
of Strings
.
# File lib/splunk-sdk-ruby/resultsreader.rb, line 150 def initialize(text_or_stream) if text_or_stream.nil? stream = StringIO.new("") elsif text_or_stream.is_a?(ExportStream) # The sensible behavior on streams from the export endpoints is to # skip all preview results and concatenate all others. The export # functions wrap their streams in ExportStream to mark that they need # this special handling. @is_export = true @reader = MultiResultsReader.new(text_or_stream).final_results() @is_preview = @reader.is_preview? @fields = @reader.fields return elsif !text_or_stream.respond_to?(:read) # Strip because the XML libraries can be pissy. stream = StringIO.new(text_or_stream.strip) else stream = text_or_stream end if !stream.nil? and stream.eof? @is_preview = nil @fields = [] else # We use a SAX parser. +listener+ is the event handler, but a SAX # parser won't usually transfer control during parsing. # To incrementally return results as we parse, we have to put # the parser into a +Fiber+ from which we can yield. listener = ResultsListener.new() @iteration_fiber = Fiber.new do if $splunk_xml_library == :nokogiri parser = Nokogiri::XML::SAX::Parser.new(listener) parser.parse(stream) else # Use REXML REXML::Document.parse_stream(stream, listener) end end @is_preview = @iteration_fiber.resume @fields = @iteration_fiber.resume @reached_end = false end end
# File lib/splunk-sdk-ruby/resultsreader.rb, line 194 def each() # If we have been passed a stream from an export endpoint, it should be # marked as such, and we handle it differently. if @is_export warn "[DEPRECATED] Do not use ResultsReader on the output of the " + "export endpoint. Use MultiResultsReader instead." enum = @reader.each() else enum = Enumerator.new() do |yielder| if !@iteration_fiber.nil? # Handle the case of empty files @reached_end = false while true result = @iteration_fiber.resume break if result.nil? or result == :end_of_results_set yielder << result end end @reached_end = true end end if block_given? # Apply the enumerator to a block if we have one enum.each() { |e| yield e } else enum # Otherwise return the enumerator itself end end
Are the results in this reader a preview from an unfinished search?
Returns: true
or false
, or nil
if
the stream is empty.
# File lib/splunk-sdk-ruby/resultsreader.rb, line 137 def is_preview? return @is_preview end
Skips the rest of the events in this ResultsReader.
# File lib/splunk-sdk-ruby/resultsreader.rb, line 225 def skip_remaining_results() if !@reached_end each() { |result|} end end