以下の内容はhttps://thinkami.hatenablog.com/entry/2026/01/25/225412より取得しました。


Railsにて、log_argumentsやconfig.filter_parametersを使って、ActiveJobでもパラメータをフィルタリングしてログへ出力してみた

Railsでは config.filter_parameters を使うことで、ログへ出力したくないパラメータを設定できます。
3.2.34 config.filter_parameters | Rails アプリケーションの設定項目 - Railsガイド

ただ、この設定がデフォルトではActiveJobでのジョブ実行時のログには適用されないと、同僚から教わりました。

そこで、どんな感じになるのか気になったことから、調べたときのメモを残します。

 
目次

 

環境

  • Ruby 3.4.8
  • Rails 8.1.2
  • Solid Queue 1.3.1
  • Delayed::Job 4.2.0

 

デフォルト設定での動作確認

まずは、デフォルトだとどのような挙動になるか確認します。

rails new --minimal で最低限のRailsアプリを作ります。minimalの場合、ActiveJobまわりの設定はスキップされます。

% bundle exec rails new . --minimal
Based on the specified options, the following options will also be activated:

  --skip-active-job [due to --minimal]
  --skip-action-mailer [due to --skip-active-job, --minimal]
  --skip-active-storage [due to --skip-active-job, --minimal]
  --skip-solid [due to --minimal]
  --skip-action-mailbox [due to --skip-active-storage, --minimal]
  --skip-action-text [due to --skip-active-storage, --minimal]
  --skip-javascript [due to --minimal]
  --skip-hotwire [due to --skip-javascript, --minimal]
  --skip-action-cable [due to --minimal]
  --skip-bootsnap [due to --minimal]
  --skip-brakeman [due to --minimal]
  --skip-bundler-audit [due to --minimal]
  --skip-ci [due to --minimal]
  --skip-dev-gems [due to --minimal]
  --skip-docker [due to --minimal]
  --skip-jbuilder [due to --minimal]
  --skip-kamal [due to --minimal]
  --skip-rubocop [due to --minimal]
  --skip-system-test [due to --minimal]
  --skip-thruster [due to --minimal]
...

 
ジェネレータを使ってJob MyJob を生成します。ジェネレータを使うことで、スキップされたActiveJobまわりの設定も生成されました。

% bin/rails g job MyJob
      invoke  test_unit
      create    test/jobs/my_job_test.rb
      create  app/jobs/my_job.rb
      create  app/jobs/application_job.rb

 
今回はJobの中で puts したり logger.info する程度とします。

class MyJob < ApplicationJob
  queue_as :default

  def perform(payload)
    puts "MyJob received payload (puts): #{payload}"
    logger.info "MyJob received payload (logger): #{payload}"
  end
end

 
Controllerも作ります。Controllerの中でも puts したり logger.info したりします。

class TokensController < ApplicationController
  skip_before_action :verify_authenticity_token, raise: false

  def create
    token = params[:token]
    puts "Received token in controller (puts): #{params}"
    logger.info "Received token in controller (logger): #{params}"
    MyJob.perform_later({ token: token })
    
    head :ok
  end
end

 
developmentモードで動かすと、 logger.infoでは development.logへログが出力されます。

今回は puts と同じように標準出力で確認できるよう、 dotenv-rails環境変数 RAILS_LOG_TO_STDOUT を設定し、ログの出力先を変更します。

.env ファイルを用意します。

RAILS_LOG_TO_STDOUT=1

 
routes.rb も適当に作ります。

Rails.application.routes.draw do
  post 'tokens', to: 'tokens#create'
end

 
curlで動作確認します。

% curl -X POST http://localhost:3000/tokens -d "token=my_secret_token"

 
ログを見てみます。

まずはController部分です。リクエストのログはフィルタリングされていますが、 putslogger.info はそのまま出力されていました。

Started POST "/tokens" for 127.0.0.1 at 2026-01-24 17:57:00 +0900

# リクエストのログはフィルタリングされている
Processing by TokensController#create as */*
  Parameters: {"token" => "[FILTERED]"}
  
# putsやlogger.infoはそのまま出力される
Received token in controller (puts): {"token" => "my_secret_token", "controller" => "tokens", "action" => "create"}
Received token in controller (logger): {"token" => "my_secret_token", "controller" => "tokens", "action" => "create"}

 
続いてJob部分です。Jobの設定は修正していないため、デフォルトの async queue adapterが使われます。
3.14 Active Jobを設定する | Rails アプリケーションを設定する - Railsガイド

 
ジョブがエンキューされたときのログです。フィルタリングはされず、そのまま出力されていました。

[ActiveJob] Enqueued MyJob (Job ID: a26d803a-c514-4a73-809a-e3120a6ead3e) to Async(default) with arguments: {token: "my_secret_token"}
[ActiveJob] Enqueued MySecretJob (Job ID: 6f56f581-2907-4f1a-b78a-6be6965656fb) to Async(default)

 
ジョブ実行時のログです。こちらも、通常のログに加えて、 putslogger.info の出力がフィルタリングされないままでした。

# 通常のログ
[ActiveJob] [MyJob] [a26d803a-c514-4a73-809a-e3120a6ead3e] Performing MyJob (Job ID: a26d803a-c514-4a73-809a-e3120a6ead3e) from Async(default) enqueued at 2026-01-24T09:02:49.949194000Z with arguments: {token: "my_secret_token"}

# puts
MyJob received payload (puts): {token: "my_secret_token"}

# logger.info
[ActiveJob] [MyJob] [a26d803a-c514-4a73-809a-e3120a6ead3e] MyJob received payload (logger): {token: "my_secret_token"}

 

log_arguments=falseで、Jobの引数を表示しないようにする

Jobで引数をなんとかする方法を探したところ、ログにJobの引数を表示しないようにする設定 log_arguments がありました。

 
実際に試してみます。まずはJob MySecretJob をジェネレータで生成します。

% bin/rails g job MySecretJob
      invoke  test_unit
      create    test/jobs/my_secret_job_test.rb
      create  app/jobs/my_secret_job.rb

 
ApplicationJobを継承した MySecretJobself.log_arguments = false を設定します。

class MySecretJob < ApplicationJob  
  queue_as :default  
  self.log_arguments = false  
  
  def perform(payload)  
    puts "MySecretJob received payload (puts): #{payload}"  
    logger.info "MySecretJob received payload (logger): #{payload}"  
  end  
end

 
Controllerに MySecretJob の実行を追加します。

def create  
  ...
  # 追加
  MySecretJob.perform_later({ token: token })  
  
  head :ok  
end

 
先ほどと同じように curlでテストしたところ、ログに引数が出なくなっていました。

...
# エンキュー
[ActiveJob] Enqueued MySecretJob (Job ID: 33e55d02-f990-432a-bf9d-0f714f0ffbc3) to Async(default)
...
# 実行
[ActiveJob] [MySecretJob] [33e55d02-f990-432a-bf9d-0f714f0ffbc3] Performing MySecretJob (Job ID: 33e55d02-f990-432a-bf9d-0f714f0ffbc3) from Async(default) enqueued at 2026-01-24T09:14:11.782581000Z

 

ログにJobの引数は出したいけど、フィルタリングもしたい

「重要な情報を含む処理ではログに一切出力しない」は適切ですが、状況によっては

  • 普通の引数はログを追いかけるときに必要なので、そのまま出力
  • 重要な一部の引数はフィルタリングして出力

を行いたいこともあります。

そこで実現できる方法を調べてみました。

 

ActiveJob::LogSubscriberをパッチする

実装

Railsのissueを調べたところ、以下が見つかりました。
[WIP] Filter parameters in ActiveJob logs by davidpiegza · Pull Request #34438 · rails/rails

そのissueでは、実装例が含まれるコメントもありました。
https://github.com/rails/rails/pull/34438#issuecomment-2336749226

コメントによると、 ActiveJob::LogSubscriber のprivateメソッド format をパッチすれば良さそうです。

今回は以下の点を修正して試してみます。

  • config.after_initialize + alias_method ではなく、 ActiveSupport.on_load(:active_job) + prepend を使う
  • alias_method ではなく、 super を使う
    • prepend の探索順で動作してほしいため

