Aggiunge monitoraggio ops: health check, log scanner, dashboard e notifiche.
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>
This commit is contained in:
@@ -13,7 +13,7 @@ Rails.application.configure do
|
||||
config.ssl_options = {
|
||||
redirect: {
|
||||
exclude: ->(request) {
|
||||
request.path == "/up" || request.path == "/cable" || request.path.start_with?("/hls/")
|
||||
request.path == "/up" || request.path == "/up/deep" || request.path == "/cable" || request.path.start_with?("/hls/")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ Rails.application.configure do
|
||||
|
||||
config.host_authorization = {
|
||||
exclude: ->(request) {
|
||||
request.path == "/up" || request.path.start_with?("/cable") || request.path.start_with?("/hls/")
|
||||
request.path == "/up" || request.path == "/up/deep" || request.path.start_with?("/cable") || request.path.start_with?("/hls/")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
backend/config/initializers/ops_log_subscriber.rb
Normal file
21
backend/config/initializers/ops_log_subscriber.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
if Rails.env.production? && ENV["OPS_LOG_SUBSCRIBER"] == "true"
|
||||
ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*args|
|
||||
event = ActiveSupport::Notifications::Event.new(*args)
|
||||
next unless event.payload[:status].to_i >= 500
|
||||
|
||||
Ops::IncidentRecorder.record(
|
||||
kind: "log_pattern",
|
||||
severity: "warning",
|
||||
title: "HTTP 500 in Rails",
|
||||
message: "#{event.payload[:method]} #{event.payload[:path]} → #{event.payload[:status]}",
|
||||
metadata: {
|
||||
"controller" => event.payload[:controller],
|
||||
"action" => event.payload[:action],
|
||||
"status" => event.payload[:status]
|
||||
},
|
||||
fingerprint: "rails_500:#{event.payload[:controller]}##{event.payload[:action]}"
|
||||
)
|
||||
rescue StandardError => e
|
||||
Rails.logger.warn("[Ops::LogSubscriber] #{e.message}")
|
||||
end
|
||||
end
|
||||
33
backend/config/initializers/sentry.rb
Normal file
33
backend/config/initializers/sentry.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
if ENV["SENTRY_DSN"].present? && !Rails.env.test?
|
||||
begin
|
||||
require "sentry-ruby"
|
||||
require "sentry-rails"
|
||||
|
||||
Sentry.init do |config|
|
||||
config.dsn = ENV["SENTRY_DSN"]
|
||||
config.breadcrumbs_logger = %i[active_support_logger http_logger]
|
||||
config.traces_sample_rate = ENV.fetch("SENTRY_TRACES_SAMPLE_RATE", "0.1").to_f
|
||||
config.environment = Rails.env
|
||||
|
||||
config.before_send = lambda do |event, _hint|
|
||||
Ops::IncidentRecorder.record(
|
||||
kind: "log_pattern",
|
||||
severity: "warning",
|
||||
title: "Sentry: #{event.message}",
|
||||
message: event.message,
|
||||
metadata: {
|
||||
"sentry_event_id" => event.event_id,
|
||||
"level" => event.level
|
||||
},
|
||||
fingerprint: "sentry:#{event.fingerprint&.first || event.event_id}"
|
||||
)
|
||||
event
|
||||
rescue StandardError => e
|
||||
Rails.logger.warn("[Sentry] ops incident hook: #{e.message}")
|
||||
event
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
Rails.logger.warn("[Sentry] gem non installata — imposta SENTRY_DSN dopo bundle add sentry-ruby sentry-rails")
|
||||
end
|
||||
end
|
||||
@@ -5,6 +5,7 @@ Sidekiq.configure_server do |config|
|
||||
|
||||
config.on(:startup) do
|
||||
StreamPublisherSyncJob.ensure_chain
|
||||
Ops::HealthMonitorJob.ensure_chain
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
16
backend/config/ops_log_patterns.yml
Normal file
16
backend/config/ops_log_patterns.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
patterns:
|
||||
- name: http_500
|
||||
severity: warning
|
||||
regex: 'Completed 500'
|
||||
- name: disk_full
|
||||
severity: critical
|
||||
regex: 'No space left on device'
|
||||
- name: db_connection
|
||||
severity: critical
|
||||
regex: 'PG::(ConnectionBad|UnableToSend)'
|
||||
- name: sidekiq_failure
|
||||
severity: warning
|
||||
regex: 'WARN.*fail'
|
||||
- name: fatal_error
|
||||
severity: critical
|
||||
regex: '\bFATAL\b'
|
||||
@@ -2,6 +2,7 @@ Rails.application.routes.draw do
|
||||
mount ActionCable.server => "/cable"
|
||||
|
||||
get "up" => "rails/health#show", as: :rails_health_check
|
||||
get "up/deep" => "ops/health#show", as: :ops_deep_health
|
||||
|
||||
namespace :api do
|
||||
namespace :v1 do
|
||||
@@ -76,6 +77,13 @@ Rails.application.routes.draw do
|
||||
|
||||
root to: "dashboard#index"
|
||||
get "metrics", to: "dashboard#metrics"
|
||||
resources :ops, only: [:index], controller: "ops" do
|
||||
member do
|
||||
post :acknowledge
|
||||
post :resolve
|
||||
post :mute
|
||||
end
|
||||
end
|
||||
get "billing", to: "billing#index", as: :billing
|
||||
post "billing/payments/:payment_id/attach_pdf", to: "billing#attach_pdf", as: :billing_payment_attach_pdf
|
||||
resources :teams, only: %i[show]
|
||||
|
||||
Reference in New Issue
Block a user