İçeriğe geç
Can Uğurlu
Geri dön

Entegrasyon logunu nereye yazmalı

Bir entegrasyon patladığında tek soru var: tam olarak ne gönderildi, tam olarak ne döndü. “Sipariş gönderilemedi” yazan bir log satırı bu soruyu cevaplamıyor, sadece bir şeyin olduğunu söylüyor.

Metin log neden yetmiyor

Log::error('Sipariş gönderilemedi', ['order_id' => $order->id]); satırı bir şeyin başarısız olduğunu söylüyor ama neyin gönderildiğini, karşı tarafın ne döndürdüğünü, hangi denemede olduğunu söylemiyor. Destek ekibi “sipariş 4821 neden Trendyol’a gitmedi” diye sorduğunda log dosyasında grep yapıp doğru satırı bulmaya çalışıyorsunuz.

Beş worker aynı anda çalışıyorsa log satırları birbirine karışıyor, sırayı takip etmek zorlaşıyor.

İsteği ve cevabı yapılandırılmış kayıt olarak tutun

Her dış istek şu alanlarla bir tabloya yazılır: endpoint, HTTP status, süre, correlation id, ham gövde.

Schema::create('integration_logs', function (Blueprint $table) {
    $table->id();
    $table->foreignId('order_id')->nullable()->constrained();
    $table->string('correlation_id')->index();
    $table->string('endpoint');
    $table->unsignedSmallInteger('status_code')->nullable();
    $table->unsignedInteger('duration_ms')->nullable();
    $table->json('request_body')->nullable();
    $table->json('response_body')->nullable();
    $table->timestamps();
});

Bunu bir dosyaya değil, bir tabloya yazın. Destek ekibi tek bir sipariş numarasına bakabilsin, dosyada grep yapmasın. Sipariş durumunu pazaryerine göre farklı adlandıran bir eşleme katmanınız varsa, bu loglar sipariş durum eşlemesini tek yerde tutun yazısındaki yapı ile birlikte okunmalı.

IntegrationLog::create([
    'order_id' => $order->id,
    'correlation_id' => $correlationId,
    'endpoint' => $endpoint,
    'status_code' => $response->status(),
    'duration_ms' => $duration,
    'request_body' => $payload,
    'response_body' => $response->json(),
]);

Başarılı isteği de yazın

Sadece hatayı loglamak yarım resim veriyor. Başarılı bir isteğin süresi zamanla yavaşlıyorsa, hiçbir hata fırlatmadan da bir sorun büyüyor demektir. Her isteği, başarılı ya da başarısız, aynı tabloya yazıp status_code alanına göre filtreleyin.

Bir correlation id, her deneme boyunca aynı kalsın

Bir job beş kez tekrar deniyorsa, beş kaydın hepsi aynı correlation_id ile yazılmalı. Aksi halde beş ayrı olay gibi görünüyor ve hangi denemenin hangisini takip ettiği belirsizleşiyor. Bu retry mantığı failed_jobs tablosuna bakmıyorsanız kuyruğunuz yok yazısındaki tries ve backoff ayarlarıyla birlikte çalışıyor.

Job’un kendi job_id’sini correlation id olarak kullanmak yeterli, yeni bir UUID üretmeye gerek yok, elinizde zaten benzersiz bir kimlik var.

Secret’ı yazarken maskeleyin, sonradan değil

Token, kart bilgisi, API key gibi alanlar veritabanına düz metin olarak girmemeli. Redaksiyon loglama anında yapılır:

function redact(array $payload): array
{
    foreach (['token', 'card_number', 'authorization'] as $key) {
        if (isset($payload[$key])) {
            $payload[$key] = '***';
        }
    }

    return $payload;
}

“Sonra temizlerim” diyip ham veriyi yazıp geçmek, o veriyi tabloda tutmak demek. Yedeklerde, replikalarda ve export’larda da kalıyor. Redaksiyonu yazma anında yapın, sonradan değil.

Saklama süresi koyun ve budayın

Ham payload tablosu hızlı büyür. Her sipariş için istek ve cevap gövdesi tutuluyorsa, günde birkaç bin sipariş bile aylar içinde milyonlarca satıra çıkıyor.

IntegrationLog::where('created_at', '<', now()->subDays(90))->delete();

Bunu zamanlanmış bir göreve bağlayın. 90 gün önceki bir siparişin ham request gövdesine ihtiyacınız neredeyse hiç olmuyor, ama tablo o veriyi taşımaya devam ediyor.

Sorgulanabilir olsun diye index atın

order_id ve created_at üzerinde birleşik index olmadan tablo büyüdükçe “bu siparişin bütün geçmişi” sorgusu da yavaşlıyor. status_code üzerinde ayrı bir index, “son bir saatte kaç istek 500 döndü” gibi sorguları hızlandırıyor:

Schema::table('integration_logs', function (Blueprint $table) {
    $table->index(['order_id', 'created_at']);
    $table->index('status_code');
});

Yapılandırılmış JSON, düz metinden daha değerli

Düz metin log dosyasını okumanın tek yolu grep. Yapılandırılmış kayıt sorgulanabiliyor: son bir saatte 500 dönen bütün istekler, üç saniyeden uzun süren çağrılar, bu correlation id’nin bütün geçmişi. Bunların hiçbiri metin dosyasında pratik değil.

Webhook tarafında da aynı prensip geçerli: webhook’u önce kabul edin, sonra işleyin yazısındaki kabul-sonra-işle akışı, bu logların hangi aşamada yazılacağını da belirliyor.

Özet

İstek ve cevabı bir tabloya, sipariş kaydına bağlı olarak yazın. Tek correlation id’yi bütün denemeler boyunca taşıyın. Secret’ı yazma anında maskeleyin, saklama süresi koyup düzenli budayın.


Bu yazıyı paylaş:

Önceki Yazı
LCP'yi bozan şey genelde font
Sonraki Yazı
Statik site mi, SSR mi