まとめるとこんな感じです。

ActiveSupport.on_load(:active_job) do
  require "active_job/log_subscriber"

  module ActiveJobLogSubscriberFilter
    private

    def format(arg)
      if arg.is_a?(Hash)
        # Rails.application.config.filter_parameters を利用してフィルタリングを適用
        parameter_filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
        parameter_filter.filter(arg.transform_values { |value| super(value) })
      else
        # superを使って、元々のformatメソッドを呼び出す。
        # なお、元々のformatメソッドの中でformatメソッドを使ったときは、ここで定義したformatメソッドが呼び出される。
        super(arg)
      end
    end
  end

  # ActiveJob::LogSubscriber にパッチを適用
  ActiveJob::LogSubscriber.prepend(ActiveJobLogSubscriberFilter)
end

 

queue_adapter :sync (デフォルト)での動作確認

では実際にパッチできているかを確認します。

まずはデフォルト設定(:sync)での動作確認です。

キューイングの時もフィルタリングされたログが出力されました。

Processing by TokensController#create as */*
  Parameters: {"token" => "[FILTERED]"}
...
[ActiveJob] Enqueued MyJob (Job ID: d8ef1e1e-1f10-4b0f-8e7b-a2f7bd594d9c) to Async(default) with arguments: [{request: {token: "[FILTERED]"}}]

 
続いてJobの実行時です。こちらもフィルタリングされていました。良さそうです。

[ActiveJob] [MyJob] [d8ef1e1e-1f10-4b0f-8e7b-a2f7bd594d9c] Performing MyJob (Job ID: d8ef1e1e-1f10-4b0f-8e7b-a2f7bd594d9c) from Async(default) enqueued at 2026-01-24T11:34:08.230302000Z with arguments: [{request: {token: "[FILTERED]"}}]

 

queue_adapter :solid_queue での動作確認

デフォルトの queue_adapter では問題なく動作しましたが、実運用では別の queue_adapter を使うことが多いはずです。

そこで、次はRails8.0から導入された Solid Queue での動作を確認します。
Ruby on Rails 8.0 Release Notes — Ruby on Rails Guides

 

Solid Queueのセットアップ

今回は rails new --minimal でアプリを生成したため、Solid Queueが導入されていません。

そこで、 Solid Queue のREADMEに従ってインストールします。
https://github.com/rails/solid_queue?tab=readme-ov-file#installation

% bundle add solid_queue
Fetching gem metadata from https://rubygems.org/.........
Resolving dependencies...
Fetching gem metadata from https://rubygems.org/.........
Fetching raabro 1.4.0
Fetching et-orbi 1.4.0
Installing raabro 1.4.0
Installing et-orbi 1.4.0
Fetching fugit 1.12.1
Installing fugit 1.12.1
Fetching solid_queue 1.3.1
Installing solid_queue 1.3.1

% bin/rails solid_queue:install
      create  config/queue.yml
      create  config/recurring.yml
      create  db/queue_schema.rb
      create  bin/jobs
        gsub  config/environments/production.rb

 
続いて、Railsガイドに従い、Solid Queueをセットアップします。
3 Solid Queue: デフォルトのバックエンド | Active Job の基礎 - Railsガイド

config/database.yml に追記します。

development:
  primary:
    <<: *default
    database: storage/development.sqlite3
  queue:
    <<: *default
    database: storage/development_queue.sqlite3
    migrations_paths: db/queue_migrate

 
DBを準備します。

% bin/rails db:prepare 

最後に、 config/environment/development.rbqueue_adapter まわりを修正します。

Rails.application.configure do
  # ...
  config.active_job.queue_adapter = :solid_queue  
  config.solid_queue.connects_to = { database: { writing: :queue } }
end

 

動作確認

ここでも curl で動作確認します。

まずはキューイングのログです。DBアクセスのログとともに以下のログが出ていました。フィルタリングされています。

Started POST "/tokens" for 127.0.0.1 at 2026-01-24 20:46:43 +0900
...
Processing by TokensController#create as */*
  Parameters: {"token" => "[FILTERED]"}
