Contoh Penggunaan Context di Laravel 12: Request Tracing dan Queue Propagation

Artikel sebelumnya menjelaskan apa itu Context facade di Laravel 12. Artikel ini fokus pada implementasi nyata: bagaimana Context dipakai untuk trace request ID, propagasi ke jobs, dan debugging yang lebih mudah.

Studi Kasus 1: Request ID di Semua Log

Masalah klasik: saat ada error, sulit tahu log mana yang terkait satu request. Solusi dengan Context:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;

class AddRequestContext
{
    public function handle(Request $request, Closure $next): mixed
    {
        Context::add([
            'request_id' => Str::uuid()->toString(),
            'url'        => $request->fullUrl(),
            'method'     => $request->method(),
            'ip'         => $request->ip(),
            'user_id'    => $request->user()?->id,
        ]);

        return $next($request);
    }
}

Daftarkan di bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->prepend(AddRequestContext::class);
})

Sekarang semua log di seluruh request otomatis punya context:

Log::info('Memproses pembayaran');
// Output di log:
// [2025-04-18 10:23:45] local.INFO: Memproses pembayaran {"request_id":"abc-123","url":"/checkout","user_id":42}

Studi Kasus 2: Propagasi Context ke Queue Jobs

Masalah: ketika request trigger job di queue, context (request ID, user ID) hilang.

Solusi: Context secara otomatis dipropagasi ke jobs jika menggunakan Illuminate\Queue\SerializesModels atau kalau job implement ShouldQueue — tapi kita harus pastikan data context yang ingin dipropagasi ada di “hydrated context”.

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;

class ProcessPayment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public function __construct(
        private int $orderId
    ) {}

    public function handle(): void
    {
        // Context dari request yang dispatch job ini otomatis tersedia
        $requestId = Context::get('request_id');

        Log::info("Memproses pembayaran order {$this->orderId}", [
            'request_id' => $requestId,
        ]);

        // proses pembayaran...
    }
}

Studi Kasus 3: Hidden Context untuk Data Sensitif

Beberapa context tidak ingin muncul di log tapi perlu tersedia di kode:

// Tambah context tersembunyi — tidak masuk ke log
Context::addHidden([
    'payment_token' => $request->payment_token,
    'api_key'       => config('services.payment.key'),
]);

// Ambil di bagian lain
$token = Context::getHidden('payment_token');

Studi Kasus 4: Debugging Feature Flag

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;

class TrackFeatureFlags
{
    public function handle(Request $request, Closure $next): mixed
    {
        $user = $request->user();

        if ($user) {
            Context::add([
                'features' => [
                    'new_checkout'     => $user->hasFeature('new-checkout'),
                    'ai_recommendations' => $user->hasFeature('ai-rec'),
                ],
            ]);
        }

        return $next($request);
    }
}

Kalau ada bug laporan dari user tertentu, cek log dan langsung tahu fitur apa yang aktif saat itu.

Dehydrate dan Hydrate untuk Custom Serialization

Untuk objek yang tidak bisa di-serialize otomatis:

Context::dehydrating(function (Context $context) {
    // Ubah Carbon ke string saat queue job dikirim
    if ($context->has('started_at')) {
        $context->add('started_at', $context->get('started_at')->toIso8601String());
    }
});

Context::hydrated(function (Context $context) {
    // Kembalikan ke Carbon saat job diproses
    if ($context->has('started_at')) {
        $context->add('started_at', Carbon::parse($context->get('started_at')));
    }
});

Baca Juga

Butuh tim yang bantu setup observability dan logging yang proper di aplikasi Laravel? Lihat layanan pengembangan aplikasi kami.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *