Skip to content

Monitoring ve Observability

Cloudflare Workers observability, Sentry hata izleme, logging ve performance monitoring stratejisi.

Achidemy, production’da Sentry (hata izleme), Cloudflare Workers Observability (log/trace) ve Session Replay ile izlenir. Bu sayfa monitoring yapılandırmasını, Sentry çalışma yapısını ve log/performance stratejisini açıklar.

Durum: Aktif. Backend (Worker) ve frontend (tarayıcı) hataları Sentry’ye gönderilir; Stripe webhook ve kritik akışlarda özel sensörler kullanılır.

Paketler: @sentry/cloudflare (Worker), @sentry/react (client).

Aşağıdaki yapı, hataların nerede yakalandığı ve Sentry’ye nasıl iletildiğini özetler.

┌─────────────────────────────────────────────────────────────────────────────┐
│ SENTRY VERİ AKIŞI │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ BACKEND (Cloudflare Worker) │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ workers/app.ts │ │
│ │ • Sentry.withSentry(env => ({ dsn, tracesSampleRate }), handler) │ │
│ │ • Tüm fetch/scheduled hataları otomatik + manuel captureException │ │
│ │ • scheduled: updateCachedRates() catch → Sentry.captureException │ │
│ │ • fetch: requestHandler catch → Sentry.captureException (tag: │ │
│ │ service: "worker_router", extra: url) │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ app/routes/api.stripe.webhook.ts │ │
│ │ • İmza doğrulama hatası → Sentry (tag: stripe_webhook_signature) │ │
│ │ • Sepet satışı hatası → Sentry (tag: stripe_cart_sale, │ │
│ │ extra: sessionId, userId) │ │
│ │ • Refund hatası → Sentry (tag: stripe_refund, extra: eventType) │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │ │
├───────────┼─────────────────────────────────────────────────────────────────┤
│ │ │
│ FRONTEND (Tarayıcı) │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ app/entry.client.tsx │ │
│ │ • Sentry.init({ dsn: VITE_SENTRY_DSN, browserTracingIntegration, │ │
│ │ replayIntegration, tracesSampleRate: 0.1, replaysSessionSampleRate:│ │
│ │ 0.1, replaysOnErrorSampleRate: 1.0 }) │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ app/root.tsx │ │
│ │ • Layout: unhandledrejection / error → Sentry.captureException │ │
│ │ (tags: type: "unhandled_rejection" | "global_error") │ │
│ │ • App ReactErrorBoundary onError → Sentry.captureException │ │
│ │ (contexts: react: errorInfo) │ │
│ │ • Route ErrorBoundary useEffect → Sentry.captureException │ │
│ │ (tags: route: pathname) │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Sentry Dashboard (Issues, Performance, Replays) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
OrtamDeğişkenAçıklama
Worker (backend)SENTRY_DSNSentry proje DSN. wrangler.toml [vars] veya wrangler secret put SENTRY_DSN. Yerelde .dev.vars.
Client (frontend)VITE_SENTRY_DSNAynı DSN; client bundle’da build zamanında enjekte edilir. .env / .dev.vars veya CI’da tanımlanmalı.

Not: DSN boşsa Sentry event göndermez; uygulama çalışmaya devam eder.

KaynakDosya / YerTag / Extra
Worker genelworkers/app.ts (fetch catch)service: "worker_router", url
Worker scheduledworkers/app.ts (scheduled catch)
Stripe imzaapi.stripe.webhook.tscontext: "stripe_webhook_signature"
Stripe sepet satışıapi.stripe.webhook.tscontext: "stripe_cart_sale", sessionId, userId
Stripe refundapi.stripe.webhook.tscontext: "stripe_refund", eventType
Tarayıcı unhandled rejectionapp/root.tsx (Layout)type: "unhandled_rejection"
Tarayıcı global errorapp/root.tsx (Layout)type: "global_error"
React Error Boundaryapp/root.tsx (App)contexts.react (errorInfo)
Route ErrorBoundaryapp/root.tsx (ErrorBoundary)route: pathname
  • tracesSampleRate (client): 0.1 — trafiğin %10’u performans izlenir.
  • replaysSessionSampleRate: 0.1 — oturumların %10’u videoya alınır.
  • replaysOnErrorSampleRate: 1.0 — hata olan tüm oturumların replay’i Sentry’ye gönderilir (beyaz ekran / tıklama konumu analizi için).

Detaylı hata sayfaları ve Error Boundary kullanımı için bkz. Hata Yönetimi ve Logging.


