본문 바로가기

컨텍스트

업데이트됨

번역일: 2026년 7월 28일

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

원문 수정
2026년 7월 28일
번역 갱신
2026년 7월 28일

컨텍스트

소개

Laravel의 컨텍스트(Context) 기능을 사용하면 요청, Job, 커맨드 실행 전반에 걸쳐 정보를 저장하고, 조회하고, 공유할 수 있습니다. 저장된 정보는 애플리케이션이 기록하는 로그에도 자동으로 포함되므로, 특정 로그 항목이 기록되기 전까지 어떤 흐름으로 코드가 실행되었는지 파악하기 쉬워지고, 분산 시스템 전반의 실행 흐름을 추적하는 데 큰 도움이 됩니다.

동작 원리

컨텍스트 기능을 이해하는 가장 빠른 방법은 내장 로깅 기능과 함께 직접 사용해 보는 것입니다. Context 파사드를 이용해 컨텍스트에 정보를 추가할 수 있습니다. 아래 예시에서는 미들웨어를 사용해 모든 요청마다 요청 URL과 고유한 트레이스 ID를 컨텍스트에 추가합니다.

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Context; use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Response; class AddContext { /** * 요청을 처리합니다. */ public function handle(Request $request, Closure $next): Response { Context::add('url', $request->url()); Context::add('trace_id', Str::uuid()->toString()); return $next($request); } }

컨텍스트에 추가된 정보는 요청 처리 중 기록되는 모든 로그 항목에 메타데이터로 자동 첨부됩니다. 메타데이터로 첨부하면, 개별 로그 항목에 직접 전달된 정보와 Context를 통해 공유된 정보를 구분할 수 있습니다. 예를 들어 아래와 같이 로그를 기록한다면:

Log::info('사용자 인증 완료.', ['auth_id' => Auth::id()]);

실제로 기록되는 로그에는 직접 전달한 auth_id뿐 아니라, 컨텍스트에 저장된 urltrace_id도 메타데이터로 함께 포함됩니다.

사용자 인증 완료. {"auth_id":27} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

컨텍스트에 저장된 정보는 큐에 디스패치되는 Job에도 전달됩니다. 예를 들어 컨텍스트에 정보를 추가한 뒤 ProcessPodcast Job을 큐에 디스패치한다고 해봅시다.

// 미들웨어에서... Context::add('url', $request->url()); Context::add('trace_id', Str::uuid()->toString()); // 컨트롤러에서... ProcessPodcast::dispatch($podcast);

Job이 디스패치될 때 현재 컨텍스트에 저장된 모든 정보가 캡처되어 Job 페이로드와 함께 전달됩니다. Job이 실행될 때는 이 정보가 다시 현재 컨텍스트로 복원(hydrate)됩니다. 따라서 Job의 handle 메서드에서 로그를 기록하면:

