class Krane::ContainerLogs

Constants

DEFAULT_LINE_LIMIT

Attributes

container_name[R]
lines[R]

Public Class Methods

new(parent_id:, container_name:, namespace:, context:, logger:) click to toggle source
# File lib/krane/container_logs.rb, line 8
def initialize(parent_id:, container_name:, namespace:, context:, logger:)
  @parent_id = parent_id
  @container_name = container_name
  @namespace = namespace
  @context = context
  @logger = logger
  @lines = []
  @next_print_index = 0
  @printed_latest = false
end

Public Instance Methods

empty?() click to toggle source
# File lib/krane/container_logs.rb, line 25
def empty?
  lines.empty?
end
print_all() click to toggle source
print_latest(prefix: false) click to toggle source
printing_started?() click to toggle source
# File lib/krane/container_logs.rb, line 44
def printing_started?
  @printed_latest
end
sync() click to toggle source
# File lib/krane/container_logs.rb, line 19
def sync
  new_logs = fetch_latest
  return unless new_logs.present?
  @lines += sort_and_deduplicate(new_logs)
end

Private Instance Methods

fetch_latest() click to toggle source
# File lib/krane/container_logs.rb, line 50
def fetch_latest
  cmd = ["logs", @parent_id, "--container=#{container_name}", "--timestamps"]
  cmd << if @last_timestamp.present?
    "--since-time=#{rfc3339_timestamp(@last_timestamp)}"
  else
    "--tail=#{DEFAULT_LINE_LIMIT}"
  end
  out, _err, _st = kubectl.run(*cmd, log_failure: false)
  out.split("\n")
end
kubectl() click to toggle source
# File lib/krane/container_logs.rb, line 61
def kubectl
  task_config = TaskConfig.new(@context, @namespace, @logger)
  @kubectl ||= Kubectl.new(task_config: task_config, log_failure_by_default: false)
end
likely_duplicate?(timestamp) click to toggle source
# File lib/krane/container_logs.rb, line 99
def likely_duplicate?(timestamp)
  return false unless @last_timestamp && timestamp
  # The --since-time granularity the API server supports is not adequate to prevent duplicates
  # This comparison takes the fractional seconds into account
  timestamp <= @last_timestamp
end
rfc3339_timestamp(time) click to toggle source
# File lib/krane/container_logs.rb, line 66
def rfc3339_timestamp(time)
  time.strftime("%FT%T.%N%:z")
end
sort_and_deduplicate(logs) click to toggle source
# File lib/krane/container_logs.rb, line 70
def sort_and_deduplicate(logs)
  parsed_lines = logs.map { |line| split_timestamped_line(line) }
  sorted_lines = parsed_lines.sort do |(timestamp1, _msg1), (timestamp2, _msg2)|
    if timestamp1.nil?
      -1
    elsif timestamp2.nil?
      1
    else
      timestamp1 <=> timestamp2
    end
  end

  deduped = []
  sorted_lines.each do |timestamp, msg|
    next if likely_duplicate?(timestamp)
    @last_timestamp = timestamp if timestamp
    deduped << msg
  end
  deduped
end
split_timestamped_line(log_line) click to toggle source
# File lib/krane/container_logs.rb, line 91
def split_timestamped_line(log_line)
  timestamp, message = log_line.split(" ", 2)
  [Time.parse(timestamp), message]
rescue ArgumentError
  # Don't fail on unparsable timestamp
  [nil, log_line]
end