Readouble

Laravel 11.x コンテキスト

イントロダクションIntroduction

Laravelの「コンテキスト」機能により、アプリケーション内で実行されているリクエスト、ジョブ、コマンド実行に渡る情報をキャプチャ、取得、共有ができます。このキャプチャした情報は、アプリケーションが書き込むログにも含まれ、ログエントリが書き込まれる前に発生していた周辺のコード実行履歴をより深く理解することができ、分散システム全体の実行フローをトレースできるようにします。Laravel's "context" capabilities enable you to capture, retrieve, and share information throughout requests, jobs, and commands executing within your application. This captured information is also included in logs written by your application, giving you deeper insight into the surrounding code execution history that occurred before a log entry was written and allowing you to trace execution flows throughout a distributed system.

動作の仕組みHow it Works

Laravelのコンテキスト機能を理解する最良の方法は、組み込まれているログ機能を使い、実際に見てみることです。開始するには、Contextファサードを使い、コンテキストへ情報を追加してください。この例では、ミドルウェアを使い、リクエストURLと一意なトレースIDを受信リクエストごとにコンテキストへ追加してみます。The best way to understand Laravel's context capabilities is to see it in action using the built-in logging features. To get started, you may add information to the context[#capturing-context] using the Context facade. In this example, we will use a middleware[/docs/{{version}}/middleware] to add the request URL and a unique trace ID to the context on every incoming request:

<?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を介して共有する情報を区別できるようになります。例えば、次のようなログエントリを書くとします。Information added to the context is automatically appended as metadata to any log entries[/docs/{{version}}/logging] that are written throughout the request. Appending context as metadata allows information passed to individual log entries to be differentiated from the information shared via Context. For example, imagine we write the following log entry:

Log::info('User authenticated.', ['auth_id' => Auth::id()]);

書き出すログは、ログエントリに渡したauth_idを含みますが、メタデータとしてコンテキストのurltrace_idもふくんでいます。The written log will contain the auth_id passed to the log entry, but it will also contain the context's url and trace_id as metadata:

User authenticated. {"auth_id":27} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

コンテキストへ追加する情報は、キュー投入するジョブでも利用できるようになります。例えば、ProcessPodcastジョブをコンテキストへ情報を追加した後で、キュー投入するとしましょう。Information added to the context is also made available to jobs dispatched to the queue. For example, imagine we dispatch a ProcessPodcast job to the queue after adding some information to the context:

// ミドルウェア中
Context::add('url', $request->url());
Context::add('trace_id', Str::uuid()->toString());

// コントローラ中
ProcessPodcast::dispatch($podcast);

ジョブを投入すると、コンテキストに現在格納しているすべての情報をキャプチャし、ジョブと共有します。取り込こんだ情報は、ジョブの実行中に現在のコンテキストへ戻します。では、ジョブの処理メソッドがログへの書き込みであったとしましょう。When the job is dispatched, any information currently stored in the context is captured and shared with the job. The captured information is then hydrated back into the current context while the job is executing. So, if our job's handle method was to write to the log:

class ProcessPodcast implements ShouldQueue
{
    use Queueable;

    // ...

    /**
     * ジョブの実行
     */
    public function handle(): void
    {
        Log::info('Processing podcast.', [
            'podcast_id' => $this->podcast->id,
        ]);

        // ...
    }
}

結果のログエントリは、ジョブ投入元のリクエストの間に、コンテキストへ追加した情報を含みます。The resulting log entry would contain the information that was added to the context during the request that originally dispatched the job:

Processing podcast. {"podcast_id":95} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

Laravelのコンテキストの機能と関連して、組み込みログへ焦点を当てましたが、以下のドキュメントでは、コンテキストによってHTTPリクエスト/キュー投入ジョブの境界を越えて情報を共有する方法や、ログエントリーと一緒に書き込まない隠しコンテキストデータを追加する方法まで説明します。Although we have focused on the built-in logging related features of Laravel's context, the following documentation will illustrate how context allows you to share information across the HTTP request / queued job boundary and even how to add hidden context data[#hidden-context] that is not written with log entries.

コンテキストのチャプタCapturing Context

Contextファサードのaddメソッドを使用して、現在のコンテキストへ情報を格納できます。You may store information in the current context using the Context facade's add method:

use Illuminate\Support\Facades\Context;

Context::add('key', 'value');

一度に複数のアイテムを追加するには、addメソッドに連想配列を渡してください。To add multiple items at once, you may pass an associative array to the add method:

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

addメソッドは、同じキーを持つ既存の値を上書きします。そのキーがまだ存在しない場合にのみコンテキストへ情報を追加したい場合は、addIfメソッドを使用してください。The add method will override any existing value that shares the same key. If you only wish to add information to the context if the key does not already exist, you may use the addIf method:

Context::add('key', 'first');

Context::get('key');
// "first"

Context::addIf('key', 'second');

Context::get('key');
// "first"

条件付きコンテキストConditional Context

whenメソッドは、指定する条件に基づき、コンテキストへデータを追加するために使用します。指定条件をtrueと評価した場合、whenメソッドに渡す最初のクロージャを呼び出し、falseと評価した場合は、2番目のクロージャを呼び出します。The when method may be used to add data to the context based on a given condition. The first closure provided to the when method will be invoked if the given condition evaluates to true, while the second closure will be invoked if the condition evaluates to 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', []),
);

スタックStacks

Contextには「スタック」を作成する機能があります。「スタック」は追加した順番で保存したデータのリストです。スタックへ情報を追加するには、pushメソッドを呼び出します。Context offers the ability to create "stacks", which are lists of data stored in the order that they were added. You can add information to a stack by invoking the push method:

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',
// ]

スタックは、アプリケーション全体で起きているイベントのような、リクエストに関する履歴情報を取得するのに便利です。たとえば、イベントリスナを作成して、クエリが実行されるたびにスタックへプッシュし、クエリSQLと期間をタプルとして取得できます。Stacks can be useful to capture historical information about a request, such as events that are happening throughout your application. For example, you could create an event listener to push to a stack every time a query is executed, capturing the query SQL and duration as a tuple:

use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\DB;

DB::listen(function ($event) {
    Context::push('queries', [$event->time, $event->sql]);
});

スタックに値があるかは、stackContainshiddenStackContainsメソッドで調べられる。You may determine if a value is in a stack using the stackContains and hiddenStackContains methods:

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

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

stackContainshiddenStackContainsメソッドは、第2引数へクロージャも受け付ける。The stackContains and hiddenStackContains methods also accept a closure as their second argument, allowing more control over the value comparison operation:

use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;

return Context::stackContains('breadcrumbs', function ($value) {
    return Str::startsWith($value, 'query_');
});

コンテキストの取得Retrieving Context

コンテキストから情報を取得するには、Contextファサードのgetメソッドを使用します。You may retrieve information from the context using the Context facade's get method:

use Illuminate\Support\Facades\Context;

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

onlyメソッドは、コンテキスト内の情報のサブセットを取得するために使用します。The only method may be used to retrieve a subset of the information in the context:

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

pullメソッドは、コンテキストから情報を取得し、すぐにコンテキストから削除するために使用します。The pull method may be used to retrieve information from the context and immediately remove it from the context:

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

コンテキストデータが、スタックに格納されている場合、popメソッドを使ってスタックから項目をポップできます.If context data is stored in a stack[#stacks], you may pop items from the stack using the pop method:

Context::push('breadcrumbs', 'first_value', 'second_value');

Context::pop('breadcrumbs')
// second_value

Context::get('breadcrumbs');
// ['first_value']

コンテキストが格納しているすべての情報を取得したい場合は、all メソッドを呼び出します。If you would like to retrieve all of the information stored in the context, you may invoke the all method:

$data = Context::all();

アイテムの存在判定Determining Item Existence

指定するキーに対応する値をコンテキストに格納しているかを調べるには、hasメソッドを使用します。You may use the has method to determine if the context has any value stored for the given key:

use Illuminate\Support\Facades\Context;

if (Context::has('key')) {
    // ...
}

hasメソッドは、格納している値に関係なく存在しているならtrueを返します。そのため、例えばnull値を持つキーでも存在しているとみなします。The has method will return true regardless of the value stored. So, for example, a key with a null value will be considered present:

Context::add('key', null);

Context::has('key');
// true

コンテキストの削除Removing Context

forgetメソッドを使うと、現在のコンテキストからキーとその値を削除できます。The forget method may be used to remove a key and its value from the current context:

use Illuminate\Support\Facades\Context;

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

Context::forget('first_key');

Context::all();

// ['second_key' => 2]

forgetメソッドに配列を指定すれば、複数のキーを一度に削除できます。You may forget several keys at once by providing an array to the forget method:

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

隠しコンテキストHidden Context

コンテキストは「隠し」データを保存する機能を提供しています。この隠し情報はログに追加せず、上記で説明したデータ検索方法ではアクセスできません。コンテキストは、隠しコンテキスト情報を操作するために別のメソッドを提供しています。Context offers the ability to store "hidden" data. This hidden information is not appended to logs, and is not accessible via the data retrieval methods documented above. Context provides a different set of methods to interact with hidden context information:

use Illuminate\Support\Facades\Context;

Context::addHidden('key', 'value');

Context::getHidden('key');
// 'value'

Context::get('key');
// null

"hidden"メソッドは、前述の非隠しメソッドの機能を反映したものです。The "hidden" methods mirror the functionality of the non-hidden methods documented above:

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

イベントEvents

コンテキストは、コンテキストの合成と分離プロセスをフックできる、2つのイベントをディスパッチします。Context dispatches two events that allow you to hook into the hydration and dehydration process of the context.

これらのイベントがどのように使うかを説明するため、アプリケーションのミドルウェアで、HTTPリクエストのAccept-Languageヘッダに基づいて、app.locale設定値を設定する事を考えてみましょう。コンテキストのイベントにより、リクエスト中にこの値を取得し、キューへリストアすることができ、キューに送信する通知が正しいapp.locale値を持つようにできます。これを実現するには、コンテキストのイベントと 隠しデータが使えます。To illustrate how these events may be used, imagine that in a middleware of your application you set the app.locale configuration value based on the incoming HTTP request's Accept-Language header. Context's events allow you to capture this value during the request and restore it on the queue, ensuring notifications sent on the queue have the correct app.locale value. We can use context's events and hidden[#hidden-context] data to achieve this, which the following documentation will illustrate.

分離Dehydrating

ジョブをキューへディスパッチするたびに、コンテキストのデータは「分離(dehtdrated)」され、ジョブのペイロードと一緒に取り込まれます。Context::dehydratingメソッドでは、分離処理中に呼び出すクロージャを登録できます。このクロージャの中で、キュー投入したジョブと共有するデータへ変更を加えることができます。Whenever a job is dispatched to the queue the data in the context is "dehydrated" and captured alongside the job's payload. The Context::dehydrating method allows you to register a closure that will be invoked during the dehydration process. Within this closure, you may make changes to the data that will be shared with the queued job.

通常、アプリケーションのAppServiceProviderクラスのbootメソッド内で、dehydrating コールバックを登録すべきでしょう。Typically, you should register dehydrating callbacks within the boot method of your application's AppServiceProvider class:

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'));
    });
}

