search
LoginSignup
35

More than 5 years have passed since last update.

posted at

Logger のログファイルへの出力を標準出力にも出力したい

概要

Rails プロジェクトでバッチ処理を実装していた際に、ログファイルへの出力を標準出力にも出力したいというケースがありました。例えば、開発中に rails runner コマンドを利用してバッチ処理を手動でキックする際は、ログに出力する内容をコンソール上にも出力したいですよね。

この場合、

error_message = '逝ってしまったわ、円環の理に導かれて…'

puts(error_message)
logger.error(error_message)

と書くのはあまりスマートではありませんね。
そこでもっと良い解決策がないか、調べてみました。

解決策

ActiveSupport::Logger.broadcast メソッドで実現できます。

このメソッドを使って、実際に以下のようなバッチ処理専用 Logger を実装してみました。

module MamiLogger
  # MamiLogger (Module) クラスのオブジェクトの特異メソッド (モジュールメソッド) として定義する。
  class << self
    delegate(
      :debug,
      :info,
      :warn,
      :error,
      :fatal,
      to: :logger
    )

    def logger
      @logger ||= begin
        # (1) 専用のログファイル出力用の Logger オブジェクトを作成する。
        logger = ActiveSupport::Logger.new(Rails.root.join('log', "mami_#{Rails.env}.log", 'monthly')
        logger.formatter = Logger::Formatter.new
        logger.datetime_format = '%Y-%m-%d %H:%M:%S'

        # (2) 標準出力用の Logger オブジェクトを作成する。
        srdout_logger = ActiveSupport::Logger.new(STDOUT)
        # (3) 複数のログを出力する機能を備えた Module オブジェクトを作成する。
        multiple_loggers =
         ActiveSupport::Logger.broadcast(srdout_logger)
        # (4) (3) で作成した Module オブジェクトを (1) に extend する。
        logger.extend(multiple_loggers)

        logger
      end
    end
  end
end

上記のコードのように、2 つ目の Logger オブジェクトを作成して、それを ActiveSupport::Logger.broadcast メソッドの引数に渡したものを 1 つ目の Logger オブジェクトに extend します。
そうすることで、複数の出力先に出力する Logger オブジェクトを作成することができます。

MamiLogger.info('ξ(✿>◡❛)ξ もう何も怖くない')
console
'ξ(✿>◡❛)ξ もう何も怖くない'
log/mami_development.log
I, [2015-03-31T18:47:22.344851 #65728]  INFO -- : ξ(✿>◡❛)ξ もう何も怖くない

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
35