diff --git a/Gemfile b/Gemfile index 57b85832..17888b63 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem "rackup", "~> 2.0" gem "sinatra", "~> 4.2" group :development, :test do + gem "aws-sdk-cloudwatch", "~> 1.128" gem "database_cleaner", "~> 2.0" gem "dotenv", "~> 3.0" gem "factory_bot", "~> 6.0" diff --git a/Gemfile.lock b/Gemfile.lock index da3e51fb..61c74076 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -26,6 +26,21 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) ast (2.4.2) + aws-eventstream (1.4.0) + aws-partitions (1.1202.0) + aws-sdk-cloudwatch (1.128.0) + aws-sdk-core (~> 3, >= 3.241.3) + aws-sigv4 (~> 1.5) + aws-sdk-core (3.241.3) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) base64 (0.3.0) benchmark (0.4.1) bigdecimal (3.2.2) @@ -54,6 +69,7 @@ GEM foreman (0.87.2) i18n (1.14.7) concurrent-ruby (~> 1.0) + jmespath (1.6.2) json (2.9.1) language_server-protocol (3.17.0.3) listen (3.9.0) @@ -167,6 +183,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + aws-sdk-cloudwatch (~> 1.128) coveralls_reborn database_cleaner (~> 2.0) dotenv (~> 3.0) diff --git a/bin/outboxer_cloudwatch_metrics b/bin/outboxer_cloudwatch_metrics new file mode 100755 index 00000000..f4eec899 --- /dev/null +++ b/bin/outboxer_cloudwatch_metrics @@ -0,0 +1,81 @@ +#!/usr/bin/env ruby + +require "bundler/setup" + +begin + require "aws-sdk-cloudwatch" +rescue LoadError + abort <<~MSG + aws-sdk-cloudwatch is not installed. + + Add it to your Gemfile: + + gem "aws-sdk-cloudwatch" + + Then run bundle install. + MSG +end + +require "outboxer" + +sleep_interval = 60 +tick_interval = 1 + +environment = ENV["RAILS_ENV"] || "development" +db_config = Outboxer::Database.config(environment: environment, pool: 1) +Outboxer::Database.connect(config: db_config) + +running = true + +["TERM", "INT"].each do |signal| + Signal.trap(signal) { running = false } +end + +cloud_watch_client = Aws::CloudWatch::Client.new( + credentials: Aws::Credentials.new( + ENV.fetch("AWS_ACCESS_KEY_ID"), ENV.fetch("AWS_SECRET_ACCESS_KEY") + ), + region: ENV.fetch("AWS_REGION"), + ssl_verify_peer: false +) + +logger = Outboxer::Logger.new($stdout, level: 1) +logger.info "Sending Outboxer metrics to CloudWatch..." + +while running + metrics_by_status = Outboxer::Message.metrics_by_status + + metric_data = metrics_by_status.except(:total).map do |status, metrics| + { + metric_name: "MessageCount", + dimensions: [ + { name: "Status", value: status.to_s.capitalize }, + { name: "Environment", value: environment } + ], + value: metrics[:count], + unit: "Count" + } + end + [ + { + metric_name: "MessageLatency", + dimensions: [ + { name: "Status", value: "Queued" }, + { name: "Environment", value: environment } + ], + value: metrics_by_status[:queued][:latency] || 0, + unit: "Seconds" + } + ] + + cloud_watch_client.put_metric_data(namespace: "Outboxer", metric_data: metric_data) + + slept = 0 + + while running && slept < sleep_interval + sleep tick_interval + + slept += tick_interval + end +end + +logger.info "Shutting down" diff --git a/generators/install_cloudwatch_metrics_generator.rb b/generators/install_cloudwatch_metrics_generator.rb new file mode 100644 index 00000000..65253c4c --- /dev/null +++ b/generators/install_cloudwatch_metrics_generator.rb @@ -0,0 +1,30 @@ +module Outboxer + class InstallCloudwatchMetricsGenerator < Rails::Generators::Base + source_root File.expand_path("../", __dir__) + + def copy_bin_file + template "bin/outboxer_cloudwatch_metrics", "bin/outboxer_cloudwatch_metrics" + run "chmod +x bin/outboxer_cloudwatch_metrics" + end + + def print_instructions + say <<~MSG + + To complete setup: + + 1. Add to Gemfile: + gem "aws-sdk-cloudwatch" + + 2. Run: + bundle install + + 3. Start: + bin/outboxer_cloudwatch_metrics + + MSG + end + end +end + +# bundle exec rails g outboxer:install_cloudwatch_metrics +# bin/outboxer_cloudwatch_metrics diff --git a/lib/outboxer/web/views/publisher.erb b/lib/outboxer/web/views/publisher.erb index 49056dbb..2f2c5f38 100644 --- a/lib/outboxer/web/views/publisher.erb +++ b/lib/outboxer/web/views/publisher.erb @@ -117,7 +117,7 @@