require 'sylvilagus/init' require 'sylvilagus/ch04' require 'json' require 'net/smtp' require 'rabbitmq-client.jar' class Sylvilagus::Ch04::AlertProducer OPS_EMAILS = ['me@localhost'].freeze ADMIN_EMAILS = ['me@localhost'].freeze def self.send_email(recipients, subject, body) Net::SMTP.start('localhost', 25) do |smtp| msgstr = <<-EOM.gsub(/^ /, '') To: #{recipients.join(', ')} From: alerts@sylvilagus.local Subject: #{subject} Date: #{Time.now} #{body} EOM smtp.send_message(msgstr, 'alerts@sylvilagus.local', recipients) end end class CriticalNotifier < Java::ComRabbitmqClient::DefaultConsumer def handleDelivery(consumer_tag, envelope, properties, body) message = JSON.parse( Java::OrgJruby::RubyString.bytes_to_string(body) ).fetch('message') Sylvilagus::Ch04::AlertProducer.send_email( OPS_EMAILS, 'CRITICAL ALERT!', message ) puts "Sent alert via email! Alert text: #{message}" puts "Recipients: #{OPS_EMAILS}" channel.basic_ack(envelope.delivery_tag, false) end end class RateLimitNotifier < Java::ComRabbitmqClient::DefaultConsumer def handleDelivery(consumer_tag, envelope, properties, body) message = JSON.parse( Java::OrgJruby::RubyString.bytes_to_string(body) ).fetch('message') Sylvilagus::Ch04::AlertProducer.send_email( ADMIN_EMAILS, 'RATE LIMIT ALERT!', message ) puts "Sent alert via email! Alert text: #{message}" puts "Recipients: #{ADMIN_EMAILS}" channel.basic_ack(envelope.delivery_tag, false) end end def main factory = Java::ComRabbitmqClient::ConnectionFactory.new factory.uri = ENV.fetch('SYLVILAGUS_ALERT_AMQP_URI') @conn = factory.new_connection channel = @conn.create_channel channel.exchange_declare('alerts', 'topic', true, false, false, nil) channel.queue_declare('critical', true, false, false, nil) channel.queue_bind('critical', 'alerts', 'critical.*', nil) channel.queue_declare('rate_limit', true, false, false, nil) channel.queue_bind('rate_limit', 'alerts', '*.rate_limit', nil) critical_notifier = CriticalNotifier.new(channel) rate_limit_notifier = RateLimitNotifier.new(channel) channel.basic_consume( 'critical', false, 'critical', critical_notifier ) channel.basic_consume( 'rate_limit', false, 'rate_limit', rate_limit_notifier ) trap(:INT) { exit 0 } puts 'Starting consumer loop...' loop { sleep 1 } ensure begin @conn.close if @conn rescue NativeException end end end if $0 == __FILE__ Sylvilagus::Ch04::AlertProducer.new.main end