Explicamos cómo compartir información entre solicitudes, jobs y comandos con la funcionalidad Context de Laravel y añadirla automáticamente a los logs.
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.
use Illuminate\Support\Facades\Context;Context::add('key', 'value');// Varias claves a la vezContext::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
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.phpDB::listen(function ($event) { Context::push('queries', [$event->time, $event->sql]);});
Context::add(['first_key' => 1, 'second_key' => 2]);Context::forget('first_key');Context::all();// ['second_key' => 2]// Varias claves a la vezContext::forget(['first_key', 'second_key']);
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 restauranContext::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.
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.
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 middlewareContext::add('trace_id', Str::uuid()->toString());// Despachar el job desde el controladorProcessPodcast::dispatch($podcast);
class ProcessPodcast implements ShouldQueue{ use Queueable; public function handle(): void { Log::info('Processing podcast.', ['podcast_id' => $this->podcast->id]); }}
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.
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.
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.phpuse 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.