로깅

업데이트됨

번역일: 2026년 8월 3일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 8월 3일
번역 갱신
2026년 8월 3일

로깅

소개

Laravel은 애플리케이션 내부에서 어떤 일이 벌어지는지 파악할 수 있도록 강력한 로깅 서비스를 제공합니다. 로그 메시지를 파일에 기록하거나, 시스템 에러 로그로 출력하거나, Slack으로 전송해 팀 전체에 알림을 보낼 수도 있습니다.

Laravel 로깅은 채널(channel) 개념을 중심으로 동작합니다. 채널은 로그 정보를 기록하는 방식 하나하나를 의미합니다. 예를 들어 single 채널은 단일 파일에 로그를 기록하고, slack 채널은 Slack으로 메시지를 전송합니다. 메시지의 심각도(severity)에 따라 여러 채널에 동시에 기록하는 것도 가능합니다.

내부적으로는 Monolog 라이브러리를 사용하며, 다양한 강력한 로그 핸들러를 지원합니다. Laravel은 이 핸들러들을 쉽게 설정하고 조합할 수 있도록 편리한 인터페이스를 제공합니다.

설정

로깅과 관련된 모든 설정은 config/logging.php 파일에 있습니다. 이 파일에서 각 로그 채널을 설정할 수 있으므로, 사용 가능한 채널과 옵션들을 꼭 살펴보시기 바랍니다.

기본적으로 Laravel은 stack 채널을 사용합니다. stack 채널은 여러 채널을 하나로 묶어주는 역할을 합니다. 스택 구성에 대한 자세한 내용은 아래 문서를 참고하세요.

사용 가능한 채널 드라이버

각 로그 채널은 "드라이버"로 구동됩니다. 드라이버는 로그 메시지가 실제로 어디에, 어떻게 기록될지를 결정합니다. 모든 Laravel 애플리케이션에서 사용할 수 있는 드라이버 목록은 다음과 같습니다. 대부분은 config/logging.php에 이미 예시 항목이 포함되어 있습니다.

이름설명
custom지정한 팩토리를 호출해 채널을 생성하는 드라이버
daily날마다 파일을 교체하는 RotatingFileHandler 기반 드라이버
monthly월마다 파일을 교체하는 RotatingFileHandler 기반 드라이버
errorlogErrorLogHandler 기반 드라이버
monolog지원되는 모든 Monolog 핸들러를 사용할 수 있는 팩토리 드라이버
papertrailSyslogUdpHandler 기반 드라이버
single단일 파일 또는 경로에 기록하는 채널 (StreamHandler)
slackSlackWebhookHandler 기반 드라이버
stack여러 채널을 묶어 다중 채널을 구성하는 래퍼
syslogSyslogHandler 기반 드라이버

NOTE

monologcustom 드라이버에 대한 더 자세한 내용은 고급 채널 커스터마이징 문서를 참고하세요.

채널 이름 설정

기본적으로 Monolog는 현재 환경(production, local 등)과 동일한 "채널 이름"으로 초기화됩니다. 이 값을 변경하려면 채널 설정에 name 옵션을 추가하면 됩니다.

'stack' => [ 'driver' => 'stack', 'name' => 'channel-name', 'channels' => ['single', 'slack'], ],

채널 사전 요구사항

Single, Daily, Monthly 채널 설정

single, daily, monthly 채널에는 세 가지 선택적 설정 옵션이 있습니다.

이름설명기본값
bubble메시지 처리 후 다른 채널로 전파할지 여부true
locking로그 파일 기록 전 파일 잠금 시도 여부false
permission로그 파일의 권한 설정0644

dailymonthly 채널의 파일 보관 기간은 max_files 옵션으로 설정할 수 있습니다. daily 채널의 경우 LOG_DAILY_DAYS 환경 변수로도 설정 가능합니다.

Papertrail 채널 설정

papertrail 채널은 hostport 설정이 필요합니다. 각각 PAPERTRAIL_URLPAPERTRAIL_PORT 환경 변수로 지정할 수 있으며, 해당 값은 Papertrail에서 확인하세요.

Slack 채널 설정

slack 채널에는 url 설정이 필요합니다. LOG_SLACK_WEBHOOK_URL 환경 변수로 지정할 수 있으며, 이 URL은 Slack 팀에 설정한 Incoming Webhook URL이어야 합니다.

기본적으로 Slack은 critical 레벨 이상의 로그만 수신합니다. LOG_LEVEL 환경 변수 또는 Slack 채널 설정 배열의 level 옵션을 수정해 이 기준을 변경할 수 있습니다.

Deprecation 경고 로깅

PHP, Laravel, 그리고 다양한 라이브러리들은 특정 기능이 곧 제거될 예정임을 deprecation 경고로 알립니다. 이러한 경고를 로그로 남기고 싶다면 LOG_DEPRECATIONS_CHANNEL 환경 변수나 config/logging.php에서 원하는 채널을 지정하세요.

'deprecations' => [ 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 'trace' => env('LOG_DEPRECATIONS_TRACE', false), ], 'channels' => [ // ... ]

또는 deprecations라는 이름의 로그 채널을 직접 정의할 수도 있습니다. 이 이름의 채널이 존재하면 항상 이 채널로 deprecation 경고가 기록됩니다.

'channels' => [ 'deprecations' => [ 'driver' => 'single', 'path' => storage_path('logs/php-deprecation-warnings.log'), ], ],

로그 스택 구성하기

앞서 설명했듯이, stack 드라이버를 사용하면 여러 채널을 하나의 로그 채널로 묶을 수 있습니다. 아래는 실제 운영 환경에서 흔히 볼 수 있는 스택 설정 예시입니다.

'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['syslog', 'slack'], //
'ignore_exceptions' => false,
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
'replace_placeholders' => true,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
'level' => env('LOG_LEVEL', 'critical'),
'replace_placeholders' => true,
],
],

이 설정을 살펴보면, stack 채널은 channels 옵션에 syslogslack 두 채널을 포함합니다. 로그 메시지가 기록될 때 두 채널 모두 처리 대상이 되지만, 실제로 기록 여부는 아래에서 설명할 메시지의 심각도(level)에 따라 결정됩니다.

로그 레벨

위 예시에서 syslogslack 채널 설정에 있는 level 옵션에 주목하세요. 이 옵션은 해당 채널에 실제로 기록되기 위한 최소 로그 레벨을 지정합니다. Laravel 로깅의 기반인 Monolog는 RFC 5424 명세에 정의된 8가지 레벨을 지원합니다. 심각도가 높은 순서대로 나열하면 다음과 같습니다.

emergency → alert → critical → error → warning → notice → info → debug

예를 들어 debug 메서드로 로그를 기록하면:

Log::debug('An informational message.');

위 설정에서 syslog 채널(최소 레벨: debug)은 이 메시지를 시스템 로그에 기록하지만, slack 채널(최소 레벨: critical)은 기록하지 않습니다. 반면 emergency 레벨의 메시지를 기록하면 두 채널 모두의 최소 레벨 조건을 충족하므로 시스템 로그와 Slack 양쪽 모두에 기록됩니다.

Log::emergency('The system is down!');

로그 메시지 작성하기

Log 파사드를 사용해 로그를 기록할 수 있습니다. RFC 5424 명세에 정의된 8가지 레벨 메서드를 모두 지원합니다.

use Illuminate\Support\Facades\Log; Log::emergency($message); Log::alert($message); Log::critical($message); Log::error($message); Log::warning($message); Log::notice($message); Log::info($message); Log::debug($message);

이 중 어느 메서드든 호출하면 해당 레벨로 logging 설정 파일에서 지정한 기본 채널에 메시지가 기록됩니다.

<?php namespace App\Http\Controllers; use App\Models\User; use Illuminate\Support\Facades\Log; use Illuminate\View\View; class UserController extends Controller { /** * 주어진 사용자의 프로필을 표시합니다. */ public function show(string $id): View { Log::info('사용자 프로필 조회: {id}', ['id' => $id]); return view('user.profile', [ 'user' => User::findOrFail($id) ]); } }

컨텍스트 정보

로그 메서드에 컨텍스트 데이터 배열을 함께 전달할 수 있습니다. 전달된 데이터는 로그 메시지와 함께 형식에 맞게 출력됩니다.

use Illuminate\Support\Facades\Log; Log::info('사용자 {id} 로그인 실패.', ['id' => $user->id]);

