Skip to content

Instantly share code, notes, and snippets.

@joshado
Created March 3, 2012 08:40
Show Gist options
  • Save joshado/1965016 to your computer and use it in GitHub Desktop.
Save joshado/1965016 to your computer and use it in GitHub Desktop.
Simple log CLI tool
#!/usr/bin/env ruby
require 'rubygems'
require 'tire'
require 'yajl/json_gem'
require 'optparse'
require 'optparse/time'
require 'time'
Tire::Configuration.url ENV['ES_BASE']
Query = {
:must => [],
:must_not => [],
:type => nil,
:from => '*',
:to => '*',
:follow => false,
:size => 10,
:output => "[%{@uuid}] %{@source_host}: %{@message}"
}
OptionParser.new do |opts|
opts.banner = "Usage: fa-logs [options]"
opts.on('--index <index>', "Specify which index to search, usually of the form 'logs-YYYY-MM-DD'") do |index|
Query[:index] = index
end
opts.on('--uuid <uuid>', "Display log entry with <UUID>") do |uuid|
Query[:display_uuid] = uuid
end
opts.on('--must <term>', "Must contain <term>") do |term|
Query[:must] << term
end
opts.on('--must-not <term>', "Must not contain <term>") do |term|
Query[:must_not] << term
end
opts.on('--from <time>', Time, "Query from a specific time") do |time|
Query[:from] = time.iso8601(2)
end
opts.on('--to <time>', Time, "Query to a specific time") do |time|
Query[:to] = time.iso8601(2)
end
opts.on('-n', '--size <num>', Integer, "Number of rows to show") do |size|
Query[:size] = size
end
opts.on('-f', '--follow', "Re-query until interrupted") do
Query[:follow] = true
end
opts.on('-o', '--output <format>', "Customise the output format (defaults to `[%{@uuid}] %{@source_host}: %{@message}`") do |format|
Query[:output] = format
end
end.parse!
if Query[:index] == nil
puts "You must supply the --index parameter, otherwise you'll overload ElasticSearch"
exit 1
end
def display_output( document, format )
format.gsub(/%\{([^\}]*)\}/) do |match|
match.gsub!(/[%{}]/,'')
out = document
match.split(".").each do |key|
out = out.send(:"#{key}")
end
out
end
end
def do_query(query, display_footer=true)
s = Tire.search(query[:index]) do
query do
boolean do
query[:must].each { |term| must { string term } }
query[:must_not].each { |term| must_not { string term } }
must { string "@timestamp:[#{query[:from]} TO #{query[:to]}]"}
end
end
size query[:size]
sort { by :@timestamp, 'desc' }
end
s.results.to_a.reverse.each do |document|
puts display_output( document, Query[:output] )
# puts "[#{document[:@uuid]}] #{ document[:@source_host] }: #{ document[:@message] }"
end
if display_footer
puts ""
puts " Query took #{s.results.time/1000.0}s"
puts " Displayed #{s.results.size} of #{s.results.total} hits"
end
s.results[0][:@timestamp] if s.results[0]
end
require 'tire/results/item'
class Tire::Results::Item
def to_hash
hash = @attributes
if hash.is_a?(Hash)
hash.each_pair do |key,value|
if value.is_a?(Tire::Results::Item)
hash[key] = value.to_hash
end
end
elsif hash.is_a?(Array)
hash.map! { |h| h.to_hash }
end
hash
end
end
if Query[:display_uuid]
require 'pp'
s = Tire.search(Query[:index]) do
query do
boolean do
must { string "@uuid:\"#{Query[:display_uuid]}\""}
end
end
end
item = s.results.to_a.first
if item
pp item.to_hash
else
puts "UUID not found."
end
elsif Query[:follow]
@last_time = nil
while true
if @last_time
Query[:from] = (Time.parse(@last_time) + 0.1).iso8601(3)
Query[:size] = 1000
end
set_time = do_query(Query, false)
@last_time = set_time if set_time
sleep 1
end
else
do_query(Query, true)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment