Skip to content

Hata Yönetimi ve Logging

Error Boundary'ler, global error handler'lar, hata sayfaları ve production error tracking stratejisi.

Achidemy, kapsamlı bir hata yönetimi sistemi kullanır. React Error Boundary’ler, global error handler’lar ve özel hata sayfaları ile kullanıcı deneyimi korunur ve hatalar loglanır.

Dosya: app/components/ErrorBoundary.tsx; onError callback ve Sentry çağrıları app/root.tsx içinde tanımlı (import * as Sentry from "@sentry/react").

Kullanım: Uygulama kökünde (app/root.tsx) tüm route’ları sarmalar.

<ReactErrorBoundary
onError={(error: Error, errorInfo: React.ErrorInfo) => {
if (import.meta.env.PROD) {
Sentry.captureException(error, { contexts: { react: errorInfo } });
}
}}
>
<Outlet />
</ReactErrorBoundary>

Özellikler:

  • Component hatalarını yakalar
  • Fallback UI gösterir
  • Hata bilgilerini loglar
  • Production’da Sentry’ye gönderilir (bkz. Monitoring ve Observability)

Dosya: app/root.tsxErrorBoundary() export fonksiyonu

Kullanım: React Router route hatalarını yakalar (loader/action hataları).

export function ErrorBoundary() {
const error = useRouteError();
const location = useLocation();
useEffect(() => {
console.error("Route ErrorBoundary caught an error:", error);
if (import.meta.env.PROD) {
Sentry.captureException(error, { tags: { route: location.pathname } });
}
}, [error, location.pathname]);
const status = isRouteErrorResponse(error) ? error.status : 500;
// Status koduna göre uygun hata sayfasını seç
const getErrorPage = () => {
switch (status) {
case 401:
return UnauthorizedPage;
case 404:
return NotFoundPage;
default:
return ServerErrorPage;
}
};
const ErrorPage = getErrorPage();
return <ErrorPage />;
}

Hata Türleri:

  • 401: UnauthorizedPage gösterilir (oturum sonlandırıldı)
  • 404: NotFoundPage gösterilir
  • 500: ServerErrorPage gösterilir

Dosya: app/components/ErrorBoundary.tsx

Özellikler:

  • Kullanıcı dostu hata mesajı
  • Geliştirme modunda hata detayları gösterilir
  • “Sayfayı Yenile” ve “Ana Sayfaya Dön” butonları
  • Dil desteği (path’den dil çıkarılır)

Dosya: app/root.tsxLayout component’i içinde

useEffect(() => {
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
console.error("Unhandled Promise Rejection:", event.reason);
if (import.meta.env.PROD) {
Sentry.captureException(event.reason, { tags: { type: "unhandled_rejection" } });
}
};
window.addEventListener("unhandledrejection", handleUnhandledRejection);
return () => {
window.removeEventListener("unhandledrejection", handleUnhandledRejection);
};
}, []);
useEffect(() => {
const handleError = (event: ErrorEvent) => {
console.error("Global Error:", event.error);
if (import.meta.env.PROD) {
Sentry.captureException(event.error, { tags: { type: "global_error" } });
}
};
window.addEventListener("error", handleError);
return () => {
window.removeEventListener("error", handleError);
};
}, []);

Tüm hata sayfaları tam ekran tasarıma sahiptir ve Navbar/Footer gösterilmez.

Dosya: app/routes/401.tsx

Özellikler:

  • “Oturum sonlandırıldı” mesajı
  • Amber/sarı renk teması (güvenlik uyarısı)
  • ShieldAlert ikonu ile güvenlik vurgusu
  • “Tekrar giriş yap” ve “Ana sayfaya dön” butonları
  • Güvenlik uyarı kutusu (şifre değiştirme önerisi)
  • Çoklu dil desteği (tr/en/es/de/fr/ja)

Kullanım Senaryoları:

  • Hesap paylaşımı nedeniyle oturum düşürüldüğünde
  • Session süresi dolduğunda
  • Yetkisiz erişim denemelerinde

Dosya: app/routes/404.tsx

Özellikler:

  • Kullanıcı dostu “Sayfa Bulunamadı” mesajı
  • Mavi renk teması
  • Ana sayfaya dönüş linki
  • Dil desteği

Dosya: app/routes/500.tsx

Özellikler:

  • “Sunucu Hatası” mesajı
  • Kırmızı/rose renk teması
  • Geliştirme modunda hata detayları
  • Ana sayfaya dönüş linki

Dosya: app/root.tsx

