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

> Erläutert, wie Sie mit der Context-Funktion von Laravel Informationen über Requests, Jobs und Commands hinweg teilen und automatisch in Logs einbetten.

## Was ist Context?

Die Context-Funktion von Laravel ist ein Mechanismus, mit dem Sie Informationen über HTTP-Requests, Queue-Jobs und Commands hinweg speichern und teilen können.
Wenn Sie über die Facade `Illuminate\Support\Facades\Context` Informationen hinzufügen, werden diese automatisch an alle Log-Einträge angehängt, die Ihre Anwendung schreibt.

Dadurch lassen sich Informationen aus einzelnen Log-Aufrufen sauber von den geteilten Kontextdaten unterscheiden.
Besonders nützlich ist das für Tracing in verteilten Systemen oder in Architekturen mit Queues.

### Ausbreitung des Kontexts

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

    Client->>Middleware: HTTP-Request
    Middleware->>Middleware: Context::add('trace_id', uuid)
    Middleware->>Controller: next($request)
    Controller->>Controller: Log::info(...) – trace_id wird automatisch angehängt
    Controller->>Queue: ProcessPodcast::dispatch()
    Queue->>Job: Kontext serialisiert übertragen
    Job->>Job: Kontext wiederherstellen (Hydrate)
    Job->>Job: Log::info(...) – trace_id wird automatisch angehängt
```

## Grundlegende Verwendung

Das typischste Muster ist das Setzen einer `trace_id` in einer Middleware. Alle nachfolgenden Log-Einträge enthalten sie dann automatisch.

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

  <Step title="Trace-ID zum Kontext hinzufügen">
    ```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="Middleware registrieren">
    Registrieren Sie sie in `bootstrap/app.php` als globale Middleware.

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

Nach dieser Einrichtung werden Log-Einträge aus Controllern oder Services automatisch mit `url` und `trace_id` versehen.

```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"}
```

## In den Kontext schreiben

### add – Werte hinzufügen

```php theme={null}
use Illuminate\Support\Facades\Context;

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

// Mehrere Werte auf einmal hinzufügen
Context::add([
    'first_key'  => 'value',
    'second_key' => 'value',
]);
```

`add` überschreibt vorhandene Schlüssel. Möchten Sie nur hinzufügen, wenn der Schlüssel noch nicht existiert, verwenden Sie `addIf`.

```php theme={null}
Context::add('key', 'first');
Context::addIf('key', 'second');

Context::get('key');
// "first" – wird nicht überschrieben
```

### increment / decrement – Zähler verwalten

Spezielle Methoden zum Erhöhen oder Verringern von Zahlenwerten. Der zweite Parameter gibt die Schrittweite an.

```php theme={null}
Context::increment('records_added');
Context::increment('records_added', 5);

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

### when – bedingt hinzufügen

Mit `when` können Sie je nach `true`-/`false`-Zweig unterschiedliche Werte hinzufügen.

```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 – auf einen Stack legen

Der Kontext unterstützt listenartige „Stacks".
Mit `push` fügen Sie Daten in der angegebenen Reihenfolge hinzu.

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

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

Beispiel für ein Query-Log als Stack:

```php theme={null}
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\DB;

// In der boot-Methode des AppServiceProvider registrieren
DB::listen(function ($event) {
    Context::push('queries', [$event->time, $event->sql]);
});
```

## Kontext lesen

### get / all

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

// Alles abrufen
$data = Context::all();
```

### only / except – nur Teile abrufen

```php theme={null}
$data = Context::only(['first_key', 'second_key']);

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

### pull / pop – abrufen und entfernen

`pull` liest den Wert eines Schlüssels und entfernt ihn zugleich aus dem Kontext.

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

Mit `pop` holen Sie den letzten Wert von einem Stack.

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

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

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

### remember – setzen, falls nicht vorhanden

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

### has / missing – Existenz prüfen

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

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

<Info>
  `has` liefert auch dann `true`, wenn `null` als Wert gespeichert ist. Geprüft wird lediglich, ob der Schlüssel existiert.
</Info>

## Kontext entfernen

Mit `forget` löschen Sie einen Schlüssel.

```php theme={null}
Context::add(['first_key' => 1, 'second_key' => 2]);

Context::forget('first_key');

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

// Mehrere auf einmal löschen
Context::forget(['first_key', 'second_key']);
```

## Kontext mit Scope

Mit der Methode `scope` können Sie den Kontext nur während der Ausführung einer Closure vorübergehend ändern und den ursprünglichen Zustand danach automatisch wiederherstellen.
Praktisch, wenn Sie in Tests oder lokalen Verarbeitungsschritten temporäre Zusatzinformationen ins Log aufnehmen möchten.

