Handling Errors and Logging
1. Using Global Error Handler
| Property | Description | Usage |
|---|---|---|
| ErrorBoundary | Component to catch JavaScript errors anywhere in the child component tree | import { ErrorBoundary } from 'expo-error-boundary'; |
| handleError | Function to handle errors in the global error handler | function handleError(error, errorInfo) { console.error(error, errorInfo); } |
Example: Implementing Global Error Handler
import React from 'react';
import { ErrorBoundary } from 'expo-error-boundary';
const App = () => {
return (
<ErrorBoundary onError={handleError}>
<YourApp />
</ErrorBoundary>
);
};
function handleError(error, errorInfo) {
console.error('Caught an error:', error, errorInfo);
}
Note: Error boundaries are React components that catch JavaScript errors in their child component tree, log those errors, and display a fallback UI instead of the component that crashed.
2. Logging Errors
| Method | Description | Usage |
|---|---|---|
| console.error() | Logs an error message to the console | console.error("An error occurred"); |
| console.warn() | Logs a warning message to the console | console.warn("This is a warning"); |
| console.log() | Logs a message to the console | console.log("Debug info"); |
Note: In Expo,
console.log and console.error are supported but may not appear in the browser console during development.Example: Using Sentry for Error Logging
import * as Sentry from "sentry-expo";
Sentry.init({
dsn: "YOUR_DSN_HERE",
});
// Log an error
Sentry.captureException(new Error("Something went wrong"));
3. Implementing Error Boundaries
| Property | Description | Usage |
|---|---|---|
| ErrorBoundary | Component that catches JavaScript errors anywhere in its child tree | import { ErrorBoundary } from 'expo-error-boundary'; |
Example: Basic Error Boundary Setup
import React from 'react';
import { ErrorBoundary } from 'expo-error-boundary';
const App = () => {
return (
<ErrorBoundary
onError={(error, errorInfo) => {
console.error('Caught an error:', error);
}}
>
<MyApp />
</ErrorBoundary>
);
};
Note: Error boundaries are React components that catch JavaScript errors in their child component tree, log those errors, and display a fallback UI instead of the component that crashed.
Key Points
- Error boundaries are React components that catch runtime errors in their child tree.
- They do not catch errors in event handlers or asynchronous code (e.g., setTimeout, promises).
- They are useful for graceful degradation in production environments.
4. Handling Async Errors
| Method | Description | Notes |
|---|---|---|
| Expo.ErrorUtils | Global error handler for async errors in Expo apps. | Used to capture and report unhandled promise rejections. |
Example: Setting up global error handler
import * as ErrorUtils from 'expo-errors';\n\nErrorUtils.setGlobalHandler((error) => {\n console.error('Unhandled async error:', error);\n // Send to crash reporting service\n});
Note: This handler is called for unhandled promise rejections and other async errors that occur in the app.
5. Using Sentry Integration
Example: Setting up Sentry with Expo
import * as Sentry from 'sentry-expo';
Sentry.init({
dsn: "YOUR_DSN_HERE",
enableInExpoDevelopment: true,
debug: false
});
| Property | Description | Default |
|---|---|---|
| dsn | Unique identifier for your Sentry project | null |
| enableInExpoDevelopment | Enables Sentry in Expo development mode | false |
| debug | Enables debug logging in Sentry SDK | false |
Note: Make sure to set
enableInExpoDevelopment to true if you want to capture errors during development.
Example: Capturing an exception
try {
throw new Error("Something went wrong!");
} catch (error) {
Sentry.Native.captureException(error);
}
Example: Logging a message
Sentry.Native.captureMessage("User performed an action", {
level: "info"
});
Sentry Integration Summary
- Initialize Sentry with your DSN in your app entry point
- Use
Sentry.Native.captureException()to report errors - Use
Sentry.Native.captureMessage()for logging messages - Enable development mode with
enableInExpoDevelopment
6. Configuring Sentry
Example: Setting up Sentry with Expo
// Install Sentry SDK
// npm install @sentry/react-native
import * as Sentry from '@sentry/react-native';
// Initialize Sentry in your app entry point
Sentry.init({
dsn: 'YOUR_SENTRY_DSN',
enableAutoSessionTracking: true,
});
// Capture an exception
try {
throw new Error('Something went wrong');
} catch (error) {
Sentry.captureException(error);
}
| Configuration Option | Description | Default Value | Notes |
|---|---|---|---|
| dsn | Sentry project DSN | None | Required for Sentry to function |
| enableAutoSessionTracking | Enables automatic session tracking | false | Useful for performance monitoring |
| debug | Enables debug logging in Sentry SDK | false | Useful for development and troubleshooting |
| release | Release version of the app | undefined | Helps in tracking errors across versions |
| environment | Environment name (e.g. production, staging) | undefined | Useful for filtering errors by environment |
Note: Ensure that the DSN is correctly configured to avoid sending errors to the wrong project.
Warning: Sentry SDK requires proper configuration in both development and production environments to capture errors effectively.
Key Points for Sentry Configuration
- DSN is mandatory to initialize Sentry
- Enable session tracking for performance monitoring
- Set release and environment to track errors across versions
- Use debug mode during development for troubleshooting
7. Capturing Exceptions
| Method | Description | Usage |
|---|---|---|
| Expo.ErrorReporter | Reports errors to a remote service | |
| ErrorBoundary | Captures JavaScript errors in components | |
Example: Reporting Unhandled Errors
import * as ErrorReporter from 'expo-error-reporter';
// Report unhandled errors
window.addEventListener('error', (event) => {
ErrorReporter.reportError(event.error);
});
// Report unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
ErrorReporter.reportError(event.reason);
});
Note:
ErrorBoundary only catches errors in React components, not native crashes or unhandled JS exceptions.8. Adding Breadcrumbs
Example: Adding breadcrumbs to an Expo app
import { useEffect } from 'react';
import * as Sentry from 'sentry-expo';
function MyComponent() {
useEffect(() => {
Sentry.addBreadcrumb({
category: 'navigation',
message: 'User navigated to Home screen',
data: {
screen: 'Home',
timestamp: Date.now()
}
});
}, []);
return <View><Text>Home Screen</Text></View>;
}
| Breadcrumb Property | Description | Example Value |
|---|---|---|
| category | Logical grouping of breadcrumb (e.g., navigation, api) | 'navigation' |
| message | Human-readable description of breadcrumb | 'User clicked button' |
| data | Additional context to associate with breadcrumb | { screen: 'Home' } |
| timestamp | ISO timestamp when breadcrumb was added | 1678886400000 |
Note: Breadcrumbs are automatically captured for navigation events in Expo apps when using Sentry SDK.
Warning: Avoid adding too many breadcrumbs as they can impact performance and memory usage.
9. Customizing Error Messages
| Property | Description | Example |
|---|---|---|
| error.message | Readable error message | Network request failed |
| error.code | Standardized error code | NETWORK_ERROR |
| error.details | Additional context or stack trace | |
Example: Custom Error Class
class CustomError extends Error {
constructor(code, message, details) {
super(message);
this.code = code;
this.details = details;
}
}
// Usage
const error = new CustomError(
'API_ERROR',
'Failed to fetch data from API',
{ url: 'https://api.example.com/data', status: 500 }
);
console.log(error.message); // "Failed to fetch data from API"
console.log(error.code); // "API_ERROR"
Note: Expo provides built-in error handling in development, but customizing messages helps with debugging and user experience.
10. Reporting Native Crashes
| Property | Description | Values |
|---|---|---|
| expo-error-reports | Enables crash reporting to Expo's error reporting service | true or false |
| errorReportUrl | Custom endpoint to send crash reports to | string |
Example: Configure crash reporting in app.json
{
"expo": {
"errorReports": {
"enabled": true,
"endpoint": "https://your-server.com/crash-reports"
}
}
}
Note: Crash reports include device info, stack traces, and app state at time of crash.
Warning: Ensure compliance with privacy regulations when collecting crash reports.
| Crash Type | Description | Handled By |
|---|---|---|
| JavaScript Exceptions | Caught and reported via Expo's error handler | Expo.ErrorReport |
| Native Crashes | Crashes in native modules or iOS/Android code | Expo.ErrorReport + native crash reporter |
11. Using Analytics
Example: Setting up analytics in Expo
import { Analytics } from 'expo-analytics';
const analytics = new Analytics('YOUR_ANALYTICS_ID');
analytics.trackEvent('user_login', {
userId: '12345',
timestamp: Date.now(),
});
| Property | Description | Values |
|---|---|---|
| trackEvent | Tracks a specific event with optional properties | string, object |
| setUserProperties | Sets user-specific properties for tracking | object |
| trackPageView | Tracks page view events | string |
Note: Analytics integration requires a valid analytics service ID (e.g., Google Analytics or Mixpanel) to function properly.
12. Tracking Custom Events
| Property | Description | Example |
|---|---|---|
| event | Name of the custom event to track | user_login |
| properties | Object containing additional data about the event | { userId: '123', page: 'home' } |
Example: Tracking a Custom Event
import { logEvent } from 'expo-analytics';
logEvent('user_login', {
userId: '123',
page: 'home'
});
Note: Custom events are tracked using the
logEvent function from the expo-analytics package.