...
[ActiveJob] Enqueued MyJob (Job ID: 5d714d02-c662-4702-9393-f77341beceaf) to SolidQueue(default) with arguments: [{request: {token: "[FILTERED]"}}]
...
[ActiveJob] Enqueued MySecretJob (Job ID: 9d8d1555-16b9-422b-9dae-c0b1034f1429) to SolidQueue(default)

 
続いて、 bin/jobs start にてJobを実行します。

実行ログは log/development.log へと出力されます。確認するとフィルタリングされていました。

[ActiveJob] [MyJob] [5d714d02-c662-4702-9393-f77341beceaf] Performing MyJob (Job ID: 5d714d02-c662-4702-9393-f77341beceaf) from SolidQueue(default) enqueued at 2026-01-24T11:46:44.063828000Z with arguments: [{request: {token: "[FILTERED]"}}]  
[ActiveJob] [MyJob] [5d714d02-c662-4702-9393-f77341beceaf] Performed MyJob (Job ID: 5d714d02-c662-4702-9393-f77341beceaf) from SolidQueue(default) in 2.78ms

 

queue_adapter :delayed_job での動作確認

続いて、サードパーティのJobバックエンドでの動作を確認します。

今回はDelayed::Jobで確認します。まずは、READMEに従いセットアップを行います。
collectiveidea/delayed_job: Database based asynchronous priority queue system -- Extracted from Shopify

% bundle add delayed_job_active_record

% bin/rails generate delayed_job:active_record
      create  bin/delayed_job
       chmod  bin/delayed_job
      create  db/migrate/20260118111515_create_delayed_jobs.rb
      
% bin/rails db:migrate
== 20260118111515 CreateDelayedJobs: migrating ================================
-- create_table(:delayed_jobs)
   -> 0.0008s
-- add_index(:delayed_jobs, [:priority, :run_at], {name: "delayed_jobs_priority"})
   -> 0.0003s
== 20260118111515 CreateDelayedJobs: migrated (0.0011s) =======================

 
続いて、 queue_adapter:delayed_job へと修正します。

config.active_job.queue_adapter = :delayed_job

 
動作確認です。エンキューしたときはフィルタリングされていました。

[ActiveJob] Enqueued MyJob (Job ID: 3ba66b0e-a06d-47bb-9957-2ebf540c934f) to DelayedJob(default) with arguments: [{request: {token: "[FILTERED]"}}]

 
次に bin/rails jobs:work にてJobを実行します。すると、フィルタリングされずにそのままログへ出力されました。

% bin/rails jobs:work
[Worker(host:*** pid:87720)] Starting job worker

# RUNNINGのログでは、そのまま出力されている
[Worker(host:*** pid:87720)] Job MyJob [e6ab8b99-944f-498f-936f-0c6d0ea8c872] from DelayedJob(default) with arguments: [[{"request" => {"token" => "my_secret_token", "_aj_symbol_keys" => ["token"]}, "_aj_symbol_keys" => ["request"]}]] (id=23) (queue=default) RUNNING

# COMPLETEDのログでも、そのまま出力されている
[Worker(host:*** pid:87720)] Job MyJob [e6ab8b99-944f-498f-936f-0c6d0ea8c872] from DelayedJob(default) with arguments: [[{"request" => {"token" => "my_secret_token", "_aj_symbol_keys" => ["token"]}, "_aj_symbol_keys" => ["request"]}]] (id=23) (queue=default) COMPLETED after 0.0066

 
これより、Delayed::Jobの場合は他にもパッチが必要そうでした。

 

Delayed::Jobをパッチする

パッチする適切な場所を探す

まずは、どこにパッチをすればよいかを確認します。

まず、ログの RUNNING などを出力いるところを探すと、 lib/delayed/worker.rb にある Delayed::Worker#runにありました。この中では job_sayを呼んでいました。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/worker.rb#L228-L229

def run(job)
  job_say job, 'RUNNING'
  # ...
end

 
job_sayでは、 job.nameを使っていました。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/worker.rb#L273-L276

def job_say(job, text, level = default_log_level)
  text = "Job #{job.name} (id=#{job.id})#{say_queue(job.queue)} #{text}"
  say text, level
end

 
job.namelib/delayed/backend/base.rb に定義されていました。ここで、 payload_object#display_name があれば、それを返しているようでした。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/backend/base.rb#L60-L64

def name
  @name ||= payload_object.respond_to?(:display_name) ? payload_object.display_name : payload_object.class.name
  # ...
end

 
payload_object の定義を見ると、YAMLとして保存されている handler の値からデシリアライズしたオブジェクトでした。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/backend/base.rb#L71-L75

def payload_object
  @payload_object ||= YAML.load_dj(handler)
  # ...
end

 
この handlerは、 payload_object= にて設定されるものでした。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/backend/base.rb#L66-L69

def payload_object=(object)
  @payload_object = object
  self.handler = object.to_yaml
end

 
payload_object=を直接使っているところはありません。ただ、 enqueue_jobnew(options)するときに、delayed_jobのバックエンドがActiveRecord、かつ、オプションとしてハッシュが渡されてくれば、 ActiveModel::AttributeAssignment の働きで属性へとセットするときに呼び出されそうです。
1.4 AttributeAssignmentモジュール | Active Model の基礎 - Railsガイド

enqueue_jobenqueue から呼ばれます。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/backend/base.rb#L10-L22

def enqueue(*args)
  job_options = Delayed::Backend::JobPreparer.new(*args).prepare
  enqueue_job(job_options)
end

def enqueue_job(options)
  new(options).tap do |job|
    # ...
  end
end

 
Delayed::Backend::JobPreparer を見ると、 set_payloadoptions ハッシュのキー payload_object へ設定してそうでした。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/backend/job_preparer.rb#L23-L25

def set_payload
  options[:payload_object] ||= args.shift
end

 
enqueue はどこで呼ばれるか確認すると、 lib/active_job/queue_adapter/delayed_job_adapter.rb で呼ばれてそうでした。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/active_job/queue_adapters/delayed_job_adapter.rb#L11-L15

def enqueue(job)
  delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), :queue => job.queue_name, :priority => job.priority)
  # ...
end

 
ここの Delayed::Job.enqueue の第一引数 JobWrapperpayload_object として設定されてそうでした。

JobWrapperの定義を確認すると、 display_name がありました。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/active_job/queue_adapters/delayed_job_adapter.rb#L30-L36

def display_name
  base_name = "#{job_data['job_class']} [#{job_data['job_id']}] from DelayedJob(#{job_data['queue_name']})"

  return base_name unless log_arguments?

  "#{base_name} with arguments: #{job_data['arguments']}"
end

 
ここに job_data['arguments'] 、つまりジョブの引数が含まれてそうでした。

よって、 JobWrapper#display_name をパッチするのが良さそうと分かりました。

 
ちなみに、JobWrapper を渡す enqueue メソッドを持つ Delayed::Job の定義を探したところ、worker.rbself.backend=(backend) で別名をつけてそうでした。
https://github.com/collectiveidea/delayed_job/blob/eaef62d844ea980433b807a496136bbd0a6ea625/lib/delayed/worker.rb#L65-L73

def self.backend=(backend)
  if backend.is_a? Symbol
    require "delayed/serialization/#{backend}"
    require "delayed/backend/#{backend}"
    backend = "Delayed::Backend::#{backend.to_s.classify}::Job".constantize
  end
  @@backend = backend # rubocop:disable ClassVars
  silence_warnings { ::Delayed.const_set(:Job, backend) }
end

 
今回の場合だと delayed_job_active_record gemを使っているため、 Delayed::Backend::ActiveRecord::Job が該当しそうです。
https://github.com/collectiveidea/delayed_job_active_record/blob/e5b4fbf8c65698d575d1afc95e4ae55e4646d24e/lib/delayed/backend/active_record.rb#L4-L33

module Delayed
  module Backend
    module ActiveRecord
      # A job object that is persisted to the database.
      # Contains the work object as a YAML field.
      class Job < ::ActiveRecord::Base
      # ...

 

JobWrapper#display_nameをパッチする

パッチする際は Rails.application.config.filter_parametersを使います。

