Introduce incidenti con dedup, job Sidekiq ogni 3 min, scan log cron, /up/deep, dashboard /admin/ops e push ntfy; include Sentry opzionale e fix test suite. Co-authored-by: Cursor <cursoragent@cursor.com>
66 lines
1.7 KiB
Ruby
66 lines
1.7 KiB
Ruby
module Ops
|
|
class Notifier
|
|
class Error < StandardError; end
|
|
|
|
def self.notify_severity?(severity)
|
|
levels = ENV.fetch("OPS_NOTIFY_SEVERITIES", "critical").split(",").map(&:strip)
|
|
levels.include?(severity.to_s)
|
|
end
|
|
|
|
def notify(incident)
|
|
notify_ntfy(incident) if ntfy_url.present?
|
|
notify_email(incident) if alert_email.present?
|
|
end
|
|
|
|
private
|
|
|
|
def notify_ntfy(incident)
|
|
priority = incident.severity == "critical" ? "5" : "3"
|
|
tags = incident.severity == "critical" ? "rotating_light" : "warning"
|
|
|
|
conn = Faraday.new do |f|
|
|
f.adapter Faraday.default_adapter
|
|
f.options.timeout = 10
|
|
f.options.open_timeout = 5
|
|
end
|
|
|
|
headers = {
|
|
"Title" => "[Match Live TV] #{incident.title}",
|
|
"Priority" => priority,
|
|
"Tags" => tags
|
|
}
|
|
headers["Authorization"] = "Bearer #{ntfy_token}" if ntfy_token.present?
|
|
|
|
body = incident.message.to_s
|
|
body += "\n\n(#{incident.occurrence_count} occorrenze)" if incident.occurrence_count > 1
|
|
|
|
response = conn.post(ntfy_url, body, headers)
|
|
return if response.success?
|
|
|
|
Rails.logger.warn("[Ops::Notifier] ntfy failed: #{response.status} #{response.body}")
|
|
rescue Faraday::Error => e
|
|
Rails.logger.warn("[Ops::Notifier] ntfy error: #{e.message}")
|
|
end
|
|
|
|
def notify_email(incident)
|
|
return unless defined?(ActionMailer)
|
|
|
|
Ops::AlertMailer.incident(incident).deliver_later
|
|
rescue StandardError => e
|
|
Rails.logger.warn("[Ops::Notifier] email error: #{e.message}")
|
|
end
|
|
|
|
def ntfy_url
|
|
ENV["OPS_NTFY_URL"].presence
|
|
end
|
|
|
|
def ntfy_token
|
|
ENV["OPS_NTFY_TOKEN"].presence
|
|
end
|
|
|
|
def alert_email
|
|
ENV["OPS_ALERT_EMAIL"].presence
|
|
end
|
|
end
|
|
end
|