특정 채널의 이후 모든 로그 항목에 공통 컨텍스트 정보를 포함하고 싶을 때는 Log 파사드의 withContext 메서드를 사용하세요. 예를 들어 요청마다 고유한 요청 ID를 로그에 포함하려면 미들웨어에서 다음과 같이 활용할 수 있습니다.

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Response; class AssignRequestId { /** * 들어오는 요청을 처리합니다. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { $requestId = (string) Str::uuid(); Log::withContext([ 'request-id' => $requestId ]); $response = $next($request); $response->headers->set('Request-Id', $requestId); return $response; } }

모든 로깅 채널에 걸쳐 컨텍스트 정보를 공유하려면 Log::shareContext() 메서드를 사용하세요. 이 메서드로 지정한 정보는 이미 생성된 채널과 이후 생성되는 채널 모두에 제공됩니다.

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Response; class AssignRequestId { /** * 들어오는 요청을 처리합니다. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { $requestId = (string) Str::uuid(); Log::shareContext([ 'request-id' => $requestId ]); // ... } }

NOTE

큐 Job 처리 중에 로그 컨텍스트를 공유해야 한다면 Job 미들웨어를 활용하세요.

특정 채널에 로그 작성하기

기본 채널이 아닌 특정 채널에 로그를 기록하고 싶다면 Log 파사드의 channel 메서드를 사용하세요. 설정 파일에 정의된 채널이라면 어느 것이든 지정할 수 있습니다.

use Illuminate\Support\Facades\Log; Log::channel('slack')->info('무언가 발생했습니다!');

여러 채널을 묶은 임시 스택을 만들고 싶다면 stack 메서드를 사용하세요.

Log::stack(['single', 'slack'])->info('무언가 발생했습니다!');

온디맨드 채널

설정 파일에 미리 정의하지 않고, 런타임에 설정 배열을 직접 전달해 즉석에서 채널을 생성할 수도 있습니다. Log 파사드의 build 메서드에 설정 배열을 전달하면 됩니다.

use Illuminate\Support\Facades\Log; Log::build([ 'driver' => 'single', 'path' => storage_path('logs/custom.log'), ])->info('무언가 발생했습니다!');

온디맨드 채널을 스택에 포함시킬 수도 있습니다. stack 메서드에 전달하는 배열에 온디맨드 채널 인스턴스를 넣으면 됩니다.

use Illuminate\Support\Facades\Log; $channel = Log::build([ 'driver' => 'single', 'path' => storage_path('logs/custom.log'), ]); Log::stack(['slack', $channel])->info('무언가 발생했습니다!');

Monolog 채널 커스터마이징

채널별 Monolog 커스터마이징

기존 채널의 Monolog 설정을 세밀하게 제어하고 싶을 때가 있습니다. 예를 들어, Laravel 내장 single 채널에 커스텀 FormatterInterface 구현체를 적용하고 싶은 경우가 그렇습니다.

이를 위해 채널 설정에 tap 배열을 정의하세요. tap 배열에는 Monolog 인스턴스가 생성된 후 이를 가로채 커스터마이징할 클래스 목록을 나열합니다. 이 클래스들의 위치에 대한 별도의 규칙은 없으므로, 프로젝트 내에 적절한 디렉터리를 만들어 자유롭게 배치할 수 있습니다.

'single' => [ 'driver' => 'single', 'tap' => [App\Logging\CustomizeFormatter::class], 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), 'replace_placeholders' => true, ],

tap 옵션을 설정한 뒤에는 Monolog 인스턴스를 커스터마이징할 클래스를 정의합니다. 이 클래스는 __invoke 메서드 하나만 필요하며, Illuminate\Log\Logger 인스턴스를 인자로 받습니다. Illuminate\Log\Logger는 내부 Monolog 인스턴스로 모든 메서드 호출을 위임합니다.

<?php namespace App\Logging; use Illuminate\Log\Logger; use Monolog\Formatter\LineFormatter; class CustomizeFormatter { /** * 주어진 로거 인스턴스를 커스터마이징합니다. */ public function __invoke(Logger $logger): void { foreach ($logger->getHandlers() as $handler) { $handler->setFormatter(new LineFormatter( '[%datetime%] %channel%.%level_name%: %message% %context% %extra%' )); } } }

NOTE

tap 배열에 나열된 모든 클래스는 서비스 컨테이너를 통해 해석되므로, 생성자 의존성은 자동으로 주입됩니다.

Monolog 핸들러 채널 생성하기

Monolog는 다양한 핸들러를 제공하지만, Laravel이 모든 핸들러에 대응하는 내장 채널을 제공하지는 않습니다. Laravel 로그 드라이버가 없는 특정 Monolog 핸들러를 채널로 직접 사용하고 싶다면 monolog 드라이버를 활용하세요.

monolog 드라이버를 사용할 때 handler 옵션으로 사용할 핸들러 클래스를 지정합니다. 핸들러 생성자에 전달할 인자가 있다면 handler_with 옵션으로 지정하세요.

'logentries' => [ 'driver' => 'monolog', 'handler' => Monolog\Handler\SyslogUdpHandler::class, 'handler_with' => [ 'host' => 'my.logentries.internal.datahubhost.company.com', 'port' => '10000', ], ],

Monolog 포매터

