> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Context (contexto)

> 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.

## ¿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

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Middleware
    participant Controller
    participant Queue
    participant Job

    Client->>Middleware: Solicitud HTTP
    Middleware->>Middleware: Context::add('trace_id', uuid)
    Middleware->>Controller: next($request)
    Controller->>Controller: Log::info(...) — trace_id añadido automáticamente
    Controller->>Queue: ProcessPodcast::dispatch()
    Queue->>Job: Serializa y envía el contexto
    Job->>Job: Restaura el contexto (Hydrate)
    Job->>Job: Log::info(...) — trace_id añadido automáticamente
```

## 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.

<Steps>
  <Step title="Crear el middleware">
    ```shell theme={null}
    php artisan make:middleware AddContext
    ```
  </Step>

  <Step title="Añadir el trace ID al Context">
    ```php theme={null}
    <?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);
        }
    }
    ```
  </Step>

  <Step title="Registrar el middleware">
    Regístralo como middleware global en `bootstrap/app.php`.

    ```php theme={null}
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(\App\Http\Middleware\AddContext::class);
    })
    ```
  </Step>
</Steps>

Con esta configuración, los logs que escribas desde controladores o servicios incluirán automáticamente `url` y `trace_id`.

```php theme={null}
Log::info('User authenticated.', ['auth_id' => Auth::id()]);
```

```text theme={null}
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

```php theme={null}
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`.

```php theme={null}
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.

```php theme={null}
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`.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
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

```php theme={null}
$value = Context::get('key');

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

### only / except — subconjuntos

```php theme={null}
$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.

```php theme={null}
$value = Context::pull('key');
```

Para sacar el último valor de una pila, usa `pop`.

```php theme={null}
Context::push('breadcrumbs', 'first_value', 'second_value');

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

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

### remember — establecer si no existe y devolver

```php theme={null}
$permissions = Context::remember(
    'user-permissions',
    fn () => $user->permissions,
);
```

### has / missing — comprobar existencia

```php theme={null}
if (Context::has('key')) {
    // ...
}

if (Context::missing('key')) {
    // ...
}
```

<Info>
  `has` devuelve `true` aunque el valor sea `null`. Solo comprueba si la clave está registrada.
</Info>

## Eliminación del contexto

Elimina una clave con `forget`.

```php theme={null}
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.

```php theme={null}
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]
```

<Warning>
  Si dentro del scope modificas un objeto, ese cambio se refleja también fuera. Con valores primitivos no hay problema.
</Warning>

## 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`.

```php theme={null}
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.

```php theme={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(/* ... */);
```

## 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.

```php theme={null}
// Establecido en el middleware
Context::add('trace_id', Str::uuid()->toString());

// Despachar el job desde el controlador
ProcessPodcast::dispatch($podcast);
```

```php theme={null}
class ProcessPodcast implements ShouldQueue
{
    use Queueable;

    public function handle(): void
    {
        Log::info('Processing podcast.', ['podcast_id' => $this->podcast->id]);
    }
}
```

```text theme={null}
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`.

```php theme={null}
// 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'));
    });
}
```

<Warning>
  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.
</Warning>

### 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.

```php theme={null}
// 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'));
        }
    });
}
```

<Warning>
  Tampoco uses la fachada `Context` dentro de `hydrated`; usa solo el repositorio `$context` recibido.
</Warning>

## Resumen

<AccordionGroup>
  <Accordion title="Diferencia entre Context y Log::withContext">
    |                        | `Context`                      | `Log::withContext`                |
    | ---------------------- | ------------------------------ | --------------------------------- |
    | Alcance                | Todos los canales de log       | Solo un canal concreto            |
    | Transferencia a jobs   | Automática (Dehydrate/Hydrate) | No                                |
    | Datos ocultos (Hidden) | Soportados                     | No                                |
    | Uso                    | Tracing, sistemas distribuidos | Metadatos específicos de un canal |
  </Accordion>

  <Accordion title="Datos que deberían ir a Hidden Context">
    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
  </Accordion>

  <Accordion title="Patrones habituales de Dehydrate/Hydrate">
    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.
  </Accordion>
</AccordionGroup>


## Related topics

- [Logging](/es/logging.md)
- [Contexto de sesión y filtrado](/es/packages/laravel-copilot-sdk/session-context.md)
- [Manejo de errores](/es/error-handling.md)
- [Eventos de streaming](/es/packages/laravel-copilot-sdk/streaming-events.md)
- [Laravel AI SDK](/es/ai-sdk.md)
