AllStak SDK for Flutter and Dart apps. Captures Flutter errors, unhandled Dart errors, logs, outbound HTTP requests, route breadcrumbs, and native crashes.

Install

flutter pub add allstak

Setup

import 'package:allstak/allstak.dart';
import 'package:flutter/material.dart';

void main() {
  AllStak.runApp(
    const AllStakConfig(
      apiKey: String.fromEnvironment('ALLSTAK_API_KEY'),
      environment: 'production',
      release: String.fromEnvironment('ALLSTAK_RELEASE'),
      service: 'mobile',
    ),
    () => runApp(const MyApp()),
  );
}

Run with:

flutter run \
  --dart-define=ALLSTAK_API_KEY=ask_live_xxx \
  [email protected]

Release identifier (automatic)

You can omit release entirely and let the SDK resolve it. Order, highest first:

  1. Explicit release: you pass to AllStakConfig — always wins.
  2. ALLSTAK_RELEASE dart-define--dart-define=ALLSTAK_RELEASE=..., read at build time. This is the automatic mechanism.
  3. SDK version (kAllStakSdkVersion) as a last resort, so release is never empty. (SDK version is not your app version — last resort only.)

Set autoDetectRelease: false to opt out of steps 2–3 (only an explicit release is ever sent).

Honest note on mobile. A shipped .ipa/.apk/web bundle has no .git directory and no git binary, so runtime git detection is impossible in production. Reading the app's store version at runtime would require a platform plugin (e.g. package_info_plus), which this SDK deliberately does not depend on to stay dependency-light. So the automatic mechanism is the build-time ALLSTAK_RELEASE dart-define. To get the real app version or a git SHA into events, pass it explicitly or via the dart-define, e.g.:

flutter build apk --dart-define=ALLSTAK_RELEASE=1.4.2+$(git rev-parse --short HEAD)

If your app already depends on package_info_plus, read the version there and pass it as release: (step 1) — the SDK won't add that dependency for you.

HTTP client

final client = AllStak.instance!.httpClient();
final response = await client.get(Uri.parse('https://api.example.com/orders'));

Manual capture

await AllStak.instance?.captureLog('info', 'checkout opened');
await AllStak.instance?.captureException(
  StateError('checkout failed'),
  stackTrace: StackTrace.current.toString(),
  context: {'screen': 'checkout'},
);
await AllStak.instance?.captureSpan(
  traceId: traceId,
  spanId: spanId,
  parentSpanId: parentSpanId,
  operation: 'http.client',
  description: 'GET https://api.example.com/orders',
  durationMs: 42,
  startTimeMillis: startMs,
  endTimeMillis: endMs,
);
await AllStak.instance?.flush();
await AllStak.instance?.close();
final diagnostics = AllStak.getDiagnostics();

captureSpan is the low-level API for completed custom spans. Trace and span IDs are normalized to W3C widths before send: 32 lowercase hex characters for traceId, 16 for spanId and parentSpanId.

diagnostics contains counters and queue sizes only: captured/sent/failed/ dropped/persisted/replayed events, retry/rate-limit counts, compression counters, breadcrumb count, active trace/span counts, and session recovery count. It never includes event payloads, headers, breadcrumbs, user data, or secrets.

Navigation breadcrumbs

MaterialApp(
  navigatorObservers: [AllStakNavigatorObserver()],
  home: const HomePage(),
);

Configuration

OptionDescription
apiKeyProject API key.
environmentDeployment environment.
releaseApp version or commit SHA. Omit to auto-detect (see "Release identifier").
autoDetectReleaseDefault true. When release is empty, resolve from the ALLSTAK_RELEASE dart-define, then the SDK version. Set false to opt out.
serviceLogical app service name.
tagsTags added to telemetry.
transportTimeoutPer-request timeout.
enableNativeCrashCaptureDefault true. Arms async-signal-safe native crash handlers (iOS POSIX sigaction; Android NDK sigaction) for hard crashes that never surface as a Dart exception. Degrades to a no-op if the native lib is unavailable.

Native crash capture

Beyond Flutter/Dart errors and the platform uncaught-exception handlers, the SDK arms async-signal-safe POSIX signal handlers (SIGSEGV/SIGABRT/SIGBUS/SIGILL/ SIGFPE/SIGTRAP) so it captures force-unwrap traps, bad-pointer access, and NDK/native signal crashes. A minimal record is written to disk during the crash and shipped on the next launch marked native.crash=true.

  • iOS works out of the box (signal handlers are pure-Swift in the plugin).
  • Android signal/NDK capture requires opting into the bundled native library — set allstak.enableNdkCrashCapture=true in your app's gradle.properties (requires the Android NDK). Without it, the SDK still captures uncaught JVM exceptions; native signal capture is a graceful no-op.

On-device end-to-end delivery of native signal/NDK crashes requires real device/emulator verification.

Privacy

The SDK redacts common sensitive headers and fields. Avoid putting secrets in custom metadata.

Troubleshooting

  • No events: confirm --dart-define=ALLSTAK_API_KEY=... is present for the target build.
  • Native crashes missing: rebuild the native app after installing the package.
  • Source maps missing: keep runtime release aligned with uploaded build artifacts.

Contributing and Support

License

MIT