본문 바로가기

로깅

업데이트됨

번역일: 2026년 10월 3일

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

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

로깅

소개

애플리케이션 내부에서 어떤 일이 일어나고 있는지 파악하기 쉽도록, Laravel은 강력한 로깅 서비스를 제공합니다. 이를 통해 로그 메시지를 파일, 시스템 에러 로그, 심지어 Slack으로 전송하여 팀 전체에 알릴 수도 있습니다.

Laravel의 로깅은 "채널(channel)" 개념을 기반으로 합니다. 각 채널은 로그 정보를 기록하는 특정 방식을 나타냅니다. 예를 들어 single 채널은 로그를 하나의 파일에 기록하고, slack 채널은 로그 메시지를 Slack으로 전송합니다. 로그 메시지는 심각도(severity)에 따라 여러 채널에 동시에 기록될 수도 있습니다.

내부적으로 Laravel은 Monolog 라이브러리를 사용하며, 이를 통해 다양하고 강력한 로그 핸들러를 지원합니다. Laravel은 이러한 핸들러들을 손쉽게 설정할 수 있도록 지원하므로, 여러 핸들러를 자유롭게 조합하여 애플리케이션에 맞는 로그 처리 방식을 구성할 수 있습니다.

설정

애플리케이션의 로깅 동작을 제어하는 모든 설정 옵션은 config/logging.php 설정 파일에 들어 있습니다. 이 파일을 통해 애플리케이션의 로그 채널을 구성할 수 있으므로, 사용 가능한 각 채널과 그 옵션들을 한 번씩 살펴보는 것이 좋습니다. 아래에서는 자주 사용되는 몇 가지 옵션을 살펴보겠습니다.

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

사용 가능한 채널 드라이버

각 로그 채널은 "드라이버(driver)"에 의해 동작합니다. 드라이버는 로그 메시지가 실제로 어떻게, 어디에 기록되는지를 결정합니다. 모든 Laravel 애플리케이션에서는 다음과 같은 로그 채널 드라이버를 사용할 수 있습니다. 대부분의 드라이버는 애플리케이션의 config/logging.php 설정 파일에 이미 항목으로 존재하므로, 이 파일을 살펴보며 내용을 익혀두는 것이 좋습니다.

이름설명
custom지정된 팩토리를 호출하여 채널을 생성하는 드라이버입니다.
daily매일 로그 파일을 교체(rotate)하는 RotatingFileHandler 기반 Monolog 드라이버입니다.
monthly매월 로그 파일을 교체하는 RotatingFileHandler 기반 Monolog 드라이버입니다.
errorlogErrorLogHandler 기반 Monolog 드라이버입니다.
monolog지원되는 모든 Monolog 핸들러를 사용할 수 있는 Monolog 팩토리 드라이버입니다.
single단일 파일 또는 경로 기반 로거 채널입니다(StreamHandler).
slackSlackWebhookHandler 기반 Monolog 드라이버입니다.
stack"다중 채널" 채널을 쉽게 만들 수 있도록 도와주는 래퍼입니다.
syslogSyslogHandler 기반 Monolog 드라이버입니다.

NOTE

monolog 드라이버와 custom 드라이버에 대해 더 자세히 알고 싶다면 고급 채널 커스터마이징 문서를 참고하세요.

채널 이름 설정하기

Monolog는 기본적으로 production이나 local과 같이 현재 환경(environment)과 동일한 "채널 이름"으로 인스턴스화됩니다. 이 값을 변경하고 싶다면, 채널 설정에 name 옵션을 추가하면 됩니다.

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

채널 사전 준비 사항

Single, Daily, Monthly 채널 설정하기

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

이름설명기본값
bubble메시지가 처리된 후 다른 채널로도 전달(bubble up)되어야 하는지 여부를 나타냅니다.true
locking로그 파일에 기록하기 전에 파일 잠금(lock)을 시도할지 여부입니다.false
permission로그 파일의 권한입니다.0644

또한 daily와 monthly 채널의 로그 보관 정책은 max_files 설정 옵션을 통해 지정할 수 있습니다. daily 채널의 보관 기간은 LOG_DAILY_DAYS 환경 변수로도 설정할 수 있습니다.

Papertrail 채널 설정하기

papertrail 채널은 host와 port 설정 옵션이 필요합니다. 이 값들은 PAPERTRAIL_URL과 PAPERTRAIL_PORT 환경 변수를 통해 정의할 수 있습니다. 이 값들은 Papertrail 사이트에서 확인할 수 있습니다.

Slack 채널 설정하기

slack 채널은 url 설정 옵션이 필요합니다. 이 값은 LOG_SLACK_WEBHOOK_URL 환경 변수로 정의할 수 있습니다. 이 URL은 여러분의 Slack 팀에 설정한 수신 Webhook(incoming webhook) URL과 일치해야 합니다.

기본적으로 Slack은 critical 레벨 이상의 로그만 수신합니다. 하지만 LOG_LEVEL 환경 변수를 조정하거나 Slack 로그 채널 설정 배열 안의 level 옵션을 수정하여 이 기준을 변경할 수 있습니다.

Deprecation 경고 로깅

PHP, Laravel, 그리고 여러 라이브러리들은 종종 일부 기능이 더 이상 사용되지 않으며(deprecated) 향후 버전에서 제거될 예정임을 알립니다. 이러한 deprecation 경고를 로그로 남기고 싶다면, LOG_DEPRECATIONS_CHANNEL 환경 변수나 애플리케이션의 config/logging.php 설정 파일을 통해 원하는 deprecations 로그 채널을 지정할 수 있습니다.

