require 'time_tracker' module Agents class HttpStatusAgent < Agent include WebRequestConcern include FormConfigurable can_dry_run! can_order_created_events! default_schedule "every_12h" form_configurable :url form_configurable :disable_redirect_follow, type: :boolean form_configurable :changes_only, type: :boolean form_configurable :headers_to_save description <<-MD The HttpStatusAgent will check a url and emit the resulting HTTP status code with the time that it waited for a reply. Additionally, it will optionally emit the value of one or more specified headers. Specify a `Url` and the Http Status Agent will produce an event with the HTTP status code. If you specify one or more `Headers to save` (comma-delimited) as well, that header or headers' value(s) will be included in the event. The `disable redirect follow` option causes the Agent to not follow HTTP redirects. For example, setting this to `true` will cause an agent that receives a 301 redirect to `http://yahoo.com` to return a status of 301 instead of following the redirect and returning 200. The `changes only` option causes the Agent to report an event only when the status changes. If set to false, an event will be created for every check. If set to true, an event will only be created when the status changes (like if your site goes from 200 to 500). MD event_description <<-MD Events will have the following fields: { "url": "...", "status": "...", "elapsed_time": "...", "headers": { "...": "..." } } MD def working? memory['last_status'].to_i > 0 end def default_options { 'url' => "http://google.com", 'disable_redirect_follow' => "true", } end def validate_options errors.add(:base, "a url must be specified") unless options['url'].present? end def header_array(str) (str || '').split(',').map(&:strip) end def check check_this_url interpolated[:url], header_array(interpolated[:headers_to_save]) end def receive(incoming_events) incoming_events.each do |event| interpolate_with(event) do check_this_url interpolated[:url], header_array(interpolated[:headers_to_save]) end end end private def check_this_url(url, local_headers) # Track time measured_result = TimeTracker.track { ping(url) } current_status = measured_result.result ? measured_result.status.to_s : '' return if options['changes_only'] == 'true' && current_status == memory['last_status'].to_s payload = { 'url' => url, 'response_received' => false, 'elapsed_time' => measured_result.elapsed_time } # Deal with failures if measured_result.result final_url = boolify(interpolated['disable_redirect_follow']) ? url : measured_result.result.to_hash[:url] payload.merge!({ 'final_url' => final_url, 'redirected' => (url != final_url), 'response_received' => true, 'status' => current_status }) # Deal with headers if local_headers.present? header_results = measured_result.result.headers.select {|header, value| local_headers.include?(header)} # Fill in headers that we wanted, but weren't returned local_headers.each { |header| header_results[header] = nil unless header_results.has_key?(header) } payload.merge!({ 'headers' => header_results }) end create_event payload: payload memory['last_status'] = measured_result.status.to_s else create_event payload: payload memory['last_status'] = nil end end def ping(url) result = faraday.get url result.status > 0 ? result : nil rescue nil end end end