Yapılandırma: wrangler.toml

[observability.logs]
enabled = true
head_sampling_rate = 1
persist = true
invocation_logs = true

Özellikler:

  • Enabled: Log kaydı aktif
  • Head Sampling Rate: %100 log kaydı (1 = tüm request’ler)
  • Persist: Log’lar Cloudflare Dashboard’da saklanır
  • Invocation Logs: Her worker invocation için log

Kullanım:

// Worker içinde
console.log("Request received:", { path: url.pathname, method: request.method });
console.error("Error occurred:", error);
console.warn("Warning:", message);

Görüntüleme:

  • Cloudflare Dashboard → Workers → Logs
  • CLI: wrangler tail (real-time logs)
[observability.traces]
enabled = false
persist = true
head_sampling_rate = 1

Not: Şu an traces kapalı; performance profiling için açılabilir.

Kullanım Senaryoları:

  • Request latency analizi
  • Database query süreleri
  • External API çağrı süreleri

Cloudflare Dashboard:

  • Request sayısı
  • Error rate
  • Average response time
  • P95/P99 latency

Görüntüleme:

  • Cloudflare Dashboard → Workers → Analytics

Hyperdrive Metrics:

  • Connection pool kullanımı
  • Query latency
  • Connection errors

Görüntüleme:

  • Cloudflare Dashboard → Hyperdrive → Analytics

Örnek: Video izleme süresi tracking

// app/lib/metrics.ts (gelecekte)
export function trackVideoWatchTime(courseId: string, seconds: number) {
// Analytics servisine gönder (örn: Google Analytics, Mixpanel)
if (import.meta.env.PROD) {
// analytics.track('video_watched', { courseId, seconds });
}
}

LevelKullanımÖrnek
console.logGenel bilgiRequest path, user action
console.warnUyarıDeprecated API kullanımı, fallback durumları
console.errorHataException, failed request
// ✅ İyi: Structured log
console.log("User enrolled", {
userId: user.id,
courseId: course.id,
price: enrollment.price,
timestamp: new Date().toISOString()
});
// ❌ Kötü: Unstructured log
console.log(`User ${user.id} enrolled in course ${course.id}`);

Loglanmaması Gerekenler:

  • Passwords
  • API keys
  • Credit card numbers
  • Personal identifiable information (PII)

Örnek:

// ❌ Kötü
console.log("User data:", user); // Password içerebilir
// ✅ İyi
console.log("User enrolled", {
userId: user.id,
email: user.email, // Email OK, password değil
});

Kullanım: Yerel veya production log’larını real-time görüntüleme

Terminal window
# Production logs
wrangler tail
# Belirli worker için
wrangler tail --name coursio
# Filter ile
wrangler tail --format pretty | grep "ERROR"

URL: https://dash.cloudflare.com

Bölümler:

  • Workers → Logs: Real-time ve geçmiş log’lar
  • Workers → Analytics: Request metrics, error rate
  • Hyperdrive → Analytics: Database connection metrics

  1. Error Rate: %5’in üzerinde error rate
  2. Response Time: P95 latency 2 saniyenin üzerinde
  3. Database Errors: Connection pool exhaustion
  4. Stripe Webhook Failures: Webhook işleme hataları
  5. Currency Sync Failures: Kur güncelleme cron job hataları
  • E-posta: Kritik hatalar için
  • Slack: Ekip bildirimleri için
  • PagerDuty: On-call durumlar için

Önerilen: /api/health endpoint’i

app/routes/api.health.ts
export async function loader() {
const checks = {
database: await checkDatabase(),
stripe: await checkStripe(),
bunny: await checkBunny(),
};
const isHealthy = Object.values(checks).every(c => c.status === 'ok');
return json(checks, {
status: isHealthy ? 200 : 503
});
}

Kullanım: Uptime monitoring servisleri için.


  • wrangler.toml — Observability ve [vars] içinde SENTRY_DSN, VITE_SENTRY_DSN
  • workers/app.ts — Sentry.withSentry sarmalayıcı, Worker hata yakalama
  • app/entry.client.tsx — Sentry.init (client), browserTracing, replay
  • app/root.tsx — Global error / unhandledrejection ve ErrorBoundary içinde Sentry.captureException
  • app/routes/api.stripe.webhook.ts — Stripe webhook Sentry sensörleri (imza, sepet, refund)
  • app/components/ErrorBoundary.tsx — React Error Boundary (onError root’tan gelir)