diff --git a/Gemfile b/Gemfile index 1729301..01db622 100644 --- a/Gemfile +++ b/Gemfile @@ -38,8 +38,9 @@ else end gem "redis-namespace", "~> 1.11" gem "redis", "~> 5.0" -gem "sentry-rails", "~> 5.5" -gem "sentry-sidekiq", "~> 5.5" +gem "sentry-ruby", "~> 6.5" +gem "sentry-rails", "~> 6.5" +gem "sentry-sidekiq", "~> 6.5" gem "sidekiq-scheduler", "~> 5.0" gem "sidekiq", "~> 7.2" gem "sitemap_generator", "~> 6.3" diff --git a/Gemfile.lock b/Gemfile.lock index d3c4a1c..3b36ef3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -115,8 +115,8 @@ GEM aws-sigv4 (1.9.0) aws-eventstream (~> 1, >= 1.0.2) base64 (0.2.0) - benchmark (0.4.1) - bigdecimal (3.3.1) + benchmark (0.5.0) + bigdecimal (4.1.2) bootsnap (1.18.3) msgpack (~> 1.2) bootstrap (5.3.3) @@ -127,8 +127,8 @@ GEM builder (3.3.0) cgi (0.5.1) choice (0.2.0) - concurrent-ruby (1.3.5) - connection_pool (2.5.4) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) crack (1.0.0) bigdecimal rexml @@ -140,12 +140,12 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) - date (3.4.1) + date (3.5.1) diff-lcs (1.5.1) docile (1.4.1) dotenv (3.1.2) drb (2.2.3) - erb (5.1.1) + erb (6.0.4) erubi (1.13.1) et-orbi (1.2.11) tzinfo @@ -198,15 +198,16 @@ GEM thor tilt hashdiff (1.1.1) - i18n (1.14.7) + i18n (1.14.8) concurrent-ruby (~> 1.0) importmap-rails (2.0.1) actionpack (>= 6.0.0) activesupport (>= 6.0.0) railties (>= 6.0.0) - io-console (0.8.1) - irb (1.15.2) + io-console (0.8.2) + irb (1.18.0) pp (>= 0.6.0) + prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) @@ -215,8 +216,8 @@ GEM activemodel (>= 6.0.0) activesupport (>= 6.0.0) redis (>= 4.2, < 6) - logger (1.6.0) - loofah (2.24.1) + logger (1.7.0) + loofah (2.25.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -230,8 +231,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2024.1001) mini_mime (1.1.5) - mini_portile2 (2.8.9) - minitest (6.0.3) + minitest (6.0.6) drb (~> 2.0) prism (~> 1.5) msgpack (1.7.2) @@ -248,8 +248,9 @@ GEM next_rails (1.4.8) rainbow (>= 3) nio4r (2.7.4) - nokogiri (1.18.10) - mini_portile2 (~> 2.8.2) + nokogiri (1.19.3-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.3-x86_64-linux-gnu) racc (~> 1.4) octokit (9.2.0) faraday (>= 1, < 3) @@ -268,7 +269,7 @@ GEM activesupport (>= 7.0.0) rack railties (>= 7.0.0) - psych (5.2.6) + psych (5.3.1) date stringio public_suffix (6.0.1) @@ -276,13 +277,13 @@ GEM nio4r (~> 2.0) raabro (1.4.0) racc (1.8.1) - rack (3.2.3) - rack-session (2.1.1) + rack (3.2.6) + rack-session (2.1.2) base64 (>= 0.1.0) rack (>= 3.0.0) rack-test (2.2.0) rack (>= 1.3) - rackup (2.2.1) + rackup (2.3.1) rack (>= 3) rails (8.0.3) actioncable (= 8.0.3) @@ -311,8 +312,8 @@ GEM activesupport (>= 4.2) choice (~> 0.2.0) ruby-graphviz (~> 1.2) - rails-html-sanitizer (1.6.2) - loofah (~> 2.21) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) rails-i18n (8.0.2) i18n (>= 0.7, < 2) @@ -330,19 +331,19 @@ GEM tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.3.0) + rake (13.4.2) rchardet (1.8.0) - rdoc (6.15.0) + rdoc (7.2.0) erb psych (>= 4.0.0) tsort redis (5.2.0) redis-client (>= 0.22.0) - redis-client (0.22.2) + redis-client (0.28.0) connection_pool redis-namespace (1.11.0) redis (>= 4) - reline (0.6.2) + reline (0.6.3) io-console (~> 0.5) rexml (3.3.7) rspec-core (3.13.0) @@ -374,17 +375,18 @@ GEM addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) securerandom (0.4.1) - sentry-rails (5.18.2) - railties (>= 5.0) - sentry-ruby (~> 5.18.2) - sentry-ruby (5.18.2) + sentry-rails (6.5.0) + railties (>= 5.2.0) + sentry-ruby (~> 6.5.0) + sentry-ruby (6.5.0) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) - sentry-sidekiq (5.18.2) - sentry-ruby (~> 5.18.2) - sidekiq (>= 3.0) - sidekiq (7.3.0) - concurrent-ruby (< 2) + logger + sentry-sidekiq (6.5.0) + sentry-ruby (~> 6.5.0) + sidekiq (>= 5.0) + sidekiq (7.3.9) + base64 connection_pool (>= 2.3.0) logger rack (>= 2.2.4) @@ -407,11 +409,11 @@ GEM builder (~> 3.0) stimulus-rails (1.3.3) railties (>= 6.0.0) - stringio (3.1.7) + stringio (3.2.0) temple (0.10.3) terminal-table (4.0.0) unicode-display_width (>= 1.1.1, < 4) - thor (1.4.0) + thor (1.5.0) tilt (2.4.0) timeout (0.4.3) tsort (0.2.0) @@ -424,7 +426,7 @@ GEM unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.2.0) - uri (1.0.4) + uri (1.1.1) useragent (0.16.11) vcr (6.4.0) webmock (3.23.1) @@ -435,7 +437,7 @@ GEM base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.7.3) + zeitwerk (2.7.5) PLATFORMS arm64-darwin-22 @@ -476,8 +478,9 @@ DEPENDENCIES redis (~> 5.0) redis-namespace (~> 1.11) rspec-rails (~> 6.1.0) - sentry-rails (~> 5.5) - sentry-sidekiq (~> 5.5) + sentry-rails (~> 6.5) + sentry-ruby (~> 6.5) + sentry-sidekiq (~> 6.5) sidekiq (~> 7.2) sidekiq-scheduler (~> 5.0) simplecov (~> 0.22) diff --git a/Gemfile.next.lock b/Gemfile.next.lock index 1db5191..39cc1c2 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -377,15 +377,16 @@ GEM addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) securerandom (0.4.1) - sentry-rails (5.18.2) - railties (>= 5.0) - sentry-ruby (~> 5.18.2) - sentry-ruby (5.18.2) + sentry-rails (6.5.0) + railties (>= 5.2.0) + sentry-ruby (~> 6.5.0) + sentry-ruby (6.5.0) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) - sentry-sidekiq (5.18.2) - sentry-ruby (~> 5.18.2) - sidekiq (>= 3.0) + logger + sentry-sidekiq (6.5.0) + sentry-ruby (~> 6.5.0) + sidekiq (>= 5.0) sidekiq (7.3.0) concurrent-ruby (< 2) connection_pool (>= 2.3.0) @@ -480,8 +481,9 @@ DEPENDENCIES redis (~> 5.0) redis-namespace (~> 1.11) rspec-rails (~> 6.1.0) - sentry-rails (~> 5.5) - sentry-sidekiq (~> 5.5) + sentry-rails (~> 6.5) + sentry-ruby (~> 6.5) + sentry-sidekiq (~> 6.5) sidekiq (~> 7.2) sidekiq-scheduler (~> 5.0) simplecov (~> 0.22) diff --git a/app/controllers/api/github_notifications_controller.rb b/app/controllers/api/github_notifications_controller.rb index e8db6de..379e3e1 100644 --- a/app/controllers/api/github_notifications_controller.rb +++ b/app/controllers/api/github_notifications_controller.rb @@ -1,17 +1,16 @@ module API class GithubNotificationsController < BaseController def create - Sentry.capture_message( + Sentry.logger.info( "POST /api/github_notifications hit while temporarily disabled", - level: :info, - extra: { - action: request.request_parameters["action"], - conclusion: request.request_parameters.dig("check_run", "conclusion"), - branch: request.request_parameters.dig("check_run", "check_suite", "head_branch"), - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + action: request.request_parameters["action"], + conclusion: request.request_parameters.dig("check_run", "conclusion"), + branch: request.request_parameters.dig("check_run", "check_suite", "head_branch"), + check_name: request.request_parameters.dig("check_run", "name"), + status: request.request_parameters.dig("check_run", "status"), + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer ) render json: { diff --git a/app/controllers/api/releases_controller.rb b/app/controllers/api/releases_controller.rb index 050ab01..6be8cea 100644 --- a/app/controllers/api/releases_controller.rb +++ b/app/controllers/api/releases_controller.rb @@ -1,16 +1,13 @@ module API class ReleasesController < BaseController def create - Sentry.capture_message( + Sentry.logger.info( "POST /api/releases hit while temporarily disabled", - level: :info, - extra: { - name: params[:name], - version: params[:version], - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + gem_name: params[:name], + version: params[:version], + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer ) render json: { diff --git a/app/controllers/api/results_controller.rb b/app/controllers/api/results_controller.rb index cc2fd58..5228c1a 100644 --- a/app/controllers/api/results_controller.rb +++ b/app/controllers/api/results_controller.rb @@ -3,18 +3,16 @@ class ResultsController < BaseController before_action :authenticate_api_key! def create - Sentry.capture_message( + Sentry.logger.info( "POST /api/results hit while temporarily disabled", - level: :info, - extra: { - compat_id: params[:compat_id], - rails_version: params[:rails_version], - strategy: params.dig(:result, :strategy), - api_key_name: @api_key&.name, - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + compat_id: params[:compat_id], + rails_version: params[:rails_version], + strategy: params.dig(:result, :strategy), + success: params.dig(:result, :success), + api_key_name: @api_key&.name, + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer ) render json: { diff --git a/app/controllers/gemmies_controller.rb b/app/controllers/gemmies_controller.rb index 8402d68..a5d8e3a 100644 --- a/app/controllers/gemmies_controller.rb +++ b/app/controllers/gemmies_controller.rb @@ -4,15 +4,15 @@ def new end def create - Sentry.capture_message( + Sentry.logger.info( "POST /gems hit (legacy gem submission)", - level: :info, - extra: { - name: gemmy_params[:name], - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + gem_name: gemmy_params[:name], + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer, + method: request.method, + path: request.path, + format: request.format.symbol ) @gemmy = Gemmies::Create.call(gemmy_params.fetch(:name)) @@ -36,15 +36,13 @@ def index def show if rand < 0.01 - Sentry.capture_message( + Sentry.logger.info( "GET /gems/:id hit (legacy gem page, 1% sample)", - level: :info, - extra: { - name: params[:id], - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + gem_name: params[:id], + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer, + format: request.format.symbol ) end @@ -64,16 +62,15 @@ def show end def compat_table - Sentry.capture_message( + Sentry.logger.info( "GET /gems/compat_table hit (legacy)", - level: :info, - extra: { - gemmy_ids: params[:gemmy_ids], - inaccessible_gemmy_ids: params[:inaccessible_gemmy_ids], - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + gemmy_ids: params[:gemmy_ids], + inaccessible_gemmy_ids: params[:inaccessible_gemmy_ids], + gemmy_count: gemmy_ids.size, + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer, + format: request.format.symbol ) render locals: { diff --git a/app/controllers/rails_releases_controller.rb b/app/controllers/rails_releases_controller.rb index 28e5bcc..b20188a 100644 --- a/app/controllers/rails_releases_controller.rb +++ b/app/controllers/rails_releases_controller.rb @@ -1,16 +1,14 @@ class RailsReleasesController < ApplicationController def show if rand < 0.01 - Sentry.capture_message( + Sentry.logger.info( "GET /gems/:gemmy_id/compatibility/:id hit (legacy compat page, 1% sample)", - level: :info, - extra: { - gemmy_id: params[:gemmy_id], - rails_id: params[:id], - remote_ip: request.remote_ip, - user_agent: request.user_agent, - referer: request.referer - } + gem_name: params[:gemmy_id], + rails_id: params[:id], + remote_ip: request.remote_ip, + user_agent: request.user_agent, + referer: request.referer, + format: request.format.symbol ) end diff --git a/app/middleware/memory_tracker.rb b/app/middleware/memory_tracker.rb new file mode 100644 index 0000000..953f76e --- /dev/null +++ b/app/middleware/memory_tracker.rb @@ -0,0 +1,42 @@ +class MemoryTracker + RSS_SPIKE_THRESHOLD_MB = 5 + + def initialize(app) + @app = app + end + + def call(env) + rss_before = current_rss_mb + status, headers, body = @app.call(env) + rss_after = current_rss_mb + delta = rss_after - rss_before + + if delta >= RSS_SPIKE_THRESHOLD_MB + req = Rack::Request.new(env) + Sentry.logger.warn( + "memory spike detected", + rss_before_mb: rss_before, + rss_after_mb: rss_after, + delta_mb: delta, + method: req.request_method, + path: req.path, + query_string: req.query_string.presence, + remote_ip: req.ip, + user_agent: req.user_agent, + referer: req.referer + ) + end + + [ status, headers, body ] + end + + private + + def current_rss_mb + IO.read("/proc/#{Process.pid}/status") + .match(/VmRSS:\s+(\d+)/)[1] + .to_i / 1024.0 + rescue + 0.0 + end +end diff --git a/config/application.rb b/config/application.rb index 36da5e2..bc1a795 100644 --- a/config/application.rb +++ b/config/application.rb @@ -37,6 +37,9 @@ class Application < Rails::Application config.middleware.insert 0, Rack::Deflater + require Rails.root.join("app/middleware/memory_tracker") + config.middleware.use MemoryTracker + Rails.application.routes.default_url_options = config.action_mailer.default_url_options = { host: ENV.fetch("HOST"), diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb index 866e95c..7157e55 100644 --- a/config/initializers/sentry.rb +++ b/config/initializers/sentry.rb @@ -1,8 +1,10 @@ Sentry.init do |config| config.breadcrumbs_logger = %i(active_support_logger http_logger) - config.include_local_variables = true + config.max_breadcrumbs = 20 + config.include_local_variables = false config.release = Rails.configuration.revision config.send_default_pii = true config.traces_sample_rate = 0.05 config.profiles_sample_rate = 0.05 + config.enable_logs = true end