개요

쿼리 로깅은 개발이나 디버깅 단계에서 유리하지만 성능에는 엄청난 악영향을 줍니다. 이때문에 Laravel 에서는 쿼리 로깅이 기본적으로 비활성화 되어 있습니다.


쿼리 로깅을 남기는 방법을 여러 가지가 있는데(라라벨 5 eloquent orm query log 남기기 참고) 라라벨의 이벤트 리스너을 사용하여 로깅을 남기는 방법을 정리해 봅니다.


리스너 구현

다음 명령어로 쿼리 이벤트 리스너를 stub 을 생성합니다.

리스너 생성

php artisan make:listener LoggingEloquentQueryListener
BASH


이제 App\Listeners 폴더에 LoggingEloquentQueryListener 라는 클래스가 생긴 것을 볼수 있습니다.

LoggingEloquentQueryListener.php

<?php

namespace App\Listeners;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class LoggingEloquentQueryListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  object  $query
     * @return void
     */
    public function handle($query)
    {
        // 
    }
}

PHP


이제 handle () 메서드에 쿼리 로그를 남기는 기능을 구현합니다.

쿼리 로깅 구현

<?php

namespace App\Listeners;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;

class LoggingEloquentQueryListener
{
    /**
     * Handle the event.
     *
     * @param  object  $query
     * @return void
     */
    public function handle($query)
    {
        // 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';
            }

            Log::channel($channel)->info([
                'sql' => $query->sql,
                'bindings' => $query->bindings,
                'time' => $query->time,
				'connection' => $query->connectionName,
            ]);
        }
    }
}
PHP

운영은 성능 이슈때문에  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,
        ],
    ];
PHP


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,
     	   ],
	],
PHP


이제 운영이 아니라면 모든 query log 를 남기게 되며 storage/logs/sql-날자명.log 파일에서 로그 내용을 확인할 수 있습니다. 운영 환경일 경우 로그를 남기려면 .env 에 다음 항목을 설정해 주면 됩니다.

QUERY_LOGGING=true
CODE

운영 환경에서 config cache 를 사용할 경우 다음 명령어로 캐시를 재생성해 주어야 합니다.

php artisan config:cache
CODE



같이 보기