React Native
@e-volv/logs-react-native is the SDK for React Native 0.74 and later, New or Old Architecture. It is a wrapper with no transport of its own: the JS layer builds events with the shared event model and redaction, and hands finished events over a TurboModule to the native Observer clients — Android: io.e-volv:logs-android (see the Android page), iOS: e-volv-logs-swift (see the iOS page) — which own the disk queue, the retry schedule, the lifecycle flush and crash capture.
Install and initialise
npm install @e-volv/logs-react-native # iOS: cd ios && pod install # New Architecture: codegen runs from package.json's codegenConfig
import EvolveLogs from '@e-volv/logs-react-native';
EvolveLogs.init({
key: 'evk_pub_…', // public project key — the ONLY kind allowed in an app
appId: 'com.acme.shop', // Android application id / iOS bundle id
service: 'shop-app',
environment: 'production',
release: '1.4.2', // match the --release you upload source maps for
});
EvolveLogs.info('order created', { orderId: 'o_1', total: 42.5 });
try {
await charge();
} catch (err) {
EvolveLogs.exception(err, { orderId: 'o_1' }); // exception.type/message/stack
}
await EvolveLogs.span('db.query', () => db.query('…'), { table: 'orders' });
// an exception inside the callback ends the span as failed and rethrows
// Queue consumers / deep links: continue an inbound traceparent.
EvolveLogs.runWithTraceparent(job.traceparent, () => {
EvolveLogs.info('job received', { jobId: job.id });
EvolveLogs.span('queue.consume', () => handle(job));
});If key or appId is missing the client is a no-op and warns once. A server key (evk_…) is refused — it has no app-id allowlist and no per-install quota, so it must never ship in a binary; mobile SDKs only accept evk_pub_… public keys. The JS layer holds no key material beyond the configure() call into native.
What runs where
The JS layer (src/) owns the event model, redaction, span and trace ids, JS crash capture, and fetch/XHR traceparent propagation. The native clients own the disk queue, batching, gzip, retry, lifecycle flush, the x-evolve-app-id / x-evolve-install-id headers, and native crashes (Kotlin exceptions, ANRs, Obj-C/Swift exceptions, signals).
JS crashes are captured by wrapping ErrorUtils.getGlobalHandler / setGlobalHandler, chaining the previous handler so the red box and the fatal-crash behaviour are unchanged. Because JS and native events carry the same key, app id and release, both crash streams land in one project.
Options beyond the ones above: redactKeys (merged into the standard password|secret|token|authorization|cookie|set-cookie|api[-_]?key backstop), sampleRate (0–1), nativeTransport (default true), networkInstrumentation (default true), captureJsErrors (default true), and url + fetchImpl (only used when nativeTransport: false).
nativeTransport: false makes the JS layer ship events itself with fetch (identity encoding, the mobile headers sent from JS). It exists for development, tests and the conformance runner — it has no disk queue, so it is not a production configuration.
Network instrumentation
With networkInstrumentation: true (default), fetch and XMLHttpRequest made inside a span/trace get a W3C traceparent header — an existing header is never overwritten — and traceparent is read off responses (EvolveLogs.getLastResponseTraceparent()), so a later JS crash can be attached to the server trace that caused it.
Architecture
New Architecture: src/spec/NativeEvolveLogs.ts is the codegen spec (codegenConfig in package.json); the JSI TurboModule serves all four methods — configure(config) (once), emitEvent(eventJson) (per event), flush() (resolves when the native queue is empty) and getInstallId() — with no bridge serialization. Old Architecture: the same Kotlin class / ObjC++ module is served through the bridge. Autolinking picks the package up on both platforms; no manual linking step. The podspec’s s.dependency 'EvolveLogs' assumes a CocoaPods distribution; until then, link e-volv-logs-swift via the app target’s SwiftPM.
Source maps (Hermes)
Release builds ship minified Hermes bytecode, so JS stacks arrive as bytecode frames. Upload the source map per release — a release-pipeline step, one per platform:
# Android (index.android.bundle.map) and iOS (main.jsbundle.map): npx @evolve/logs-cli upload-artifacts --key evk_… --url https://api.e-volv.io \ --release 1.4.2 --platform react-native --type sourcemap \ index.android.bundle.map
Without the map the error group still forms and counts, but frames show minified names and no file:line.
Status
The JS layer is verified: it conforms to the shared wire fixture in Node through the pure-JS transport. The native half is not: the Kotlin and Swift TurboModule code has not been compiled (no Android SDK or Xcode in the environment it was written in) — treat both as integration-ready, not release-ready. In the default native mode the JS buffer is a hand-off, not a queue: if the native module is missing, events are dropped with a startup warning.
Package reference: packages/logs-react-native. Back to SDK overview.