Hata sayfalarında Navbar ve Footer gizlenir:

const isErrorRoute = matches.some((m) =>
[
"error-401",
"error-404",
"error-500",
"lang-401",
"lang-404",
"lang-500",
"lang-catchall-404",
"catchall-404",
].includes(m.id)
);
// Navbar ve Footer gizlenir
{!isErrorRoute && <Navbar />}
{!isErrorRoute && <Footer />}

Örnek: app/routes/api.stripe.webhook.ts

export async function action({ request, context }: ActionFunctionArgs) {
try {
// Webhook işleme
} catch (error) {
console.error("Stripe webhook error:", error);
// Hata yanıtı
return json(
{ error: "Webhook processing failed" },
{ status: 500 }
);
}
}

Dosya: app/graphql/schema.ts

const schema = createSchema({
typeDefs,
resolvers: {
Query: {
// ...
},
Mutation: {
submitExercise: async (_, { exerciseId, code }, { db, user }) => {
try {
// Mutation logic
} catch (error) {
console.error("GraphQL mutation error:", error);
throw new GraphQLError("Mutation failed", {
extensions: { code: "INTERNAL_SERVER_ERROR" }
});
}
}
}
}
});

  • Console Logging: console.error, console.warn, console.log
  • Hata Detayları: Tam stack trace ve hata bilgileri gösterilir
  • Error Tracking: Sentry aktif; Worker, client ve Stripe webhook hataları Sentry’ye gönderilir. Detay için Monitoring ve Observability sayfasına bakın.
  • Structured Logging: Cloudflare Workers Logs kullanılır
  • Hassas Bilgi: Kullanıcı bilgileri ve API key’ler loglanmaz

Yapılandırma: wrangler.toml

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

Kullanım:

console.error("Error occurred:", error);
console.log("Request details:", { path: url.pathname, method: request.method });

  • Kullanıcıya: Genel, anlaşılır mesajlar
  • Geliştiriciye: Detaylı hata bilgileri (sadece development modunda)
Hata TürüHTTP StatusAksiyon
Validation Error400Kullanıcıya form hatası göster
Authentication Error401Login sayfasına yönlendir
Authorization Error403Erişim reddedildi mesajı
Not Found404404 sayfası göster
Server Error500500 sayfası göster
// ✅ İyi: Spesifik hata yakalama
try {
await processPayment();
} catch (error) {
if (error instanceof StripeError) {
// Stripe hatası
} else {
// Genel hata
}
}
// ❌ Kötü: Genel catch
try {
await processPayment();
} catch (error) {
// Tüm hatalar aynı şekilde işleniyor
}

React, aynı bileşende her render’da aynı sayıda ve sırada hook çağrılmasını zorunlu kılar. Sayfa geçişlerinde (örn. course → bundle) veya loading sırasında hook’lardan önce return <Skeleton /> veya return null yapılırsa, bazı render’larda daha az hook çalışır ve “Minified React error #300” (Rendered fewer hooks than expected) oluşur.

Önlem: Route bileşenlerinde:

  • useLoaderData ve diğer tüm hook’lar erken return’lerden önce çağrılır.
  • Loading veya veri yokluğuna göre skeleton / null return’ü yalnızca tüm hook’lar bittikten sonra yapılır.
  • Loader verisi loaderData?.field ve ?? [] ile güvenli kullanılır; hesaplamalar (reduce vb.) hook’lardan sonra ve atma riski olmayacak şekilde yazılır.

Bkz. Kod Konvansiyonları — Route bileşeninde hook sırası ve skeleton.

Sentry entegrasyonu aktif; hatalar app/root.tsx ve workers/app.ts içinde Sentry.captureException ile gönderilir. Stripe webhook’ta imza, sepet satışı ve refund bloklarında özel tag/extra ile raporlanır. Çalışma yapısı ve tag listesi için Monitoring ve Observability — Sentry bölümüne bakın.


  • app/components/ErrorBoundary.tsx — React Error Boundary bileşeni
  • app/root.tsx — Global error handler’lar, Sentry.captureException ve Route ErrorBoundary
  • app/entry.client.tsx — Sentry.init (client)
  • app/routes/401.tsx — 401 Unauthorized sayfası
  • app/routes/404.tsx — 404 Not Found sayfası
  • app/routes/500.tsx — 500 Server Error sayfası
  • app/routes/api.stripe.webhook.ts — Stripe webhook Sentry sensörleri
  • wrangler.toml — Observability ve Sentry DSN değişkenleri