> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 로깅

> Laravel의 로깅 시스템을 사용해 애플리케이션의 동작을 파일·Slack·외부 서비스에 기록하는 방법을 배웁니다.

## 로깅이란

Laravel의 로깅은 **채널**이라는 개념을 축으로 설계되어 있습니다.
채널이란 로그의 쓰기 대상과 방법을 정의한 설정 단위로, 파일, Slack, syslog 등 다양한 출력 대상을 조합할 수 있습니다.

내부적으로 [Monolog](https://github.com/Seldaek/monolog) 라이브러리를 사용하고 있어 풍부한 핸들러와 포매터를 활용할 수 있습니다.

<Info>
  기본적으로 `stack` 채널이 사용됩니다. `stack`은 여러 채널을 통합해서 다루는 부모 채널입니다.
</Info>

## 설정

로깅 설정은 `config/logging.php`에 집중되어 있습니다. 환경 변수 `LOG_CHANNEL`로 기본 채널을 전환합니다.

```php theme={null}
// config/logging.php
'default' => env('LOG_CHANNEL', 'stack'),
```

### 이용 가능한 채널 드라이버

| 드라이버       | 설명                              |
| ---------- | ------------------------------- |
| `single`   | 하나의 파일에 모든 로그를 기록               |
| `daily`    | 날짜별로 파일을 나누어 기록(로테이션 포함)        |
| `slack`    | Slack의 Incoming Webhook로 메시지 전송 |
| `stack`    | 여러 채널을 통합하는 부모 채널               |
| `syslog`   | 시스템 syslog에 기록                  |
| `errorlog` | PHP 오류 로그에 기록                   |
| `monolog`  | Monolog의 핸들러를 직접 지정             |
| `custom`   | 팩토리 클래스로 채널을 완전히 커스터마이징         |

### 로그 레벨

Laravel은 [RFC 5424](https://tools.ietf.org/html/rfc5424)에 정의된 8단계 로그 레벨을 지원합니다.
심각도가 높은 순으로 나열되어 있습니다.

| 레벨          | 용도 예                               |
| ----------- | ---------------------------------- |
| `emergency` | 시스템 전체가 사용 불가. 즉시 대응 필요            |
| `alert`     | 즉시 사람이 대응해야 하는 상태(DB 접속 끊김 등)      |
| `critical`  | 앱의 주요 기능이 멈춘 중대한 장애                |
| `error`     | 런타임 오류. 대응이 필요하지만 즉시는 아닌 경우도 많다    |
| `warning`   | 잠재적 문제. 지원 중단 API 사용, 예기치 않은 데이터 등 |
| `notice`    | 정상 동작이지만 주목할 만한 정보                 |
| `info`      | 사용자 로그인이나 주문 확정 등 일반적인 조작 로그       |
| `debug`     | 개발 중의 상세 디버깅 정보                    |

채널의 `level` 설정은 **최저 로그 레벨**을 의미합니다.
예를 들어 `level`이 `error`라면 `error` 이상(`critical`, `alert`, `emergency`)만 기록됩니다.

## 기본 사용법

### Log 파사드

`Illuminate\Support\Facades\Log` 파사드를 사용해 각 레벨의 메시지를 기록합니다.

```php theme={null}
use Illuminate\Support\Facades\Log;

Log::emergency('시스템이 정지했습니다.');
Log::alert('데이터베이스 접속이 끊어졌습니다.');
Log::critical('결제 서비스가 응답하지 않습니다.');
Log::error('사용자 데이터 갱신에 실패했습니다.');
Log::warning('지원 중단된 메서드가 호출되었습니다.');
Log::notice('설정 파일이 재로드되었습니다.');
Log::info('사용자가 로그인했습니다.');
Log::debug('쿼리 실행 시간: 42ms');
```

컨트롤러에서의 사용 예시입니다.

```php theme={null}
<?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('사용자 프로필을 표시합니다.', ['user_id' => $id]);

        return view('user.profile', [
            'user' => User::findOrFail($id),
        ]);
    }
}
```

### log() 헬퍼 함수

`log()` 헬퍼를 사용하면 `Log` 파사드를 import하지 않고 작성할 수 있습니다.

```php theme={null}
log('헬퍼로부터의 로그입니다.');

// 레벨과 컨텍스트도 지정할 수 있습니다
log('사용자를 생성했습니다.', 'info', ['user_id' => $user->id]);
```

### 컨텍스트 정보 추가

메시지와 함께 컨텍스트(배열)를 전달하면 관련 정보를 함께 기록할 수 있습니다.

```php theme={null}
Log::info('로그인 실패.', [
    'user_id' => $user->id,
    'ip'      => $request->ip(),
    'reason'  => '비밀번호 불일치',
]);
```

#### withContext() — 채널 전체에 공통 컨텍스트 부여

특정 채널에 대해 이후 모든 로그 엔트리에 공통 정보를 부여하고 싶은 경우에는 `withContext()`를 사용합니다.
요청 ID처럼 모든 로그에 포함하고 싶은 정보에 적합합니다.

```php theme={null}
Log::withContext(['request-id' => (string) Str::uuid()]);

// 이후 모든 로그에 request-id가 자동으로 포함된다
Log::info('처리를 시작합니다.');
Log::error('오류가 발생했습니다.');
```

#### shareContext() — 모든 채널에 공통 컨텍스트 부여

`withContext()`는 대상 채널에만 효과가 한정되지만, `shareContext()`는 모든 채널에 공통 컨텍스트를 부여합니다.

```php theme={null}
Log::shareContext(['app-version' => config('app.version')]);
```

## 채널 설정

### stack 채널 — 여러 채널에 동시 기록

`stack` 채널을 사용하면 한 번의 로그 호출로 여러 채널에 기록할 수 있습니다.

```php theme={null}
// config/logging.php
'channels' => [
    'stack' => [
        'driver'   => 'stack',
        'channels' => ['daily', 'slack'],
    ],

    'daily' => [
        'driver' => 'daily',
        'path'   => storage_path('logs/laravel.log'),
        'level'  => env('LOG_LEVEL', 'debug'),
        'days'   => 14,
    ],

    'slack' => [
        'driver'   => 'slack',
        'url'      => env('LOG_SLACK_WEBHOOK_URL'),
        'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
        'emoji'    => env('LOG_SLACK_EMOJI', ':boom:'),
        'level'    => 'critical',
    ],
],
```

이 설정에서는 `debug` 이상의 모든 로그가 `daily`(파일)에 기록되고, `critical` 이상만 `slack`에도 전송됩니다.

<Tip>
  프로덕션 환경에서는 `slack` 채널의 레벨을 `error`나 `critical`로 설정하는 것을 권장합니다.
  경미한 로그까지 Slack으로 보내면 알림이 대량이 되어 중요한 알람이 파묻힙니다.
</Tip>

### daily 채널 — 로그 로테이션

`daily` 채널은 날짜별로 파일을 나누고 오래된 파일을 자동 삭제합니다.

```php theme={null}
'daily' => [
    'driver' => 'daily',
    'path'   => storage_path('logs/laravel.log'),
    'level'  => env('LOG_LEVEL', 'debug'),
    'days'   => env('LOG_DAILY_DAYS', 14), // 14일분 유지
],
```

<Warning>
  `days`를 작게 하면 오래된 로그가 빨리 삭제됩니다.
  프로덕션 환경의 장애 조사에 대비해 충분한 보존 기간을 확보해 주세요.
</Warning>

### Slack으로의 오류 알림

Slack의 [Incoming Webhook URL](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks)을 획득하고, `.env`에 설정합니다.

```ini theme={null}
LOG_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
```

```php theme={null}
// config/logging.php
'slack' => [
    'driver'   => 'slack',
    'url'      => env('LOG_SLACK_WEBHOOK_URL'),
    'username' => 'Laravel Error Bot',
    'emoji'    => ':fire:',
    'level'    => 'error',
],
```

`stack` 채널에 `slack`을 포함시키고 `LOG_CHANNEL=stack`을 설정하면 오류 발생 시 자동으로 알림이 갑니다.

### 특정 채널에 로그 기록

`Log::channel()`로 대상 채널을 명시적으로 지정할 수 있습니다.

```php theme={null}
// slack 채널에만 기록
Log::channel('slack')->error('결제 서비스가 응답하지 않습니다.');

// 여러 채널에 동시 기록
Log::stack(['daily', 'slack'])->critical('데이터베이스 접속에 실패했습니다.');
```

## 온디맨드 채널

`Log::build()`를 사용하면 설정 파일에 정의하지 않고 즉석에서 커스텀 채널을 만들 수 있습니다.
테스트나 일시적인 출력 대상으로의 기록에 편리합니다.

```php theme={null}
use Illuminate\Support\Facades\Log;

$channel = Log::build([
    'driver' => 'single',
    'path'   => storage_path('logs/import-' . now()->format('Ymd') . '.log'),
]);

Log::stack([$channel])->info('CSV 임포트를 시작합니다.');
```

## 실전 유스케이스

### 미들웨어에서 요청 ID 부여하기

모든 로그에 공통 요청 ID를 부여하면 로그에서 특정 요청의 흐름을 추적하기 쉬워집니다.

<Steps>
  <Step title="미들웨어를 생성한다">
    ```shell theme={null}
    php artisan make:middleware AssignRequestId
    ```
  </Step>

  <Step title="handle() 메서드를 구현한다">
    ```php theme={null}
    <?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
    {
        public function handle(Request $request, Closure $next): Response
        {
            $requestId = (string) Str::uuid();

            Log::withContext(['request-id' => $requestId]);

            $response = $next($request);

            $response->headers->set('X-Request-Id', $requestId);

            return $response;
        }
    }
    ```
  </Step>

  <Step title="미들웨어를 등록한다">
    `bootstrap/app.php`에서 글로벌 미들웨어로 등록합니다.

    ```php theme={null}
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(\App\Http\Middleware\AssignRequestId::class);
    })
    ```
  </Step>
</Steps>

이 설정 후 모든 로그에 `request-id`가 자동으로 부여됩니다.

```
[2026-03-01 12:00:00] local.INFO: 사용자가 로그인했습니다. {"request-id":"550e8400-...","user_id":1}
[2026-03-01 12:00:00] local.INFO: 대시보드를 표시합니다. {"request-id":"550e8400-..."}
```

### 지원 중단 경고의 로그 기록

PHP나 Laravel의 지원 중단 기능을 사용했을 때의 경고를 로그에 남길 수 있습니다.

```php theme={null}
// config/logging.php
'deprecations' => [
    'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
    'trace'   => env('LOG_DEPRECATIONS_TRACE', false),
],
```

`.env`에서 채널을 지정합니다.

```ini theme={null}
LOG_DEPRECATIONS_CHANNEL=daily
```

## Laravel Pail — 실시간 로그 감시

[Laravel Pail](https://github.com/laravel/pail)은 터미널에서 애플리케이션의 로그를 실시간으로 확인할 수 있는 개발 도구입니다.

<Info>
  Pail의 실행에는 PHP의 [PCNTL](https://www.php.net/manual/ja/book.pcntl.php) 확장이 필요합니다.
</Info>

### 설치

```shell theme={null}
composer require --dev laravel/pail
```

### 기본 사용법

```shell theme={null}
# 로그를 흘려보며 확인한다
php artisan pail

# 상세 표시(생략 없음)
php artisan pail -v

# 스택 트레이스도 표시
php artisan pail -vv
```

### 로그 필터링

```shell theme={null}
# 키워드로 좁히기
php artisan pail --filter="QueryException"

# 메시지만으로 좁히기
php artisan pail --message="로그인"

# 로그 레벨로 좁히기
php artisan pail --level=error

# 특정 사용자의 로그만 표시
php artisan pail --user=1
```

## 정리

<AccordionGroup>
  <Accordion title="로그 레벨 선택 방법">
    | 레벨          | 사용 타이밍                             |
    | ----------- | ---------------------------------- |
    | `emergency` | 시스템 전체가 정지할 정도의 치명적인 장애            |
    | `alert`     | 즉시 사람이 개입해야 하는 상태                  |
    | `critical`  | 주요 기능이 동작하지 않는 중대한 장애              |
    | `error`     | 예기치 않은 런타임 오류. 대응이 필요              |
    | `warning`   | 지원 중단된 사용이나 예기치 않은 데이터 등 주의해야 할 상태 |
    | `notice`    | 정상이지만 기록해 두고 싶은 중요한 조작             |
    | `info`      | 사용자 조작이나 비즈니스 이벤트 기록               |
    | `debug`     | 개발 중의 상세 디버깅 정보(프로덕션에서는 불필요)       |
  </Accordion>

  <Accordion title="채널 선택 가이드">
    * **개발 환경**: `single`이나 `daily`로 파일에 기록
    * **프로덕션 환경**: `stack`으로 `daily`(파일 저장)와 `slack`(오류 알림)을 조합
    * **특정 처리의 로그**: `Log::build()`로 온디맨드 채널을 생성해 독립된 파일에 기록
    * **실시간 감시**: `php artisan pail`로 터미널에서 확인
  </Accordion>

  <Accordion title="프로덕션 환경에서의 주의점">
    * `debug` 로그에는 기밀 정보가 포함되는 경우가 있습니다. 프로덕션 환경에서는 `LOG_LEVEL=error` 이상을 권장합니다.
    * 로그 파일은 정기적으로 로테이션해서 디스크를 압박하지 않도록 해 주세요(`daily` 채널의 `days` 설정).
    * Slack 같은 외부 서비스로의 알림은 레이트 리밋에 주의해 주세요. 중대한 오류만 알리도록 레벨을 설정해 주세요.
  </Accordion>
</AccordionGroup>


## Related topics

- [Laravel Pulse](/ko/pulse.md)
- [Laravel 9에서 10으로의 업그레이드](/ko/blog/upgrade-9-to-10.md)
- [요청 라이프사이클](/ko/lifecycle.md)
