http_status_agent.rb 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. require 'time_tracker'
  2. module Agents
  3. class HttpStatusAgent < Agent
  4. include WebRequestConcern
  5. include FormConfigurable
  6. can_dry_run!
  7. can_order_created_events!
  8. default_schedule "every_12h"
  9. form_configurable :url
  10. form_configurable :disable_redirect_follow, type: :boolean
  11. form_configurable :changes_only, type: :boolean
  12. form_configurable :headers_to_save
  13. description <<~MD
  14. 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.
  15. 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.
  16. 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.
  17. 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).
  18. MD
  19. event_description <<~MD
  20. Events will have the following fields:
  21. {
  22. "url": "...",
  23. "status": "...",
  24. "elapsed_time": "...",
  25. "headers": {
  26. "...": "..."
  27. }
  28. }
  29. MD
  30. def working?
  31. memory['last_status'].to_i > 0
  32. end
  33. def default_options
  34. {
  35. 'url' => "http://google.com",
  36. 'disable_redirect_follow' => "true",
  37. }
  38. end
  39. def validate_options
  40. errors.add(:base, "a url must be specified") unless options['url'].present?
  41. end
  42. def header_array(str)
  43. (str || '').split(',').map(&:strip)
  44. end
  45. def check
  46. check_this_url interpolated[:url], header_array(interpolated[:headers_to_save])
  47. end
  48. def receive(incoming_events)
  49. incoming_events.each do |event|
  50. interpolate_with(event) do
  51. check_this_url interpolated[:url],
  52. header_array(interpolated[:headers_to_save])
  53. end
  54. end
  55. end
  56. private
  57. def check_this_url(url, local_headers)
  58. # Track time
  59. measured_result = TimeTracker.track { ping(url) }
  60. current_status = measured_result.result ? measured_result.status.to_s : ''
  61. return if options['changes_only'] == 'true' && current_status == memory['last_status'].to_s
  62. payload = { 'url' => url, 'response_received' => false, 'elapsed_time' => measured_result.elapsed_time }
  63. # Deal with failures
  64. if measured_result.result
  65. final_url = boolify(interpolated['disable_redirect_follow']) ? url : measured_result.result.env.url.to_s
  66. payload.merge!({ 'final_url' => final_url, 'redirected' => (url != final_url), 'response_received' => true,
  67. 'status' => current_status })
  68. # Deal with headers
  69. if local_headers.present?
  70. header_results = local_headers.each_with_object({}) { |header, hash|
  71. hash[header] = measured_result.result.headers[header]
  72. }
  73. payload.merge!({ 'headers' => header_results })
  74. end
  75. create_event(payload:)
  76. memory['last_status'] = measured_result.status.to_s
  77. else
  78. create_event(payload:)
  79. memory['last_status'] = nil
  80. end
  81. end
  82. def ping(url)
  83. result = faraday.get url
  84. result.status > 0 ? result : nil
  85. rescue StandardError
  86. nil
  87. end
  88. end
  89. end