[Laravel6.0] monologでカスタムログを出力する。

今回は、Laravelで出力するログをカスタマイズしていきます。

#新しくチャンネルを作成する
config/logging.phpで、新しくチャンネルを作成し、新しいチャンネルをデフォルトで使用するようにします。

```php:config/logging.php
    'default' => env('LOG_CHANNEL', 'stack'),

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            // デフォルトで、customlogチャンネルを使用する
            'channels' => ['customlog'],
            'ignore_exceptions' => false,
        ],

        // 新しいチャンネル名
        'customlog' => [
            // customドライバを選択
            'driver' => 'custom',
            // monologインスタンスを作成するためのクラスを指定
            'via' => \App\Logging\CustomFormatterLog::class,
            'level' => 'info',
            'name' => 'customlog',
        ],
```

#ログをカスタマイズする

```php:app/Logging/CustomFormatterLog
<?php

namespace App\Logging;

use Monolog\Handler\StreamHandler;
use Monolog\Formatter\JsonFormatter;
use Monolog\Logger;
use App\Logging\CustomJsonFormatter;

class CustomFormatterLog extends FormatterAbstract.php
{
    public function __invoke(array $config)
    {
        $handler = new StreamHandler(env('/project/storage/logs/info.log', 'php://stdout'), $this->level($config));

        $handler->setFormatter(new CustomJsonFormatter());

        $log = new Logger($this->parseChannel($config));

        $log->pushHandler($handler);

        return $log;
    }
}
```

```php:app/Logging/FormatterAbstract.php
abstract class ConfigFormatter
{
    protected $levels = [
        'debug'     => Monolog::DEBUG,
        'info'      => Monolog::INFO,
        'notice'    => Monolog::NOTICE,
        'warning'   => Monolog::WARNING,
        'error'     => Monolog::ERROR,
        'critical'  => Monolog::CRITICAL,
        'alert'     => Monolog::ALERT,
        'emergency' => Monolog::EMERGENCY,
    ];

    protected function parseChannel(array $config)
    {
        if (!isset($config['name'])) {
            return 'customlog';
        }
        return $config['name'];
    }

    protected function level(array $config)
    {
        $level = $config['level'] ?? 'debug';

        if (isset($this->levels[$level])) {
            return $this->levels[$level];
        }

        throw new InvalidArgumentException('Invalid log level.');
    }
}
```
ログのカスタマイズはapp/Logging/CustomJsonFormatter.phpで行います。
今回は、カスタムログをJson形式で出力してみます。Json形式で出力したい時は、monologのFormatterであるJsonFormatterを使うと便利です。[^1]

```php:app/Logging/CustomJsonFormatter.php
<?php

namespace App\Logging;

use Monolog\Formatter\JsonFormatter as BaseJsonFormatter;

class CustomJsonFormatter extends BaseJsonFormatter
{

    public function format(array $record) : string
    {
        // ここでログをカスタマイズします。
        $record = [
          
            'method' => request()->server('REQUEST_METHOD'),
            'http_status' => $record['level'],
            'latency' => $record['latency']
        ];

        $jsonLog = $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');

        return $jsonLog;
    }
}
```

#ログ出力用のMiddlewareを作成する
今回は、レスポンスログを出力してみます。ログ出力のため**Middleware**を作成します。

```
php artisan make:middleware ResponseLogMiddleware
```

###Middlewareを追加
app/Http/Kernel.phpの$middlewareプロパティへ追加。

```php:app/Http/Kernel.php
protected $middleware = [
        // ... 省略
        \App\Http\Middleware\ResponseLogMiddleware::class,
    ];
```

###ResponseLogMiddlewareを編集
せっかくなので、今回はリクエストからレスポンスにかかった時間もログに出力したいと思います。

```php:app/Http/Middleware/ResponseLogMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;
use Log;

class ResponseLogMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        $responseLog = [];
        // リクエストからレスポンスにかかる時間を計算
        $responseLog['latency'] = (microtime(true) - $request->server->get('REQUEST_TIME_FLOAT'));
        Log::info('request', $responseLog);
        return $response;
    }
}

```

これで、**storage/logs/info.log**に次のようなログが出力されていればOKです！

```
{"method":"GET","http_status":200,"latency":0.9532308578491211}
```


[^1]: monologでは他にも様々なFormatterやHandler等が用意されています。 
 https://github.com/Seldaek/monolog