monolog 드라이버를 사용하면 기본적으로 LineFormatter가 사용됩니다. formatterformatter_with 옵션으로 원하는 포매터 타입을 지정할 수 있습니다.

'browser' => [ 'driver' => 'monolog', 'handler' => Monolog\Handler\BrowserConsoleHandler::class, 'formatter' => Monolog\Formatter\HtmlFormatter::class, 'formatter_with' => [ 'dateFormat' => 'Y-m-d', ], ],

핸들러 자체에서 포매터를 제공하는 경우에는 formatter 옵션 값을 default로 설정하면 됩니다.

'newrelic' => [ 'driver' => 'monolog', 'handler' => Monolog\Handler\NewRelicHandler::class, 'formatter' => 'default', ],

Monolog 프로세서

Monolog는 메시지를 기록하기 전에 가공할 수 있는 프로세서 기능도 지원합니다. 직접 프로세서를 만들거나 Monolog가 제공하는 기존 프로세서를 활용할 수 있습니다.

monolog 드라이버의 프로세서를 설정하려면 채널 설정에 processors 값을 추가하세요.

'memory' => [ 'driver' => 'monolog', 'handler' => Monolog\Handler\StreamHandler::class, 'handler_with' => [ 'stream' => 'php://stderr', ], 'processors' => [ // 클래스명만 지정하는 간단한 방식 Monolog\Processor\MemoryUsageProcessor::class, // 옵션과 함께 지정하는 방식 [ 'processor' => Monolog\Processor\PsrLogMessageProcessor::class, 'with' => ['removeUsedContextFields' => true], ], ], ],

팩토리로 커스텀 채널 생성하기

Monolog 인스턴스의 초기화와 설정을 완전히 직접 제어하는 커스텀 채널을 만들고 싶다면 config/logging.php에서 custom 드라이버 타입을 사용하세요. 설정에는 Monolog 인스턴스를 생성할 팩토리 클래스를 via 옵션으로 지정합니다.

'channels' => [ 'example-custom-channel' => [ 'driver' => 'custom', 'via' => App\Logging\CreateCustomLogger::class, ], ],

custom 드라이버 채널을 설정했다면, Monolog 인스턴스를 생성할 클래스를 정의하세요. 이 클래스는 Monolog 로거 인스턴스를 반환하는 __invoke 메서드 하나만 필요하며, 채널 설정 배열이 인자로 전달됩니다.

<?php namespace App\Logging; use Monolog\Logger; class CreateCustomLogger { /** * 커스텀 Monolog 인스턴스를 생성합니다. */ public function __invoke(array $config): Logger { return new Logger(/* ... */); } }

Pail로 실시간 로그 확인하기

버그를 디버깅하거나 특정 유형의 오류를 모니터링할 때 애플리케이션 로그를 실시간으로 확인해야 할 때가 많습니다.

Laravel Pail은 커맨드라인에서 Laravel 애플리케이션의 로그를 실시간으로 확인할 수 있는 패키지입니다. 기본 tail 명령어와 달리, Pail은 Laravel Nightwatch, Sentry, Flare 등 모든 로그 드라이버와 호환됩니다. 또한 원하는 로그를 빠르게 찾을 수 있도록 유용한 필터 옵션도 제공합니다.

설치

WARNING

Laravel Pail을 사용하려면 PHP의 PCNTL 확장이 필요합니다.

Composer로 Pail을 개발 의존성으로 설치하세요.

composer require --dev laravel/pail

사용법

로그 실시간 확인을 시작하려면 pail 명령어를 실행하세요.

php artisan pail

출력 상세도를 높이고 로그가 잘리지 않도록 하려면 -v 옵션을 사용하세요.

php artisan pail -v

예외 스택 트레이스까지 포함한 최대 상세 출력을 원한다면 -vv 옵션을 사용하세요.

php artisan pail -vv

실시간 확인을 중단하려면 언제든지 Ctrl+C를 누르세요.

로그 필터링

`--filter`

--filter 옵션으로 로그의 타입, 파일, 메시지, 스택 트레이스 내용을 기준으로 필터링할 수 있습니다.

php artisan pail --filter="QueryException"

`--message`

메시지 내용만으로 필터링하려면 --message 옵션을 사용하세요.

php artisan pail --message="User created"

`--level`

로그 레벨을 기준으로 필터링하려면 --level 옵션을 사용하세요.

php artisan pail --level=error

`--user`

특정 사용자가 인증된 상태에서 기록된 로그만 표시하려면 --user 옵션에 해당 사용자의 ID를 전달하세요.

php artisan pail --user=1

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 8월 3일