Skip to content
Merged
8 changes: 8 additions & 0 deletions guides/source/configuring.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,14 @@ config.session_store :my_custom_store

The default store is a cookie store with the application name as the session key.

#### `config.silence_healthcheck_path`

Specifies the path of the healthcheck that should be silenced in the logs. Uses `Rails::Rack::SilenceRequest` to implement the silencing. All in service of keeping healthchecks from clogging the production logs, especially for early-stage applications.

```
config.silence_healthcheck_path = "/up"
```

#### `config.ssl_options`

Configuration options for the [`ActionDispatch::SSL`](https://api.rubyonrails.org/classes/ActionDispatch/SSL.html) middleware.
Expand Down
6 changes: 6 additions & 0 deletions railties/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
* Add Rails::Rack::SilenceRequest middleware and use it via `config.silence_healthcheck_path = path`
to silence requests to "/up". This prevents the Kamal-required healthchecks from clogging up
the production logs.

*DHH*

* Introduce `mariadb-mysql` and `mariadb-trilogy` database options for `rails new`

When used with the `--devcontainer` flag, these options will use `mariadb` as the database for the
Expand Down
1 change: 1 addition & 0 deletions railties/lib/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require "rails/deprecator"
require "rails/application"
require "rails/backtrace_cleaner"
require "rails/rack/silence_request"

require "active_support/railtie"
require "action_dispatch/railtie"
Expand Down
3 changes: 2 additions & 1 deletion railties/lib/rails/application/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Configuration < ::Rails::Engine::Configuration
:cache_classes, :cache_store, :consider_all_requests_local, :console,
:eager_load, :exceptions_app, :file_watcher, :filter_parameters, :precompile_filter_parameters,
:force_ssl, :helpers_paths, :hosts, :host_authorization, :logger, :log_formatter,
:log_tags, :railties_order, :relative_url_root,
:log_tags, :silence_healthcheck_path, :railties_order, :relative_url_root,
:ssl_options, :public_file_server,
:session_options, :time_zone, :reload_classes_only_on_change,
:beginning_of_week, :filter_redirect, :x,
Expand Down Expand Up @@ -62,6 +62,7 @@ def initialize(*)
@exceptions_app = nil
@autoflush_log = true
@log_formatter = ActiveSupport::Logger::SimpleFormatter.new
@silence_healthcheck_path = nil
@eager_load = nil
@secret_key_base = nil
@api_only = false
Expand Down
4 changes: 4 additions & 0 deletions railties/lib/rails/application/default_middleware_stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def build_stack
middleware.use ::ActionDispatch::RequestId, header: config.action_dispatch.request_id_header
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies

if path = config.silence_healthcheck_path
middleware.use ::Rails::Rack::SilenceRequest, path: path
end

middleware.use ::Rails::Rack::Logger, config.log_tags
middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app
middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Rails.application.configure do
# Skip http-to-https redirect for the default health check endpoint.
# config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } }

# Prevent healthchecks from clogging up the logs
config.silence_healthcheck_path = "/up"

# Log to STDOUT by default
config.logger = ActiveSupport::Logger.new(STDOUT)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
Expand Down
33 changes: 33 additions & 0 deletions railties/lib/rails/rack/silence_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

# :markup: markdown

require "active_support/logger_silence"

module Rails
module Rack
# Allows you to silence requests made to a specific path.
# This is useful for preventing recurring requests like healthchecks from clogging the logging.
# This middleware is used to do just that against the path /up in production by default.
#
# Example:
#
# config.middleware.insert_before \
# Rails::Rack::Logger, Rails::Rack::SilenceRequest, path: "/up"
#
# This middleware can also be configured using `config.silence_healthcheck = "/up"` in Rails.
class SilenceRequest
def initialize(app, path:)
@app, @path = app, path
end

def call(env)
if env["PATH_INFO"] == @path
Rails.logger.silence { @app.call(env) }
else
@app.call(env)
end
end
end
end
end
6 changes: 3 additions & 3 deletions railties/test/commands/middleware_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,10 @@ def app
assert_includes middleware, "ActionDispatch::AssumeSSL"
end

test "ActionDispatch::SSL is present when force_ssl is set" do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dhh did you mean to delete this test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not. Not sure what happened there. Please do PR to restore!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add_to_config "config.force_ssl = true"
test "silence healthcheck" do
add_to_config "config.silence_healthcheck_path = '/up'"
boot!
assert_includes middleware, "ActionDispatch::SSL"
assert_includes middleware, "Rails::Rack::SilenceRequest"
end

test "ActionDispatch::SSL is configured with options when given" do
Expand Down
21 changes: 21 additions & 0 deletions railties/test/rack_silence_request_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

require "abstract_unit"
require "rack/test"
require "minitest/mock"

class RackSilenceRequestTest < ActiveSupport::TestCase
test "silence request only to specific path" do
mock_logger = Minitest::Mock.new
mock_logger.expect :silence, nil

app = Rails::Rack::SilenceRequest.new(lambda { |env| [200, env, "app"] }, path: "/up")

Rails.stub(:logger, mock_logger) do
app.call(Rack::MockRequest.env_for("http://example.com/up"))
app.call(Rack::MockRequest.env_for("http://example.com/down"))
end

assert mock_logger.verify
end
end