class AwsUtils::AwsLogs

Constants

LOG_LEVELS
MAX_EVENTS
MAX_STREAMS

Public Instance Methods

run() click to toggle source
# File lib/awsutils/awslogs.rb, line 17
def run
  print_events
rescue TooManyEventsError
  puts "Too many log events to process (MAX: #{MAX_EVENTS}). " \
       'Please try filtering the output with -f'
  exit 3
rescue TooManyStreamsError
  puts "Too many streams to process (MAX: #{MAX_STREAMS}). " \
       'Please try filtering the output with -s'
  exit 3
rescue LogGroupNotFoundError
  puts "No log groups found starting with #{opts[:group]}"
  exit 1
rescue NoStreamsError
  puts 'Streams filter did not return any streams'
  exit 1
rescue MultipleGroupsError => e
  puts e.message
  exit 2
end

Private Instance Methods

chunk_events(streams_chunk, token = nil) click to toggle source
# File lib/awsutils/awslogs.rb, line 94
def chunk_events(streams_chunk, token = nil)
  parameters = {
    log_group_name: log_group_name,
    log_stream_names: streams_chunk,
    start_time: max_age_ts,
    next_token: token
  }
  parameters[:filter_pattern] = opts[:filter_pattern] if opts[:filter_pattern]
  response = cloudwatchlogs.filter_log_events parameters
  collector = response.events
  collector += chunk_events(streams_chunk, response.next_token) if response.next_token
  raise TooManyEventsError if collector.count > MAX_EVENTS

  collector
end
cloudwatchlogs() click to toggle source
# File lib/awsutils/awslogs.rb, line 185
def cloudwatchlogs
  @cloudwatchlogs ||= Aws::CloudWatchLogs::Client.new
end
filtered_log_events() click to toggle source
# File lib/awsutils/awslogs.rb, line 120
def filtered_log_events
  return log_events unless opts[:request_id]

  log_events.select { |event| event.message =~ /\b#{opts[:request_id]}\b/ }
end
log_events() click to toggle source
# File lib/awsutils/awslogs.rb, line 110
def log_events
  # puts "Filtering from #{streams.count} streams in #{streams.count / 50 + 1} chunks"
  collector = []
  streams.each_slice(50) { |streams_chunk| collector += chunk_events(streams_chunk) }

  puts 'No events found' if collector.empty?

  collector.sort_by(&:timestamp)
end
log_group_name() click to toggle source
# File lib/awsutils/awslogs.rb, line 81
def log_group_name
  @log_group_name ||= begin
    r = cloudwatchlogs.describe_log_groups log_group_name_prefix: opts[:group]
    return r.log_groups.first.log_group_name if r.log_groups.count == 1
    raise LogGroupNotFoundError if r.log_groups.empty?

    err_msg = "Group filter #{opts[:group]} found multiple groups:\n\n"
    err_msg += r.log_groups.map(&:log_group_name).join("\n")
    err_msg += "\nMore than 50 log groups returned. Only showed the first 50." if r.next_token
    raise MultipleGroupsError, err_msg
  end
end
max_age_ts() click to toggle source
# File lib/awsutils/awslogs.rb, line 179
def max_age_ts
  return 0 unless opts[:age]

  (Time.at(Time.now - opts[:age]).to_f * 1_000).to_i
end
opts() click to toggle source
# File lib/awsutils/awslogs.rb, line 40
def opts
  @opts ||= Optimist.options do
    opt :age,
        'Max age in seconds',
        short: 'a',
        type: Integer
    opt :group,
        'Log group (e.g. /aws/lambda/sf-updater)',
        required: true,
        type: String,
        short: 'g'
    opt :filter_pattern,
        'See: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/FilterAndPatternSyntax.html',
        type: String,
        short: 'f'
    opt :streams_prefix,
        'E.g. 2016/08',
        type: String,
        short: 's'
    opt :timestamp,
        'Include the timestamp from the event metadata in the output',
        short: 't',
        default: false
    opt :show_request_id,
        'Show the request ID in every log message',
        short: 'r',
        default: false
    opt :request_id,
        'Print only messages with a specific request ID',
        short: 'R',
        type: :string
    opt :log_level,
        'Lowest log level to show',
        default: 'INFO',
        short: 'l'
    opt :show_stream_name,
        'Include the name of the log stream on the output line',
        default: false
  end
end
print_events() click to toggle source
show_logentry?(level) click to toggle source
# File lib/awsutils/awslogs.rb, line 153
def show_logentry?(level)
  return true unless LOG_LEVELS.include? level

  LOG_LEVELS.index(level.upcase) >= LOG_LEVELS.index(opts[:log_level].upcase)
end
streams(token = nil) click to toggle source
# File lib/awsutils/awslogs.rb, line 159
def streams(token = nil)
  parameters = {
    log_group_name: log_group_name,
    next_token: token
  }
  parameters[:log_stream_name_prefix] = opts[:streams_prefix] if opts[:streams_prefix]
  response = cloudwatchlogs.describe_log_streams parameters
  collector =
    response
    .log_streams
    .select { |s| s.last_event_timestamp && s.last_event_timestamp > max_age_ts }
    .map(&:log_stream_name)
  raise NoStreamsError if token.nil? && collector.count.zero?

  collector += streams(response.next_token) if response.next_token
  raise TooManyStreamsError if collector.count > MAX_STREAMS

  collector
end