class DatadogChefEvents

helper class for sending events about chef runs

Attributes

event_body[R]
event_title[R]

Public Class Methods

new() click to toggle source
# File lib/chef/handler/datadog_chef_events.rb, line 16
def initialize
  @hostname = nil
  @run_status = nil
  @failure_notfications = nil

  @alert_type = ''
  @event_priority = ''
  @event_title = ''
  # TODO: refactor how event_body is constructed in the class methods
  #       handling of the event_body is a bit clunky and depends on the order of
  #       method calls
  @event_body = ''
end

Public Instance Methods

emit_to_datadog(dog) click to toggle source

Emit Chef event to Datadog

@param dog [Dogapi::Client] Dogapi Client to be used

# File lib/chef/handler/datadog_chef_events.rb, line 69
def emit_to_datadog(dog)
  @event_body = ''
  build_event_data

  begin
    evt = dog.emit_event(Dogapi::Event.new(@event_body,
                                           msg_title: @event_title,
                                           event_type: 'config_management.run',
                                           event_object: @hostname,
                                           alert_type: @alert_type,
                                           priority: @event_priority,
                                           source_type_name: 'chef',
                                           tags: @tags
                                          ), host: @hostname)
    # FIXME: nice-to-have: abstract format of return value away a bit
    # in dogapi directly. See https://github.com/DataDog/dogapi-rb/issues/18
    if evt.length < 2
      Chef::Log.warn("Unexpected response from Datadog Event API: #{evt}")
    else
      # [http_response_code, {"event" => {"url" => "...", ...}}]
      # 2xx means ok
      if evt[0].to_i / 100 != 2
        Chef::Log.warn("Could not submit event to Datadog (HTTP call failed): #{evt[0]}")
      else
        Chef::Log.debug("Successfully submitted Chef event to Datadog for #{@hostname} at #{evt[1]['event']['url']}")
      end
    end
  rescue StandardError => e
    Chef::Log.warn("Could not determine whether Chef event was successfully submitted to Datadog: #{evt}. Error:\n#{e}")
  end
end
with_failure_notifications(failure_notifications) click to toggle source

set the failure notification list

@param failure_notifications [Array] set of datadog notification handles @return [DatadogChefTags] instance reference to self enabling method chaining

# File lib/chef/handler/datadog_chef_events.rb, line 52
def with_failure_notifications(failure_notifications)
  @failure_notifications = failure_notifications
  self
end
with_hostname(hostname) click to toggle source

set the target hostname (chef node name)

@param hostname [String] hostname to use for the handler report @return [DatadogChefTags] instance reference to self enabling method chaining

# File lib/chef/handler/datadog_chef_events.rb, line 34
def with_hostname(hostname)
  @hostname = hostname
  self
end
with_run_status(run_status) click to toggle source

set the chef run status used for the report

@param run_status [Chef::RunStatus] current chef run status @return [DatadogChefTags] instance reference to self enabling method chaining

# File lib/chef/handler/datadog_chef_events.rb, line 43
def with_run_status(run_status)
  @run_status = run_status
  self
end
with_tags(tags) click to toggle source

set the datadog host tags associated with the event

@param [Array] the set of host tags @return [DatadogChefTags] instance reference to self enabling method chaining

# File lib/chef/handler/datadog_chef_events.rb, line 61
def with_tags(tags)
  @tags = tags
  self
end

Private Instance Methods

build_event_data() click to toggle source

Marshal the Event data for submission

# File lib/chef/handler/datadog_chef_events.rb, line 135
def build_event_data
  # bail early in case of a compiletime failure
  # OPTIMIZE: Use better inspectors to handle failure scenarios, refactor needed.
  if compile_error?
    @alert_type = 'error'
    @event_title = "Chef failed during compile phase on #{@hostname} "
    @event_priority = 'normal'
    @event_body = 'Chef was unable to complete a run, an error during compilation may have occurred.'
  else
    run_time = pluralize(@run_status.elapsed_time, 'second')

    # This is the first line of the Event body, the rest is appended here.
    @event_body = "Chef updated #{@run_status.updated_resources.length} resources out of #{@run_status.all_resources.length} resources total."

    # Update resource list, truncated when failed to 5
    # update will add to the event_body
    update_resource_list

    if @run_status.success?
      @alert_type = 'success'
      @event_priority = 'low'
      @event_title = "Chef completed in #{run_time} on #{@hostname} "
    else
      @alert_type = 'error'
      @event_priority = 'normal'
      @event_title = "Chef failed in #{run_time} on #{@hostname} "

      if @failure_notifications
        handles = @failure_notifications
        # convert the notification handle array to a string
        @event_body << "\nAlerting: #{handles.join(' ')}\n"
      end

      @event_body << "\n$$$\n#{@run_status.formatted_exception}\n$$$\n"
      @event_body << "\n$$$\n#{@run_status.backtrace.join("\n")}\n$$$\n"
    end
  end
end
pluralize(number, noun) click to toggle source
# File lib/chef/handler/datadog_chef_events.rb, line 103
def pluralize(number, noun)
  case number
  when 0..1
    "less than 1 #{noun}"
  else
    "#{number.round} #{noun}s"
  end
rescue
  Chef::Log.warn("Cannot make #{number} more legible")
  "#{number} #{noun}s"
end
update_resource_list() click to toggle source

Compose a list of resources updated during a run.

# File lib/chef/handler/datadog_chef_events.rb, line 116
def update_resource_list
  # No resources updated?
  return unless @run_status.updated_resources.length.to_i > 0

  if @run_status.failed?
    # Shorten the list when there is a failure for stacktrace debugging
    report_resources = @run_status.updated_resources.last(5)
  else
    report_resources = @run_status.updated_resources
  end

  @event_body = "\n$$$\n"
  report_resources.each do |r|
    @event_body << "- #{r} (#{r.defined_at})\n"
  end
  @event_body << "\n$$$\n"
end