'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 옵션을 통해 syslog와 slack, 두 개의 채널을 묶고 있습니다. 즉, 로그 메시지를 기록할 때 이 두 채널 모두 메시지를 기록할 기회를 얻게 됩니다. 다만 아래에서 살펴보겠지만, 각 채널이 실제로 메시지를 기록할지 여부는 메시지의 심각도("level")에 따라 결정됩니다.

로그 레벨

위 예시에서 syslog와 slack 채널 설정에 있는 level 옵션을 눈여겨보세요. 이 옵션은 해당 채널이 메시지를 기록하기 위해 메시지가 가져야 하는 최소 "레벨"을 결정합니다. Laravel의 로깅 서비스를 구동하는 Monolog는 RFC 5424 명세에 정의된 모든 로그 레벨을 제공합니다. 심각도가 높은 순서대로 나열하면 emergency, alert, critical, error, warning, notice, info, debug 순입니다.

예를 들어 debug 메서드로 메시지를 기록한다고 가정해 보겠습니다.

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

위 설정에서는 syslog 채널이 이 메시지를 시스템 로그에 기록합니다. 하지만 이 메시지는 critical 이상이 아니므로 Slack으로는 전송되지 않습니다. 반면 emergency 레벨로 메시지를 기록하면, 이 레벨은 두 채널 모두의 최소 임계값을 넘으므로 시스템 로그와 Slack 모두로 전송됩니다.

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

로그 메시지 작성하기

Log 파사드를 사용하면 로그 정보를 기록할 수 있습니다. 앞서 설명했듯이, 로거는 RFC 5424 명세에 정의된 8가지 로그 레벨 — emergency, alert, critical, error, warning, notice, info, debug — 를 제공합니다.

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('Showing the user profile for user: {id}', ['id' => $id]); return view('user.profile', [ 'user' => User::findOrFail($id) ]); } }

컨텍스트 정보

로그 메서드에는 컨텍스트 데이터 배열을 함께 전달할 수 있습니다. 이렇게 전달한 컨텍스트 데이터는 적절히 포맷되어 로그 메시지와 함께 표시됩니다.

use Illuminate\Support\Facades\Log; Log::info('User {id} failed to login.', ['id' => $user->id]);

경우에 따라 특정 채널에 이후 기록되는 모든 로그 항목에 공통으로 포함되어야 하는 컨텍스트 정보를 지정하고 싶을 수 있습니다. 예를 들어 들어오는 각 요청에 연결된 요청 ID를 로그에 함께 남기고 싶은 경우입니다. 이럴 때는 Log 파사드의 withContext 메서드를 사용하면 됩니다.

<?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('Something happened!');

여러 채널로 구성된 즉석(on-demand) 로그 스택을 만들고 싶다면, stack 메서드를 사용하면 됩니다.

Log::stack(['single', 'slack'])->info('Something happened!');

즉석(On-Demand) 채널

애플리케이션의 logging 설정 파일에 해당 설정이 존재하지 않더라도, 실행 시점에 설정을 직접 전달하여 즉석에서 채널을 생성할 수도 있습니다. 이를 위해서는 Log 파사드의 build 메서드에 설정 배열을 전달하면 됩니다.

use Illuminate\Support\Facades\Log; Log::build([ 'driver' => 'single', 'path' => storage_path('logs/custom.log'), ])->info('Something happened!');

또한 즉석 로그 스택 안에 즉석 채널을 포함시키고 싶을 수도 있습니다. 이 경우, stack 메서드에 전달하는 배열에 즉석 채널 인스턴스를 함께 포함시키면 됩니다.

use Illuminate\Support\Facades\Log; $channel = Log::build([ 'driver' => 'single', 'path' => storage_path('logs/custom.log'), ]); Log::stack(['slack', $channel])->info('Something happened!');

Monolog 채널 커스터마이징

채널의 Monolog 커스터마이징

때로는 기존 채널에서 Monolog가 어떻게 설정되는지에 대해 완전한 제어가 필요할 수 있습니다. 예를 들어 Laravel에 내장된 single 채널에 커스텀 Monolog FormatterInterface 구현체를 적용하고 싶은 경우입니다.

이를 위해서는 채널 설정에 tap 배열을 정의하면 됩니다. tap 배열에는 Monolog 인스턴스가 생성된 후 이를 커스터마이징("탭(tap)"하는)할 기회를 가지는 클래스들의 목록을 담습니다. 이러한 클래스를 어느 위치에 두어야 한다는 정해진 규칙은 없으므로, 애플리케이션 내에 원하는 디렉터리를 자유롭게 만들어 보관하면 됩니다.

'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 인스턴스로 그대로 전달(proxy)합니다.

<?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" 클래스는 서비스 컨테이너를 통해 해석(resolve)되므로, 생성자에 필요한 의존성이 있다면 자동으로 주입됩니다.

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 드라이버를 사용할 때는 기본적으로 Monolog의 LineFormatter가 기본 포매터로 사용됩니다. 하지만 formatter와 formatter_with 설정 옵션을 통해 핸들러에 전달되는 포매터 종류를 직접 지정할 수 있습니다.

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

사용 중인 Monolog 핸들러가 자체적으로 포매터를 제공할 수 있는 경우라면, formatter 설정 옵션 값을 default로 지정하면 됩니다.

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

Monolog 프로세서

Monolog는 메시지를 기록하기 전에 가공(process)할 수도 있습니다. 직접 프로세서를 만들거나, 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를 포함한 모든 로그 드라이버와 함께 작동하도록 설계되었습니다. 또한 Pail은 원하는 로그를 빠르게 찾을 수 있도록 유용한 필터 기능들도 제공합니다.

설치

WARNING

Laravel Pail은 PCNTL PHP 확장 모듈이 필요합니다.

시작하려면 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년 10월 3일