class Chef::Telemeter::Sender

Attributes

config[R]
session_files[R]

Public Class Methods

find_session_files(config) click to toggle source
# File lib/chef/telemeter/sender.rb, line 40
def self.find_session_files(config)
  Telemeter::Log.info("Looking for telemetry data to submit")
  session_search = File.join(config[:payload_dir], "telemetry-payload-*.yml")
  session_files = Dir.glob(session_search)
  Telemeter::Log.info("Found #{session_files.length} sessions to submit")
  session_files
end
new(session_files, config) click to toggle source
# File lib/chef/telemeter/sender.rb, line 48
def initialize(session_files, config)
  @session_files = session_files
  @config = config
end
start_upload_thread(config) click to toggle source
# File lib/chef/telemeter/sender.rb, line 31
def self.start_upload_thread(config)
  # Find the files before we spawn the thread - otherwise
  # we may accidentally pick up the current run's session file if it
  # finishes before the thread scans for new files
  session_files = Sender.find_session_files(config)
  sender = Sender.new(session_files, config)
  Thread.new { sender.run }
end

Public Instance Methods

process_session(path) click to toggle source
# File lib/chef/telemeter/sender.rb, line 76
def process_session(path)
  Telemeter::Log.info("Processing telemetry entries from #{path}")
  content = load_and_clear_session(path)
  submit_session(content)
end
run() click to toggle source
# File lib/chef/telemeter/sender.rb, line 53
def run
  if Telemeter.enabled?
    Telemeter::Log.info("Telemetry enabled, beginning upload of previous session(s)")
    # dev mode telemetry gets sent to a different location

    if config[:dev_mode]
      ENV["CHEF_TELEMETRY_ENDPOINT"] ||= "https://telemetry-acceptance.chef.io"
    end
    session_files.each { |path| process_session(path) }
  else
    # If telemetry is not enabled, just clean up and return. Even though
    # the telemetry gem will not send if disabled, log output saying that we're submitting
    # it when it has been disabled can be alarming.
    Telemeter::Log.info("Telemetry disabled, clearing any existing session captures without sending them.")
    session_files.each { |path| FileUtils.rm_rf(path) }
  end
  require "fileutils" unless defined?(FileUtils)
  FileUtils.rm_rf(config[:session_file])
  Telemeter::Log.info("Terminating, nothing more to do.")
rescue => e
  Telemeter::Log.fatal "Sender thread aborted: '#{e}' failed at  #{e.backtrace[0]}"
end
submit_entry(telemetry, entry, sequence, total) click to toggle source
# File lib/chef/telemeter/sender.rb, line 101
def submit_entry(telemetry, entry, sequence, total)
  Telemeter::Log.info("Submitting telemetry entry #{sequence}/#{total}: #{entry} ")
  telemetry.deliver(entry)
  Telemeter::Log.info("Entry #{sequence}/#{total} submitted.")
rescue => e
  # No error handling in telemetry lib, so at least track the failrue
  Telemeter::Log.error("Failed to send entry #{sequence}/#{total}: #{e}")
  Telemeter::Log.error("Backtrace: #{e.backtrace} ")
end
submit_session(content) click to toggle source
# File lib/chef/telemeter/sender.rb, line 82
def submit_session(content)
  # Each file contains the actions taken within a single run of the chef tool.
  # Each run is one session, so we'll first remove remove the session file
  # to force creating a new one.
  FileUtils.rm_rf(config[:session_file])
  # We'll use the version captured in the sesion file
  entries = content["entries"]
  total = entries.length
  product_info = config[:product] || {}
  telemetry = Telemetry.new(product: product_info[:name] || "chef-workstation",
                            origin: product_info[:origin] || "command-line",
                            product_version: product_info[:version] || content["version"],
                            install_context: product_info[:install_context] || "omnibus")
  total = entries.length
  entries.each_with_index do |entry, x|
    submit_entry(telemetry, entry, x + 1, total)
  end
end

Private Instance Methods

load_and_clear_session(path) click to toggle source
# File lib/chef/telemeter/sender.rb, line 113
def load_and_clear_session(path)
  content = File.read(path)
  # We'll remove it now instead of after we parse or submit it -
  # if we fail to deliver, we don't want to be stuck resubmitting it if the problem
  # was due to payload. This is a trade-off - if we get a transient error, the
  # payload will be lost.
  # TODO: Improve error handling so we can intelligently decide whether to
  #       retry a failed load or failed submit.
  FileUtils.rm_rf(path)
  YAML.load(content)
end