e-volv
Docs menu

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

shell
npm install @e-volv/logs-react-native
# iOS:
cd ios && pod install   # New Architecture: codegen runs from package.json's codegenConfig
typescript
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:

text
# 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.