class ProcessPodcast implements ShouldQueue { use Queueable; // ... /** * Job을 실행합니다. */ public function handle(): void { Log::info('팟캐스트 처리 중.', [ 'podcast_id' => $this->podcast->id, ]); // ... } }

원래 요청에서 컨텍스트에 추가했던 정보가 Job의 로그에도 그대로 나타납니다.

팟캐스트 처리 중. {"podcast_id":95} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

이 문서에서는 로깅과의 연동 외에도, HTTP 요청과 큐 Job 사이에서 정보를 공유하는 방법, 그리고 로그에 기록되지 않는 숨겨진 컨텍스트 데이터를 활용하는 방법을 설명합니다.

컨텍스트 저장

Context 파사드의 add 메서드로 현재 컨텍스트에 정보를 저장할 수 있습니다.

use Illuminate\Support\Facades\Context; Context::add('key', 'value');

여러 항목을 한 번에 추가하려면 연관 배열을 전달하면 됩니다.

Context::add([ 'first_key' => 'value', 'second_key' => 'value', ]);

add 메서드는 동일한 키가 이미 존재하면 해당 값을 덮어씁니다. 키가 존재하지 않을 때만 추가하고 싶다면 addIf 메서드를 사용하세요.

Context::add('key', 'first'); Context::get('key'); // "first" Context::addIf('key', 'second'); Context::get('key'); // "first"

특정 키의 값을 증가 또는 감소시키는 편의 메서드도 제공됩니다. 첫 번째 인수로 키를 지정하며, 두 번째 인수로 증감할 양을 지정할 수 있습니다.

Context::increment('records_added'); Context::increment('records_added', 5); Context::decrement('records_added'); Context::decrement('records_added', 5);

조건부 컨텍스트 저장

when 메서드를 사용하면 조건에 따라 컨텍스트에 데이터를 추가할 수 있습니다. 조건이 true이면 첫 번째 클로저가, false이면 두 번째 클로저가 실행됩니다.

use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Context; Context::when( Auth::user()->isAdmin(), fn ($context) => $context->add('permissions', Auth::user()->permissions), fn ($context) => $context->add('permissions', []), );

스코프 컨텍스트

scope 메서드를 사용하면 특정 클로저 실행 동안만 컨텍스트를 임시로 변경하고, 클로저가 완료되면 원래 상태로 자동 복원할 수 있습니다. 두 번째와 세 번째 인수로 클로저 실행 중에만 병합할 추가 데이터를 전달할 수도 있습니다.

use Illuminate\Support\Facades\Context; use Illuminate\Support\Facades\Log; Context::add('trace_id', 'abc-999'); Context::addHidden('user_id', 123); Context::scope( function () { Context::add('action', 'adding_friend'); $userId = Context::getHidden('user_id'); Log::debug("사용자 [{$userId}]를 친구 목록에 추가하는 중."); // 사용자 [987]를 친구 목록에 추가하는 중. {"trace_id":"abc-999","user_name":"taylor_otwell","action":"adding_friend"} }, data: ['user_name' => 'taylor_otwell'], hidden: ['user_id' => 987], ); Context::all(); // [ // 'trace_id' => 'abc-999', // ] Context::allHidden(); // [ // 'user_id' => 123, // ]

WARNING

스코프 클로저 내부에서 컨텍스트에 저장된 객체를 직접 변경(mutate)하면, 그 변경 사항은 스코프 밖에서도 반영됩니다.

스택

컨텍스트는 데이터를 추가된 순서대로 저장하는 "스택"을 지원합니다. push 메서드로 스택에 값을 추가할 수 있습니다.

use Illuminate\Support\Facades\Context; Context::push('breadcrumbs', 'first_value'); Context::push('breadcrumbs', 'second_value', 'third_value'); Context::get('breadcrumbs'); // [ // 'first_value', // 'second_value', // 'third_value', // ]

스택은 요청 처리 중 발생한 이벤트를 시간 순서대로 기록할 때 유용합니다. 예를 들어 DB 쿼리가 실행될 때마다 SQL과 소요 시간을 스택에 쌓을 수 있습니다.

use Illuminate\Support\Facades\Context; use Illuminate\Support\Facades\DB; // AppServiceProvider.php에서... DB::listen(function ($event) { Context::push('queries', [$event->time, $event->sql]); });

stackContainshiddenStackContains 메서드로 특정 값이 스택에 존재하는지 확인할 수 있습니다.

if (Context::stackContains('breadcrumbs', 'first_value')) { // } if (Context::hiddenStackContains('secrets', 'first_value')) { // }

두 번째 인수로 클로저를 전달하면 더 세밀한 비교 로직을 구현할 수 있습니다.

use Illuminate\Support\Facades\Context; use Illuminate\Support\Str; return Context::stackContains('breadcrumbs', function ($value) { return Str::startsWith($value, 'query_'); });

컨텍스트 조회

Context 파사드의 get 메서드로 컨텍스트에서 값을 가져올 수 있습니다.

use Illuminate\Support\Facades\Context; $value = Context::get('key');

onlyexcept 메서드를 사용하면 컨텍스트의 일부 항목만 선택적으로 가져올 수 있습니다.

$data = Context::only(['first_key', 'second_key']); $data = Context::except(['first_key']);

pull 메서드는 값을 가져오는 동시에 컨텍스트에서 해당 항목을 제거합니다.

$value = Context::pull('key');

스택에 저장된 데이터는 pop 메서드로 마지막 항목부터 꺼낼 수 있습니다.

Context::push('breadcrumbs', 'first_value', 'second_value'); Context::pop('breadcrumbs'); // second_value Context::get('breadcrumbs'); // ['first_value']

rememberrememberHidden 메서드는 키에 해당하는 값이 없을 경우 클로저의 반환값을 컨텍스트에 저장하고 반환합니다. 값이 이미 있으면 그 값을 그대로 반환합니다.

$permissions = Context::remember( 'user-permissions', fn () => $user->permissions, );

컨텍스트에 저장된 모든 정보를 가져오려면 all 메서드를 사용하세요.

$data = Context::all();

키 존재 여부 확인

hasmissing 메서드로 특정 키에 값이 저장되어 있는지 확인할 수 있습니다.

use Illuminate\Support\Facades\Context; if (Context::has('key')) { // ... } if (Context::missing('key')) { // ... }

has 메서드는 저장된 값이 null이더라도 키가 존재하면 true를 반환합니다.

Context::add('key', null); Context::has('key'); // true

컨텍스트 삭제

forget 메서드로 특정 키와 그 값을 현재 컨텍스트에서 제거할 수 있습니다.

use Illuminate\Support\Facades\Context; Context::add(['first_key' => 1, 'second_key' => 2]); Context::forget('first_key'); Context::all(); // ['second_key' => 2]

배열을 전달하면 여러 키를 한 번에 삭제할 수 있습니다.

Context::forget(['first_key', 'second_key']);

숨겨진 컨텍스트

컨텍스트는 "숨겨진(hidden)" 데이터를 별도로 저장하는 기능을 제공합니다. 숨겨진 정보는 로그에 첨부되지 않으며, 앞서 설명한 일반 조회 메서드로는 접근할 수 없습니다. 숨겨진 컨텍스트를 다루기 위한 전용 메서드가 별도로 제공됩니다.

use Illuminate\Support\Facades\Context; Context::addHidden('key', 'value'); Context::getHidden('key'); // 'value' Context::get('key'); // null

숨겨진 컨텍스트 메서드는 일반 메서드와 동일한 방식으로 동작하며, 아래와 같이 대응됩니다.

Context::addHidden(/* ... */); Context::addHiddenIf(/* ... */); Context::pushHidden(/* ... */); Context::getHidden(/* ... */); Context::pullHidden(/* ... */); Context::popHidden(/* ... */); Context::onlyHidden(/* ... */); Context::exceptHidden(/* ... */); Context::allHidden(/* ... */); Context::hasHidden(/* ... */); Context::missingHidden(/* ... */); Context::forgetHidden(/* ... */);

이벤트

컨텍스트는 hydration 및 dehydration 과정에 훅(hook)을 걸 수 있는 두 가지 이벤트를 제공합니다.

이 이벤트가 필요한 상황을 예로 들어보겠습니다. 미들웨어에서 HTTP 요청의 Accept-Language 헤더를 기반으로 app.locale 설정값을 변경한다고 가정합니다. 요청 처리 중에는 이 값이 올바르게 설정되지만, 이후 큐 Job이 실행될 때는 해당 로케일 설정이 유지되지 않습니다. 컨텍스트 이벤트와 숨겨진 컨텍스트를 함께 활용하면 이 문제를 해결할 수 있습니다. 아래에서 그 방법을 설명합니다.

Dehydrating

Job이 큐에 디스패치될 때 컨텍스트 데이터는 "dehydrate(탈수)"되어 Job 페이로드와 함께 저장됩니다. Context::dehydrating 메서드로 이 과정에서 실행될 클로저를 등록할 수 있습니다. 클로저 내부에서는 큐 Job과 공유될 데이터를 수정할 수 있습니다.

일반적으로 dehydrating 콜백은 애플리케이션의 AppServiceProvider 클래스의 boot 메서드 안에서 등록합니다.

use Illuminate\Log\Context\Repository; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Context; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Context::dehydrating(function (Repository $context) { $context->addHidden('locale', Config::get('app.locale')); }); }

NOTE

dehydrating 콜백 내부에서는 Context 파사드를 직접 사용하지 마세요. 파사드를 사용하면 현재 프로세스의 컨텍스트가 변경됩니다. 반드시 콜백에 전달된 $context 리포지터리 인스턴스만 사용하세요.

Hydrated

큐에서 Job이 실행되기 시작할 때 Job과 함께 전달된 컨텍스트 데이터가 현재 컨텍스트로 "hydrate(수화)"됩니다. Context::hydrated 메서드로 이 과정에서 실행될 클로저를 등록할 수 있습니다.

마찬가지로 hydrated 콜백도 AppServiceProviderboot 메서드에서 등록하는 것이 일반적입니다.

use Illuminate\Log\Context\Repository; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Context; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Context::hydrated(function (Repository $context) { if ($context->hasHidden('locale')) { Config::set('app.locale', $context->getHidden('locale')); } }); }

NOTE

hydrated 콜백 내부에서도 Context 파사드를 직접 사용하지 말고, 콜백에 전달된 $context 리포지터리 인스턴스만을 통해 변경하세요.

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

번역일: 2026년 7월 28일