```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],
);

// Nach Verlassen des Scopes gelten wieder die ursprünglichen Werte
Context::all();
// ['trace_id' => 'abc-999']

Context::allHidden();
// ['user_id' => 123]
```

<Warning>
  Ändern Sie innerhalb des Scopes ein Objekt, wirken sich diese Änderungen auch außerhalb des Scopes aus. Bei primitiven Werten ist das nicht der Fall.
</Warning>

## Hidden Context

Daten, die nicht in Logs auftauchen sollen (Passwörter, API-Schlüssel, personenbezogene Daten), speichern Sie im Hidden Context.
Sie können nicht mit der regulären `get`-Methode gelesen werden, sondern nur über dedizierte Methoden wie `getHidden`.

```php theme={null}
use Illuminate\Support\Facades\Context;

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

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

Context::get('key');
// null – nicht per regulärem get abrufbar
```

Für den Hidden Context stehen dieselben Methoden wie für den regulären Kontext zur Verfügung.

```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(/* ... */);
```

## Übergabe an Queue-Jobs

Beim Dispatchen eines Jobs wird der aktuelle Kontext automatisch serialisiert und in den Job-Payload eingebettet.
Beim Ausführen des Jobs wird der ursprüngliche Kontext wiederhergestellt, sodass zum Beispiel die `trace_id` aus dem Request auch in Logs des Queue-Jobs erhalten bleibt.

```php theme={null}
// In der Middleware setzen
Context::add('trace_id', Str::uuid()->toString());

// Im Controller den Job dispatchen
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"}
```

Sie sehen, dass die `trace_id` aus dem Request auch in Log-Einträgen aus dem Queue-Job erscheint.

### Dehydrating – Anpassungen beim Verschicken des Jobs

Mit `Context::dehydrating` können Sie den Kontext unmittelbar vor dem Versand des Jobs anpassen.
Zum Beispiel, um die durch den Header `Accept-Language` bestimmte Locale an die Queue zu übertragen.

```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>
  Verwenden Sie in der `dehydrating`-Callback nicht die `Context`-Facade, sondern ausschließlich das an die Callback übergebene `$context`-Repository.
  Andernfalls verändern Sie den Kontext des aktuellen Prozesses.
</Warning>

### Hydrated – Wiederherstellung beim Ausführen des Jobs

Mit `Context::hydrated` können Sie unmittelbar nach dem Wiederherstellen des Kontexts vor der Job-Ausführung eingreifen.
Zum Beispiel, um die zuvor gespeicherte Locale in die Konfiguration zu übernehmen.

```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>
  Auch in der `hydrated`-Callback dürfen Sie die `Context`-Facade nicht verwenden; nutzen Sie ausschließlich das übergebene `$context`-Repository.
</Warning>

## Zusammenfassung

<AccordionGroup>
  <Accordion title="Context vs. Log::withContext">
    |                         | `Context`                       | `Log::withContext`            |
    | ----------------------- | ------------------------------- | ----------------------------- |
    | Reichweite              | Alle Log-Channels               | Nur ein bestimmter Channel    |
    | Übernahme in Queue-Jobs | Automatisch (Dehydrate/Hydrate) | Nein                          |
    | Hidden Data             | Unterstützt                     | Nein                          |
    | Anwendungsfall          | Tracing / verteilte Systeme     | Channel-spezifische Metadaten |
  </Accordion>

  <Accordion title="Für welche Daten eignet sich Hidden Context?">
    Da Hidden Context nicht in Logs erscheint, können Sie folgende Daten sicher speichern:

    * Session-IDs oder User-IDs (falls sie nicht in Logs auftauchen sollen)
    * API-Schlüssel oder Authentifizierungstoken
    * Locale oder Konfigurationswerte (sollen in die Queue übernommen, aber nicht geloggt werden)
    * Interne Flags oder Zustände
  </Accordion>

  <Accordion title="Häufige Muster mit Dehydrate/Hydrate">
    1. **Locale übernehmen**: In `dehydrating` `app.locale` im Hidden Context speichern, in `hydrated` per `Config::set` wiederherstellen.
    2. **Auth-Informationen weiterreichen**: Informationen zum im Request authentifizierten Nutzer im Queue-Job weiter nutzbar machen.
    3. **Tenant-ID**: In Multi-Tenant-Anwendungen die Tenant-Kennung queue-übergreifend teilen.
  </Accordion>
</AccordionGroup>


## Related topics

- [Logging](/de/logging.md)
- [Session-Kontext und Filterung](/de/packages/laravel-copilot-sdk/session-context.md)
- [Fehlerbehandlung](/de/error-handling.md)
- [Telemetrie](/de/packages/laravel-copilot-sdk/telemetry.md)
- [Streaming-Ereignisse](/de/packages/laravel-copilot-sdk/streaming-events.md)
