react-native-observability
v0.1.1
Published
Production-grade observability and debugging toolkit for React Native with structured logging, error boundaries, on-device debug panel, and zero forced dependencies.
Maintainers
Readme
react-native-observability
A production-grade, provider-agnostic observability and debugging toolkit for React Native. Structured logging, optional remote backends, crash capture, PII redaction, on-device debug panel, and first-party integrations for HTTP clients and navigation — all with zero forced runtime dependencies.
npm install react-native-observabilityWhy react-native-observability?
Most observability stacks force you to pick a vendor upfront and bundle its SDK into your core. This library inverts that: it ships provider-agnostic primitives that work with any backend (Sentry, Datadog, your own service) or none at all. Wire only the vendors you use—zero bundle cost if you ship nothing.
The library is pure TypeScript with no native module of its own. Native features (persistent storage, shake-to-open) come from optional peers you opt into.
Features
- Structured logger — composable transports (console, in-memory ring buffer, MMKV),
LogLevelenum, hierarchical namespaces, child loggers, and optional session ID tagging - Observability adapters — forward errors to any backend via
createCustomAdapter(Datadog, Sentry, your service). Adapter fan-out is microtask-deferred and isolated—a broken backend never crashes your app - Crash capture —
installGlobalErrorHandler()catches uncaught JS errors and unhandled promise rejections - Error boundaries —
AppErrorBoundaryandScreenErrorBoundarywith fine-grained error isolation and custom fallback UI - Provider-agnostic HTTP — tag requests with the active screen, apply PII redaction, intercept and mock network traffic. Vendor shims for Axios,
fetch, GraphQL, React Navigation, React Query, tRPC, Apollo, urql, and RTK Query - Session management — MMKV-backed persistence, per-session byte budgets, crash detection across launches, and optional encryption
- Deep PII redaction — recursive key-path matching (
user.**.email) and value-side regexes for email, JWT, credit cards—applied in the write path before any transport or adapter sees data - On-device debug panel — 6+ tabs (Logs, Network, State, Navigation, Performance, Settings), light/dark/system theming, live state inspection, session history, breadcrumb timeline, and crash trail
- Backpressure & sampling — bounded drop-tail queue, token-bucket rate limiting, and per-level/per-namespace sampling to prevent runaway I/O
- Self-telemetry —
getInternalMetrics(),setKillSwitch(), and panic mode to halt I/O if the library fails
Installation
npm install react-native-observability
# or
pnpm add react-native-observability
# or
yarn add react-native-observabilityOptional peers — install only what you use:
| Peer | Unlocks |
| -------------------------- | -------------------------------------- |
| react-native-mmkv | Persistent storage, session management |
| axios | Axios HTTP observer |
| (built-in) | Fetch observer |
| graphql | GraphQL observer |
| @react-navigation/native | React Navigation observer |
| @tanstack/react-query | React Query observer |
| @trpc/client | tRPC observer |
| @apollo/client | Apollo observer |
| urql / @urql/core | urql observer |
| @reduxjs/toolkit | RTK Query observer |
Quick Start
1. Create a Logger
// src/services/logger.ts
import {
createLogger,
ConsoleTransport,
MemoryTransport,
LogLevel,
} from 'react-native-observability';
export const memoryTransport = new MemoryTransport({ maxEntries: 500 });
export const logger = createLogger({
namespace: 'app',
level: __DEV__ ? LogLevel.DEBUG : LogLevel.WARN,
transports: [new ConsoleTransport(), memoryTransport],
});2. Wrap Your App
// App.tsx
import { AppErrorBoundary } from 'react-native-observability';
import { DebugPanelProvider } from 'react-native-observability/panel';
import { logger, memoryTransport } from './services/logger';
import { http } from './services/http';
export default function App() {
return (
<AppErrorBoundary logger={logger} FallbackComponent={ErrorFallback}>
<DebugPanelProvider
enabled={__DEV__}
logSource={memoryTransport}
networkSource={http.store}
openOn={['multiTap']}
multiTapCount={5}
>
<Root />
</DebugPanelProvider>
</AppErrorBoundary>
);
}
function ErrorFallback({ error, retry }: { error: Error; retry: () => void }) {
return (
<View>
<Text>Error: {error.message}</Text>
<Button onPress={retry} title="Retry" />
</View>
);
}3. Observe HTTP
// src/services/http.ts
import axios from 'axios';
import { createHttpObserver } from 'react-native-observability';
import { observeAxios } from 'react-native-observability/observers/axios';
import { observeFetch } from 'react-native-observability/observers/fetch';
import { logger } from './logger';
export const http = createHttpObserver({
logger,
redact: { headerKeys: ['Authorization'], bodyKeys: ['password', 'token'] },
});
const client = axios.create({ baseURL: 'https://api.example.com' });
observeAxios(client, http);
observeFetch(http);
export { client };4. Use the Logger
import { logger } from './services/logger';
// Simple entry
logger.info('User logged in', { userId: 'u123' });
// With an error
try {
await fetchData();
} catch (error) {
logger.error('Fetch failed', error instanceof Error ? error : new Error(String(error)));
}
// Child loggers for namespace hierarchy
const authLogger = logger.child('auth');
authLogger.debug('Validating token');5. Open the Panel
The panel opens via gesture (shake or multi-tap):
import { useDebugPanel } from 'react-native-observability/panel';
export function MyScreen() {
const { openPanel } = useDebugPanel();
return <Button onPress={() => openPanel('logs')} title="Open Logs" />;
}Architecture
┌───────────────────────────────────┐
│ Application Code │
│ Logging · Navigation · HTTP │
└─────────────────┬─────────────────┘
│
▼ entry
┌─────────────────┴─────────────────┐
│ Logger Core │
│ (hot path) │
│ filter · redact · sample │
└─────────────────┬─────────────────┘
│
┌─────────────────────┼─────────────────────┐
dispatch queue feed
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ Transports │ │ Adapters │ │ Integrations │
│ │ │ async·isolated │ │ event stores │
└────────────────┘ └────────────────┘ └────────────────┘
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ Console output │ │Remote backends │ │ HTTP · Screen │
│ Memory (ring) │ │ Sentry·Datadog │ │Breadcrumb·Perf │
│ MMKV (persist) │ │ │ │ │
└────────────────┘ └────────────────┘ └────────────────┘
│ │
└─────────────────────┬─────────────────────┘
subscribe · query
│
▼
┌─────────────────┴─────────────────┐
│ Debug Panel │
└─────────────────┬─────────────────┘
│
▼ render
┌─────────────────┴─────────────────┐
│ Live UI │
│Logs · Network · State · Nav · Perf│
└───────────────────────────────────┘Data flow:
- App calls logger —
logger.info(),trackScreen(), HTTP requests - Logger core (hot path) — Filters, redacts, samples, tags with screen/session
- Three paths in parallel:
- Transports — Write independently (Console, Memory, MMKV*)
- Adapters — Queued async, error-isolated (Sentry, Datadog, custom)
- Integrations — Feed into stores (HTTP, screens, breadcrumbs, perf)
- Panel reads stores — Real-time subscription via
useSyncExternalStore - User sees live UI — Logs, network, state, navigation, performance
*Optional peer: react-native-mmkv
Documentation
Start here: Documentation Navigation Guide — Find what you need by goal or problem
Essential guides:
- Getting Started — First-time setup and core concepts
- Installation — Peer dependencies and platform setup
- Quick Start — 5-minute walkthrough
Understanding the system:
- Architecture — System design and principles
- Diagrams — Visual flowcharts and sequence diagrams
- Configuration — All configuration options
- API Reference — Complete export reference
Feature guides:
- Logger — Structured logging and transports
- Error Boundaries — Error isolation
- HTTP Observer — Network monitoring and mocking
- Debug Panel — On-device UI and customization
- Screen Tracking — Screen attribution
- Persistence — MMKV storage and sessions
- Observers — Vendor integrations
- Adapters — Custom backends
- Breadcrumbs — Timeline and crash trails
- Performance — Performance monitoring
- Redaction — PII protection
Production & support:
- Testing — Testing patterns
- Troubleshooting — Common issues
- FAQ — 40+ frequently asked questions
Examples
- Expo Example — Go-safe subset, no native build required
- Bare Example — Full native surface with MMKV and shake-to-open
Supported Platforms
- React Native: ≥0.73.0
- React: ≥18.0.0
- Node: ≥18
Bundle Size
Observability ships with aggressive size budgets enforced in CI. Core is ~8 KB (gzipped), adapters are ~4 KB, and the panel is ~30 KB (excluding React/React Native).
Contributing
We welcome contributions. Please read CONTRIBUTING.md for guidelines.
Development
pnpm install
pnpm build # tsup — CJS + ESM + .d.ts
pnpm typecheck # tsc --noEmit
pnpm lint # eslint
pnpm test # jest
pnpm test:coverage
pnpm size # size-limit — verify budgetsLicense
MIT — see LICENSE for details.
Questions? Open an issue on GitHub.
