Laravel Event Listener를 사용하여 엘로퀀트 쿼리 로그(Eloquent Query Logging) 남기기
개요
쿼리 로깅은 개발이나 디버깅 단계에서 유리하지만 성능에는 엄청난 악영향을 줍니다. 이때문에 Laravel 에서는 쿼리 로깅이 기본적으로 비활성화 되어 있습니다.
쿼리 로깅을 남기는 방법을 여러 가지가 있는데(라라벨 5 query log 남기기 참고) 라라벨의 이벤트 리스너을 사용하여 로깅을 남기는 방법을 정리해 봅니다.
리스너 구현
다음 명령어로 쿼리 이벤트 리스너 stub 을 생성합니다.
리스너 생성
php artisan make:listener LoggingEloquentQueryListener
App\Listeners 폴더에 LoggingEloquentQueryListener 라는 클래스가 생긴 것을 볼수 있습니다.
LoggingEloquentQueryListener.php
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Database\Events\QueryExecuted;
class LoggingEloquentQueryListener
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param QueryExecuted $event
* @return void
*/
public function handle(QueryExecuted $event)
{
//
}
}
handle () 메서드에 쿼리 로그를 남기는 기능을 구현합니다.
쿼리 로깅 구현
<?php
namespace App\Listeners;
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
class LoggingEloquentQueryListener
{
/**
* Handle the event.
*
* @param QueryExecuted $event
* @return void
*/
public function handle(QueryExecuted $event)
{
// production 이 아니거나 logging.query_logging 이 true 일 경우 로깅
if (app()->environment() !== 'production' || config('logging.query_logging')) {
// php-fpm 이 생성하는 log 와 권한 충돌을 막기 위해 console 에서 실행시에는 별도 채널에 로그 기록
$channel = 'sql';
if (app()->runningInConsole()) {
$channel = 'sql-cli';
}
$message = [
'sql' => $event->sql,
'bindings' => $event->bindings,
'time' => $event->time,
'connection' => $event->connectionName,
];
Log::channel($channel)->info(json_encode($message, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
}
}
}
운영은 성능 이슈때문에 query logging 을 끄는 게 좋지만 디버깅이 필요할 수 있으므로 config 설정 여부에 따라 로깅을 남기도록 구현합니다.
구현이 완료되면 Event 를 받을 수 있도록 EventServiceProvider 에의 $listen 항목에 구현한 클래스를 등록하며 이벤트 클래스는 \Illuminate\Database\Events\QueryExecuted 입니다.
App\Providers\EventServiceProvider
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
// query logging listener
\Illuminate\Database\Events\QueryExecuted::class => [
LoggingEloquentQueryListener::class,
],
];
config 설정
이제 config/logging.php 에 로그 채널과 로그 항목을 추가합니다.
config/logging.php
<?php
return [
'query_logging' => env('QUERY_LOGGING', false),
// sql 로깅용 채널 추가
'channels' => [
//...
'sql' => [
'driver' => 'daily',
'path' => storage_path('logs/sql.log'),
'level' => env('QUERY_LOG_LEVEL','info'),
'days' => 14,
],
// console log channel
'sql-cli' => [
'driver' => 'daily',
'path' => storage_path('logs/sql-cli.log'),
'level' => env('QUERY_LOG_LEVEL','info'),
'days' => 14,
],
],
이제 운영이 아니라면 모든 query log 를 남기게 되며 storage/logs/sql-날자명.log 파일에서 로그 내용을 확인할 수 있습니다.
운영 환경일 경우 로그를 남기려면 .env 에 다음 항목을 설정해 주면 됩니다.
QUERY_LOGGING=true
운영 환경에서 config cache 를 사용할 경우 다음 명령어로 캐시를 재생성해 주어야 합니다.
$ php artisan config:cache