RailsアプリでELBからのヘルスチェックのアクセスをログに残さないようにする

概要

EC2上で稼働するRuby on Railsのログに、ELBからのヘルスチェックのリクエストが記録されないようにする手順です。

環境

  • Ruby 2.2.3
  • Ruby on Rails 4.2.4
  • Application Load Balancer

手順

  • Railsのロガーに ActiveSupport::Logger を継承するクラスが設定されているか確認する

    config/application.rb
    # NG
    config.logger = Logger.new('log/application.log')
    
    # OK
    config.logger = ActiveSupport::Logger.new('log/application.log')
    
    # OK
    config.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new('log/application.log'))
    

    この作業が完了できていない場合に起きるエラーは後述。

  • 条件に応じてログ出力を抑制する処理を記述する CustomLogger クラスを作成する

    lib/custom_logger.rb
    class CustomLogger < Rails::Rack::Logger
      def call(env)
        user_agent = env['HTTP_USER_AGENT']
    
        if user_agent.include?('ELB-HealthChecker')
          Rails.logger.silence do
            super
          end
        else
          super
        end
      end
    end
    
  • ミドルウェアスタック内の Rails::Rack::Logger を独自で定義した CustomLogger に置き換える

    config/initializers/custom_logger.rb
    require 'custom_logger'
    MyApp::Application.config.middleware.swap Rails::Rack::Logger, CustomLogger
    

    MyApp の部分は各アプリケーションの名前に置き換える。具体的には config/application.rbmodule MyApp のように定義している名前に合わせる。

備考

curlでユーザーエージェントを変更してリクエストを発行する

手元の開発環境で効率的に検証することができる。

curl -A "ELB-HealthChecker" http://localhost:3000/

Basic認証をかけている環境では、さらに -u オプションでユーザー名とパスワードを指定することでテストできる。

curl \
  -u user:password \
  -A "ELB-HealthChecker" \
  http://localhost:3000/

Railsのロガーに ActiveSupport::Logger を継承しているクラスが設定されていない場合に発生するエラー

ELB以外からのアクセスの(=ユーザーエージェントに ELB-HealthChecker が含まれない)場合は問題なくログが出力されるが、ELBからのアクセス時には以下のようなエラーが発生する。

2021-09-24 01:14:54 +0900: Rack app error handling request { GET / }
#<ArgumentError: wrong number of arguments (0 for 1)>
/var/www/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/core_ext/kernel/reporting.rb:89:in `capture'
/var/www/lib/custom_logger.rb:8:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/request_store-1.4.0/lib/request_store/middleware.rb:19:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/request_id.rb:21:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/rack-1.6.8/lib/rack/methodoverride.rb:22:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/rack-1.6.8/lib/rack/runtime.rb:18:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/rack-1.6.8/lib/rack/lock.rb:17:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/static.rb:116:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/rack-1.6.8/lib/rack/sendfile.rb:113:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:518:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:165:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/rack-1.6.8/lib/rack/content_length.rb:15:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/puma-3.8.2/lib/puma/configuration.rb:224:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/puma-3.8.2/lib/puma/server.rb:600:in `handle_request'
/var/www/vendor/bundle/ruby/2.2.0/gems/puma-3.8.2/lib/puma/server.rb:435:in `process_client'
/var/www/vendor/bundle/ruby/2.2.0/gems/puma-3.8.2/lib/puma/server.rb:299:in `block in run'
/var/www/vendor/bundle/ruby/2.2.0/gems/puma-3.8.2/lib/puma/thread_pool.rb:120:in `call'
/var/www/vendor/bundle/ruby/2.2.0/gems/puma-3.8.2/lib/puma/thread_pool.rb:120:in `block in spawn_thread'

背景

EC2でRuby on Railsを稼働させており、前段にApplication Load Balancerを配置しています。ヘルスチェックで定期的にアプリケーションにリクエストが来るようになっていますが、そのログがアクセスログに残ってしまうと見づらかったりログファイルを圧迫して困っていました。

ログはAWSのCloudWatch Logsに送信しているので、ログの量が増えれば転送量やストレージ容量が増え、コスト増加につながるため、それを防ぎたい狙いもありました。

Nginxでは既にELBからのヘルスチェックのアクセスをログに残さないように設定していましたが、Railsの方はまだ設定できていませんでした。NginxだけでなくRailsアプリケーションが正しく動作していることをヘルスチェックの条件にしたいので、Railsが処理するパスを叩くことは継続したい状況でした。

感想

Rackの設定は普段触れることがないのでまだまだ知らないことだらけです。必要になったタイミングで多少時間を多めに取ってコツコツ理解できたらと思います。

参考にさせていただいたサイト

© 2021 itotetsu.work / This site uses Google Analytics.