また、Jobの引数のトップレベルがHashやArrayであっても、 filter_parameters で定義されているキーに対してはフィルタリングを行いたいです。

ActiveSupport::ParameterFilter の定義を見ると、 #filter の中で #callを呼んでいました。
https://github.com/rails/rails/blob/2b4feede1b6ead327b40c3415749de58af896e05/activesupport/lib/active_support/parameter_filter.rb#L83-L85

def filter(params)
  @no_filters ? params.dup : call(params)
end

 
#call を確認すると、トップレベルをHashにしておけば、あとはいい感じにやってくれそうでした。
https://github.com/rails/rails/blob/2b4feede1b6ead327b40c3415749de58af896e05/activesupport/lib/active_support/parameter_filter.rb#L125-L133

def call(params, full_parent_key = nil, original_params = params)
  filtered_params = params.class.new

  params.each do |key, value|
    filtered_params[key] = value_for_key(key, value, full_parent_key, original_params)
  end

  filtered_params
end

 
そこで、 #filter を呼ぶときにどんな型が来ても args キーを持つHashとなるようにします。

filtered_arguments = filter.filter({ args: job_data["arguments"] })[:args]

また、ActiveJobと異なり、ActiveSupport.on_load が使えないことから、 Rails.application.config.after_initialize でパッチを当てることにします。

 
パッチの全体はこんな感じです。

Rails.application.config.after_initialize do  
  # DelayedJob の JobWrapper が存在する場合のみ、パッチを行う  
  if defined?(ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper)   
    require "active_job/queue_adapters/delayed_job_adapter"  
  
    # パッチ用のモジュールを定義  
    module DelayedJobArgumentsFilter  
      def display_name  
        base_name = "#{job_data["job_class"]} [#{job_data["job_id"]}] from DelayedJob(#{job_data["queue_name"]})"  
        return base_name unless log_arguments?  

        filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)  
        filtered_arguments = filter.filter({ args: job_data["arguments"] })[:args]
  
        "#{base_name} with arguments: #{filtered_arguments.inspect}"  
      end  
    end  
    # ターゲットのクラスが確実に存在する状態で、モンキーパッチを行う prepend  
    # 対象のクラスの前にモジュールが挿入されるため、クラスに同名メソッドがあったとしても、モジュールのほうが優先して使用される  
ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper.prepend(DelayedJobArgumentsFilter)  
  end  
end

 

動作確認

再度 curl で動作確認します。すると、フィルタリングされた状態でログへ出力されました。

[Worker(*** pid:37897)] Job MyJob [7ab16f93-9265-4510-b9ea-35e20c85d82c] from DelayedJob(default) with arguments: [[{"request" => {"token" => "[FILTERED]", "_aj_symbol_keys" => "[FILTERED]"}, "_aj_symbol_keys" => "[FILTERED]"}]] (id=25) (queue=default) RUNNING

[Worker(*** pid:37897)] Job MyJob [7ab16f93-9265-4510-b9ea-35e20c85d82c] from DelayedJob(default) with arguments: [[{"request" => {"token" => "[FILTERED]", "_aj_symbol_keys" => "[FILTERED]"}, "_aj_symbol_keys" => "[FILTERED]"}]] (id=25) (queue=default) COMPLETED after 0.0083

 

テストコードを書く

毎回 curl で動作確認をするのは手間なので、各パターンのテストコードを書きます。今回はRSpecで書くため、セットアップします。

% bin/rails g rspec:install
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb

 
また、Jobの動作確認で perform_enqueued_jobs を使いたいため、 ActiveJob::TestHelperrails_helper.rb でincludeします。

config.include ActiveJob::TestHelper, type: :job

 

log_arguments=falseのテストコード

テストで確認しやすくするため、標準出力を StringIO へと差し替えます。

around do |example|  
  # 元の設定を退避  
  original_base_logger = ActiveJob::Base.logger  
  original_subscriber_logger = ActiveJob::LogSubscriber.logger  
  original_stdout = $stdout  
  
  # ロガーと標準出力を StringIO に差し替え  
  ActiveJob::Base.logger = logger  
  ActiveJob::LogSubscriber.logger = logger  
  $stdout = log_output  
  
  example.run  
ensure  
  # テスト終了後に設定を元に戻す  
  ActiveJob::Base.logger = original_base_logger  
  ActiveJob::LogSubscriber.logger = original_subscriber_logger  
  $stdout = original_stdout  
end

 
log_arguments=false の場合は、ログにJobの引数が表示されないことを確認します。

なお、ログ出力のタイミングはエンキュー時と実行時の2つあるため、テストの中でエンキューと実行のできる perform_enqueued_jobs を使います。
https://api.rubyonrails.org/v8.1/classes/ActiveJob/TestHelper.html#method-i-perform_enqueued_jobs

RSpec.describe MySecretJob, type: :job do
  describe "引数の非表示化の検証" do  
  # 参考:  
  # ログの出力タイミングはエンキュー時・実行時などがあるが、ActiveJob::LogSubscriberはどちらのタイミングでも動作する  
  # ここでは、常にログへ出力されないことを確認するため、perform_enqueued_jobs + perform_laterを使っている  
  it "Hash形式の引数がログや標準出力に表示されないこと" do  
    payload = { token: "my_secret_data", body: "my_data" }  
    # ジョブをエンキューして実行  
    perform_enqueued_jobs do  
      MySecretJob.perform_later(payload)  
    end  
  
    logs = log_output.string  
  
    # ジョブがエンキュー・実行されたこと自体のログは出力されることを確認  
    expect(logs).to include("Enqueued MySecretJob")  
    expect(logs).to include("Performing MySecretJob")  
  
    # log_arguments = false なので、引数自体がログに含まれないこと  
    expect(logs).not_to include("my_secret_data")  
    expect(logs).not_to include("my_data")  
    expect(logs).not_to include('token')  
    expect(logs).not_to include('[FILTERED]')  
  end
  
  # ...
end

 

ActiveJobのテストコード

こちらも log_arguments=false と同じく、ログの出力先を StrngIOに差し替えつつ、テストコードを書きます。

以下のパターンでは適切にフィルタリングされていることを確認しています。

it "Hashの場合に、tokenキーのみがフィルタリングされていること" do  
  perform_enqueued_jobs do  
    MyJob.perform_later({ token: "PII", body: "my_data" })  
  end  
  logs = log_output.string  
    
  expect(logs).to include("Enqueued MyJob")  
  expect(logs).to include("Performing MyJob")  
  expect(logs).to include('token: "[FILTERED]"')  
  expect(logs).to include('body: "my_data"')  
end

 

Delayed::Jobのテストコード

Delayed::Jobに対するテストコードでは、ログの出力先の差し替えに加えて queue_adapter も差し替えます。テストコードでは test adapterになるためです。

around do |example|  
  old_adapter = ActiveJob::Base.queue_adapter  
  ActiveJob::Base.queue_adapter = :delayed_job
  # ...
ensure  
  ActiveJob::Base.queue_adapter = old_adapter  
end

 
queue_adapterを delayed_job とした場合、Delayed::Jobのジョブは実行されません。

そこで、テストコードの中で明示的に Delayed::Worker.new.work_off してジョブを実行します。

it "Hashの場合に、tokenキーのみがフィルタリングされていること" do  
  MyJob.perform_later({ token: "PII", body: "my_data" })  
  
  enqueued_job = Delayed::Job.last  
  display_name = enqueued_job.payload_object.display_name  
  expect(display_name).to include('"token" => "[FILTERED]"')  
  expect(display_name).to include('"body" => "my_data"')  
  
  Delayed::Worker.new.work_off  
  
  logs = log_output.string  
  expect(logs).to include("Enqueued MyJob")  
  expect(logs).to include("Performing MyJob")  
  expect(logs).to include('token: "[FILTERED]"')  
  expect(logs).to include('body: "my_data"')  
end

 

ソースコード

GitHubに上げました。
https://github.com/thinkAmi-sandbox/parameter_filter_job-example

今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/parameter_filter_job-example/pull/1




以上の内容はhttps://thinkami.hatenablog.com/entry/2026/01/25/225412より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14