Laravel5.5でmonolog->pushHandlerするときはログレベルを指定しなければならない


※Laravel5.5の話です
Laravel5.6からはログの仕様そのものが変わっています

概要

Laravelでは柔軟なログ設定が可能。
ログを標準出力にだしつつファイルにも記録したいということも可能で、これを以下のようにMonologに追加する形で実装していました。

$handler = new \Monolog\Handler\StreamHandler('php://stderr');

$monolog = \Log::getMonoLog();
$monolog->pushHandler($handler);

ログレベルの変更がきかない

開発時にずっとdebugレベルだったのでなんとも思わなかったが、ふとデプロイ後に.envを書き換えてもdebugレベルが出続ける。

# 相変わらずdebugレベルが出力される

$ cat .env | grep APP_LOG_LEVEL
APP_LOG_LEVEL=info

ログレベルの指定がない場合にはdebugとなる

ログレベルの判定をどこでやっているのか追っていくと、
vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php でやっていることがわかりました。

    /**
     * @param int     $level  The minimum logging level at which this handler will be triggered
     * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
     */
    public function __construct($level = Logger::DEBUG, $bubble = true)
    {
        $this->setLevel($level);
        $this->bubble = $bubble;
    }

    /**
     * {@inheritdoc}
     */
    public function isHandling(array $record)
    {
        return $record['level'] >= $this->level;
    }

    /**
     * Sets minimum logging level at which this handler will be triggered.
     *
     * @param  int|string $level Level or level name
     * @return self
     */
    public function setLevel($level)
    {
        $this->level = Logger::toMonologLevel($level);

        return $this;
    }

必要箇所だけぬいてます。
isHandling でレベル判定してます。
そもそもログLevelは __constructsetLevel 関数が呼ばれここでしています。

backtraceなどで追いかけると、MonologのHandlerを作るときにコンストラクタが呼ばれ、ログレベルが設定されるようです。
前述Handlerを作るところで出力先のみ指定していたので、debugが自動的に選択されてしまったようです。

修正

.envに指定するのはログレベルの文字列ですが、これを数値に変換しなければなりません。
これも setLevel の実装を参考に以下のようにしました。

$level = \Monolog\Logger::toMonologLevel(config('app.log_level'));
$handler = new \Monolog\Handler\StreamHandler('php://stderr', $level);

$monolog = \Log::getMonoLog();
$monolog->pushHandler($handler);