Skip to content

Gözlemlenebilirlik

Adapter, açık bir sorumluluk ayrımı üzerine inşa edilmiş iki katmanlı bir gözlemlenebilirlik sistemi sunar:

  • Observer'lar — metrikler, yapılandırılmış loglama ve dağıtık izleme için salt okunur hook'lar
  • Interceptor'lar — istek/yanıtları mutasyona uğratmak için okuma-yazma hook'ları

Gözlemlemek istediğinizde observer kullanın. Mutasyona uğratmak istediğinizde interceptor kullanın.

HttpAdapterObserver

Builder üzerindeki .withObserver() ile adapter'a tek bir observer ekleyin.

HookNe zaman çalışır
onRequestStart(request)Tüm request interceptor'larından sonra, HTTP çağrısından hemen önce
onRequestSuccess(response, durationMs)Başarılı bir yanıttan sonra (retry'lar dahil toplam süreyi içerir)
onRequestFailure(error, durationMs)Son hata çağırana iletildiğinde
onRetry(attempt, error, delayMs)Her retry planlandığında, backoff gecikmesinden önce

Örnek: Metrikler + Yapılandırılmış Loglama

typescript
import {
  HttpAdapterObserver,
  HttpAdapter,
  RetryPolicies,
  Response,
  BaseAdapterException,
} from '@yildizpay/http-adapter';

class MetricsObserver implements HttpAdapterObserver {
  onRequestStart(request: Request): void {
    logger.debug({
      event: 'http_request_start',
      method: request.method,
      url: request.url,
      correlationId: request.correlationId,
    });
  }

  onRequestSuccess(response: Response, durationMs: number): void {
    metrics.histogram('http.request.duration_ms', durationMs, {
      status: String(response.status),
    });
  }

  onRequestFailure(error: BaseAdapterException, durationMs: number): void {
    metrics.increment('http.request.error', {
      type: error.name,
      retryable: String(error.isRetryable()),
    });
    logger.error({ event: 'http_request_failure', ...error.toJSON(), durationMs });
  }

  onRetry(attempt: number, error: BaseAdapterException, delayMs: number): void {
    logger.warn({
      event: 'http_retry',
      attempt,
      delayMs,
      reason: error.name,
    });
  }
}

const adapter = HttpAdapter.builder()
  .withRetryPolicy(RetryPolicies.exponential(3))
  .withObserver(new MetricsObserver())
  .build();

CircuitBreakerObserver

Fluent .observe() metodu aracılığıyla bir CircuitBreaker instance'ına observer ekleyin.

HookNe zaman çalışır
onStateChange(from, to)Her durum geçişinde (CLOSED↔OPEN↔HALF_OPEN)
onSuccess()Breaker üzerinden her başarılı çalıştırmanın ardından
onFailure(error)Bir başarısızlık sayıldığında (yani isFailure predicate true döndürdüğünde)
onProbeRejected()HALF_OPEN'da eşzamanlı bir çağıran geri çevrildiğinde

Örnek: Circuit Breaker Metrikleri

typescript
import {
  CircuitBreaker,
  CircuitBreakerObserver,
  CircuitState,
  BaseAdapterException,
} from '@yildizpay/http-adapter';

class CircuitMetricsObserver implements CircuitBreakerObserver {
  onStateChange(from: CircuitState, to: CircuitState): void {
    logger.warn({
      event: 'circuit_breaker_state_change',
      from,
      to,
    });
    metrics.increment('circuit_breaker.state_change', { from, to });
  }

  onProbeRejected(): void {
    metrics.increment('circuit_breaker.probe_rejected');
  }

  onFailure(error: BaseAdapterException): void {
    metrics.increment('circuit_breaker.failure', { type: error.name });
  }
}

const adapter = HttpAdapter.builder()
  .withCircuitBreaker(
    new CircuitBreaker({ failureThreshold: 5, resetTimeoutMs: 30_000 })
      .observe(new CircuitMetricsObserver()),
  )
  .withObserver(new MetricsObserver())
  .build();

Pino / Winston ile Entegrasyon

Tüm BaseAdapterException instance'ları toJSON() uyguladığından yapılandırılmış logger'larla doğal şekilde entegre olurlar:

typescript
// Pino
logger.error(error.toJSON());

// Winston
logger.error('istek başarısız', error.toJSON());

// Düz nesne kabul eden herhangi bir logger
logger.log('error', { message: error.message, ...error.toJSON() });

toJSON() çıktısı name, message, code, stack ve HTTP exception'lar için durum kodu, yanıt gövdesi ve RequestContext içeren tam response nesnesini içerir.

Released under the MIT License.