概要
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 -- : ξ(✿>◡❛)ξ もう何も怖くない
参考
-
Railsで、複数の出力先にlogを出力する
- 「エラーログだけ 2 箇所に出力したい場合」の方法も記載されています。