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