Vai al contenuto principale

Cos’è Context

La funzionalità Context di Laravel è un meccanismo per registrare e condividere informazioni attraverso l’esecuzione di richieste, job in coda e comandi. Le informazioni aggiunte tramite la facade Illuminate\Support\Facades\Context vengono aggiunte automaticamente a tutte le voci di log emesse dall’applicazione. Ti permette di distinguere chiaramente le informazioni passate a una singola chiamata di log da quelle condivise mantenute da Context. È particolarmente utile per tracciare sistemi distribuiti o architetture basate su code.

Flusso di propagazione del contesto

Uso di base

Il caso d’uso più tipico è impostare un trace_id in un middleware. Verrà incluso automaticamente in tutte le voci di log successive.
1

Crea il middleware

php artisan make:middleware AddContext
2

Aggiungi il trace ID a Context

<?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);
    }
}
3

Registra il middleware

Registralo come middleware globale in bootstrap/app.php.
->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\App\Http\Middleware\AddContext::class);
})
Dopo questa configurazione, i log scritti da controller e servizi conterranno automaticamente url e trace_id.
Log::info('User authenticated.', ['auth_id' => Auth::id()]);
User authenticated. {"auth_id":27} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

Scrittura nel Context

add — aggiungere un valore

use Illuminate\Support\Facades\Context;

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

// Aggiungi più valori insieme
Context::add([
    'first_key'  => 'value',
    'second_key' => 'value',
]);
add sovrascrive una chiave esistente. Per aggiungere solo se non esiste usa addIf.
Context::add('key', 'first');
Context::addIf('key', 'second');

Context::get('key');
// "first" — non sovrascritto

increment / decrement — gestione di contatori

Metodi dedicati per incrementare/decrementare valori numerici. Il secondo argomento indica la variazione.
Context::increment('records_added');
Context::increment('records_added', 5);

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

when — aggiunta condizionale

Con when puoi aggiungere dati diversi a seconda che la condizione sia true o 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', []),
);

push — aggiungere a uno stack

Context supporta uno “stack” per dati in forma di elenco. Con push i dati si accumulano nell’ordine in cui li aggiungi.
Context::push('breadcrumbs', 'first_value');
Context::push('breadcrumbs', 'second_value', 'third_value');

Context::get('breadcrumbs');
// ['first_value', 'second_value', 'third_value']
Esempio di storico di esecuzione query in uno stack.
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\DB;

// Nel metodo boot di AppServiceProvider.php
DB::listen(function ($event) {
    Context::push('queries', [$event->time, $event->sql]);
});

Lettura del Context

get / all

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

// Prendi tutto
$data = Context::all();

only / except — prendi solo alcune chiavi

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

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

pull / pop — leggere ed eliminare

pull legge il valore e lo elimina dal Context.
$value = Context::pull('key');
Per estrarre l’ultimo valore da uno stack usa pop.
Context::push('breadcrumbs', 'first_value', 'second_value');

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

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

remember — se non esiste, imposta e restituisci

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

has / missing — verifica dell’esistenza

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

if (Context::missing('key')) {
    // ...
}
has restituisce true anche se il valore è null. Verifica solo la presenza della chiave.

Rimozione dal Context

Con forget elimini una chiave.
Context::add(['first_key' => 1, 'second_key' => 2]);

Context::forget('first_key');

Context::all();
// ['second_key' => 2]

// Elimina più chiavi insieme
Context::forget(['first_key', 'second_key']);

Context con scope

Con scope puoi modificare temporaneamente il Context durante l’esecuzione di una closure e ripristinarlo automaticamente al termine. Utile in test o elaborazioni locali dove vuoi aggiungere informazioni temporanee ai log.
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("Adding user [{$userId}] to friends list.");
        // Adding user [987] to friends list.  {"trace_id":"abc-999","user_name":"taylor_otwell","action":"adding_friend"}
    },
    data: ['user_name' => 'taylor_otwell'],
    hidden: ['user_id' => 987],
);

// Terminato lo scope, i valori tornano quelli originali
Context::all();
// ['trace_id' => 'abc-999']

Context::allHidden();
// ['user_id' => 123]
Se modifichi un oggetto dentro lo scope, la modifica si riflette anche fuori. Se usi valori primitivi non c’è problema.

Hidden Context

Per dati che non vuoi far apparire nei log (password, chiavi API, dati personali) usa Hidden Context. Non sono leggibili con get: solo con metodi dedicati come getHidden.
use Illuminate\Support\Facades\Context;

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

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

Context::get('key');
// null — non è leggibile con il normale get
Hidden Context espone lo stesso set di metodi del Context normale.
Context::addHidden(/* ... */);
Context::addHiddenIf(/* ... */);
Context::pushHidden(/* ... */);
Context::getHidden(/* ... */);
Context::pullHidden(/* ... */);
Context::popHidden(/* ... */);
Context::onlyHidden(/* ... */);
Context::exceptHidden(/* ... */);
Context::allHidden(/* ... */);
Context::hasHidden(/* ... */);
Context::missingHidden(/* ... */);
Context::forgetHidden(/* ... */);

Trasferimento ai job in coda

Quando dispatchi un job nella coda, il Context corrente viene serializzato automaticamente nel payload del job. All’esecuzione del job il Context viene ripristinato, così il trace_id impostato nella richiesta viene ereditato anche nei log della coda.
// Impostato nel middleware
Context::add('trace_id', Str::uuid()->toString());

// Dispatch del job dal controller
ProcessPodcast::dispatch($podcast);
class ProcessPodcast implements ShouldQueue
{
    use Queueable;

    public function handle(): void
    {
        Log::info('Processing podcast.', ['podcast_id' => $this->podcast->id]);
    }
}
Processing podcast. {"podcast_id":95} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}
Il trace_id della richiesta compare anche nei log dei job.

Dehydrating — personalizzare l’invio del job

Con Context::dehydrating puoi trasformare il Context appena prima dell’invio del job. Ad esempio, quando vuoi passare in coda la locale determinata dall’header Accept-Language.
// AppServiceProvider.php

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'));
    });
}
Nella callback dehydrating non usare la facade Context: manipola solo il repository $context passato come argomento. L’uso della facade modificherebbe il Context del processo corrente.

Hydrated — ripristino all’esecuzione del job

Con Context::hydrated puoi eseguire logica quando il Context viene ripristinato prima dell’esecuzione del job. Ad esempio, applica al file di configurazione la locale salvata.
// AppServiceProvider.php

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'));
        }
    });
}
Anche nella callback hydrated non usare la facade Context: manipola solo il repository $context passato.
ContextLog::withContext
AmbitoTutti i canali di logSolo un canale specifico
Trasferimento ai jobAutomatico (Dehydrate/Hydrate)No
Dati HiddenSupportatiNo
UsoTracing, sistemi distribuitiMetadati specifici del canale
Hidden Context non compare nei log, quindi puoi memorizzare in sicurezza:
  • Session ID o user ID (se non vuoi che restino nei log)
  • Chiavi API e token di autenticazione
  • Locale o valori di configurazione (da ereditare in coda ma non necessari nei log)
  • Flag e stati interni
  1. Trasferimento della locale: in dehydrating salvi app.locale in Hidden Context; in hydrated la ripristini con Config::set.
  2. Propagazione dell’autenticazione: puoi far riferimento nel job alle informazioni dell’utente autenticato nella richiesta.
  3. Tenant ID: in app multi-tenant condividi l’identificatore di tenant attraverso la coda.
Ultima modifica il 13 luglio 2026