lightbulb Note: dehydratingコールバック内で、Contextファサードを使用してはいけません。コールバックへ渡されたリポジトリにのみ、変更を加えるようにしてください。[!NOTE]
You should not use the Context facade within the dehydrating callback, as that will change the context of the current process. Ensure you only make changes to the repository passed to the callback.

合成Hydrated

キュー投入したジョブがキュー上で実行を開始するたび、そのジョブで共有されていたコンテキストは、現在のコンテキストへ「合成(hydrated)」します。Context::hydratedメソッドを使用すると、合成のプロセスで呼び出すクロージャを登録できます。Whenever a queued job begins executing on the queue, any context that was shared with the job will be "hydrated" back into the current context. The Context::hydrated method allows you to register a closure that will be invoked during the hydration process.

通常、アプリケーションのAppServiceProviderクラスのbootメソッド内で、hydratedコールバックを登録する必要があります。Typically, you should register hydrated callbacks within the boot method of your application's AppServiceProvider class:

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'));
        }
    });
}

lightbulb Note: Hydratedコールバック内ではContextファサードを使用せず、代わりにコールバックへ渡すリポジトリにのみ変更を加えてください。[!NOTE]
You should not use the Context facade within the hydrated callback and instead ensure you only make changes to the repository passed to the callback.

章選択

設定

明暗テーマ
light_mode
dark_mode
brightness_auto システム設定に合わせる
テーマ選択
photo_size_select_actual デフォルト
photo_size_select_actual モノクローム(白黒)
photo_size_select_actual Solarized風
photo_size_select_actual GitHub風(青ベース)
photo_size_select_actual Viva(黄緑ベース)
photo_size_select_actual Happy(紫ベース)
photo_size_select_actual Mint(緑ベース)
コードハイライトテーマ選択

明暗テーマごとに、コードハイライトのテーマを指定できます。

テーマ配色確認
スクリーン表示幅
640px
80%
90%
100%

768px以上の幅があるときのドキュメント部分表示幅です。

インデント
無し
1rem
2rem
3rem
原文確認
原文を全行表示
原文を一行ずつ表示
使用しない

※ 段落末のEボタンへカーソルオンで原文をPopupします。

Diff表示形式
色分けのみで区別
行頭の±で区別
削除線と追記で区別

※ [tl!…]形式の挿入削除行の表示形式です。

テストコード表示
両コード表示
Pestのみ表示
PHPUnitのみ表示
OS表示
全OS表示
macOSのみ表示
windowsのみ表示
linuxのみ表示
和文変換

対象文字列と置換文字列を半角スペースで区切ってください。(最大5組各10文字まで)

本文フォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

コードフォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

保存内容リセット

localStrageに保存してある設定項目をすべて削除し、デフォルト状態へ戻します。

ヘッダー項目移動

キーボード操作