ActiveRecordやRefile、OmniAuthなどはGem毎のloggerを設定できる。
Refileの実装を見てみるとmoduleのインスタンス変数としてloggerを用意している。
module GemName
class << self
attr_accessor :logger
def configure
yield self
end
end
end
require 'logger'
GenName.configure do |config|
config.logger = Logger.new($stdout)
end
使うときは GemName.logger.info
と全力で。どこからでも呼び出せる。
GemName.logger.info 'Start do something'
プログラムの初期化時にloggerを指定することができるため、フレームワークが用意したロガーを使うことも簡単。
# configure blockを使う
GemName.configure do |config|
config.logger = Rails.logger
end
# 直接代入もできる
GemName.logger = Rails.logger
loggerが必要だったらこれに似た方法でloggerを設定できるようにすればいい。
あまり勧めない例
エントリポイントで生成したloggerを頑張って引数で渡し続けるやつ。
require 'logger'
module GemNname
class CLI
def run(*args)
logger = Logger.new($stdout)
options = { ... }
# 引数で渡すよ!
DoSomething.new(logger, options).execute
end
end
class DoSomething
# 渡ってきたよ!
def initialize(logger, options)
@logger = logger
@options = options
end
def execute
logger.debug 'Start do something'
end
end
end
GemName::CLI.new.run(ARGV.dup)
この形で書かれた中規模のプログラムがあって辛い思いをしてる。
というのもlogを出力したいだけなのに呼び出し階層を辿ってコンストラクタなどにloggerをいちいち追加する必要があるから。
好きなタイミングでログを出力したいけど、別にloggerの取得方法に興味はないし、そのために引数を増やすなんてことはしたくないのだ。