Saltar al contenido principal

¿Qué es Context?

La funcionalidad Context de Laravel es un mecanismo para registrar y compartir información a través de solicitudes, jobs de cola y ejecuciones de comandos. Al añadir información mediante la fachada Illuminate\Support\Facades\Context, esa información se agrega automáticamente a todas las entradas de log que la aplicación escribe. Así puedes distinguir claramente la información pasada en cada llamada de log de la información compartida que mantiene Context. Es especialmente útil para hacer tracing en sistemas distribuidos o arquitecturas con colas.

Flujo de propagación del contexto

Uso básico

El caso más habitual es fijar un trace_id en un middleware. Se incluirá automáticamente en todas las entradas de log posteriores.
1

Crear el middleware

php artisan make:middleware AddContext
2

Añadir el trace ID al 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

Registrar el middleware

Regístralo como middleware global en bootstrap/app.php.
->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\App\Http\Middleware\AddContext::class);
})
Con esta configuración, los logs que escribas desde controladores o servicios incluirán automáticamente url y 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"}

Escritura en el contexto

add — añadir valores

use Illuminate\Support\Facades\Context;

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

// Varias claves a la vez
Context::add([
    'first_key'  => 'value',
    'second_key' => 'value',
]);
add sobrescribe las claves existentes. Para añadir solo si la clave no existe, usa addIf.
Context::add('key', 'first');
Context::addIf('key', 'second');

Context::get('key');
// "first" — no se sobrescribe

increment / decrement — contadores

Métodos específicos para aumentar o disminuir un valor numérico. El segundo argumento indica el paso.
Context::increment('records_added');
Context::increment('records_added', 5);

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

when — añadir condicionalmente

Con when puedes añadir datos distintos cuando la condición es 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 — apilar en una lista

Context soporta “pilas” de datos en formato lista. Con push los datos se apilan en el orden en que se añaden.
Context::push('breadcrumbs', 'first_value');
Context::push('breadcrumbs', 'second_value', 'third_value');

Context::get('breadcrumbs');
// ['first_value', 'second_value', 'third_value']
Ejemplo registrando el historial de consultas en una pila.
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\DB;

// Regístralo en el método boot de AppServiceProvider.php
DB::listen(function ($event) {
    Context::push('queries', [$event->time, $event->sql]);
});

Obtención del contexto

get / all

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

// Todos
$data = Context::all();

only / except — subconjuntos

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

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

pull / pop — obtener y eliminar

pull obtiene el valor y lo elimina del contexto a la vez.
$value = Context::pull('key');
Para sacar el último valor de una pila, usa pop.
Context::push('breadcrumbs', 'first_value', 'second_value');

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

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

remember — establecer si no existe y devolver

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

has / missing — comprobar existencia

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

if (Context::missing('key')) {
    // ...
}
has devuelve true aunque el valor sea null. Solo comprueba si la clave está registrada.

Eliminación del contexto

Elimina una clave con forget.
Context::add(['first_key' => 1, 'second_key' => 2]);

Context::forget('first_key');

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

// Varias claves a la vez
Context::forget(['first_key', 'second_key']);

Contexto con scope

Con scope, puedes modificar el contexto solo durante la ejecución del closure y restaurarlo automáticamente al salir. Es útil para incluir información temporal en los logs durante pruebas u operaciones localizadas.
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],
);

// Al salir del scope, los valores se restauran
Context::all();
// ['trace_id' => 'abc-999']

Context::allHidden();
// ['user_id' => 123]
Si dentro del scope modificas un objeto, ese cambio se refleja también fuera. Con valores primitivos no hay problema.

Hidden Context

Los datos que no deben aparecer en los logs (contraseñas, claves de API, PII) se guardan en el “Hidden Context”. No pueden leerse con get; solo con métodos dedicados como getHidden.
use Illuminate\Support\Facades\Context;

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

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

Context::get('key');
// null — no se puede obtener con get normal
El Hidden Context tiene los mismos métodos que el contexto normal.
Context::addHidden(/* ... */);
Context::addHiddenIf(/* ... */);
Context::pushHidden(/* ... */);
Context::getHidden(/* ... */);
Context::pullHidden(/* ... */);
Context::popHidden(/* ... */);
Context::onlyHidden(/* ... */);
Context::exceptHidden(/* ... */);
Context::allHidden(/* ... */);
Context::hasHidden(/* ... */);
Context::missingHidden(/* ... */);
Context::forgetHidden(/* ... */);

Transferencia a jobs de cola

Al despachar un job, el contexto actual se serializa automáticamente en el payload del job. Al ejecutarse el job se restaura el contexto original, por lo que el trace_id establecido en la solicitud aparece también en los logs de la cola.
// Establecido en el middleware
Context::add('trace_id', Str::uuid()->toString());

// Despachar el job desde el controlador
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"}
Comprueba cómo el trace_id de la solicitud también aparece en los logs de la cola.

Dehydrating — personalizar al enviar el job

Con Context::dehydrating puedes ajustar el contexto justo antes de enviar el job. Por ejemplo, pasar a la cola el locale determinado por la cabecera 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'));
    });
}
Dentro del callback dehydrating no uses la fachada Context; usa únicamente el repositorio $context que recibe el callback. Usar la fachada modificaría el contexto del proceso actual.

Hydrated — restauración al ejecutar el job

Context::hydrated te permite añadir lógica justo cuando se restaura el contexto, antes de ejecutar el job. Por ejemplo, aplicar al archivo de configuración el locale guardado.
// 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'));
        }
    });
}
Tampoco uses la fachada Context dentro de hydrated; usa solo el repositorio $context recibido.

Resumen

ContextLog::withContext
AlcanceTodos los canales de logSolo un canal concreto
Transferencia a jobsAutomática (Dehydrate/Hydrate)No
Datos ocultos (Hidden)SoportadosNo
UsoTracing, sistemas distribuidosMetadatos específicos de un canal
El Hidden Context no aparece en los logs, así que puedes guardar con seguridad:
  • IDs de sesión o de usuario (si no quieres dejarlos en el log)
  • Claves de API o tokens de autenticación
  • Locales o valores de configuración (los quieres transferir a la cola pero no loguear)
  • Flags o estados internos
  1. Transferencia del locale: guarda app.locale en el Hidden Context en dehydrating y restáuralo con Config::set en hydrated.
  2. Propagación de la información de autenticación: hacer que el job pueda consultar el usuario autenticado en la solicitud.
  3. ID de tenant: compartir el identificador de tenant entre solicitudes y jobs en aplicaciones multitenant.
Última modificación el 13 de julio de 2026