layerx_debugger 1.0.1 copy "layerx_debugger: ^1.0.1" to clipboard
layerx_debugger: ^1.0.1 copied to clipboard

Drop-in debugger and logger for Flutter and GetX: pretty console logs, Dio/http capture, crash handling, route, widget and performance tracking, plus an in-app log viewer.

πŸ› LayerX Debugger

In-app debugging for Flutter β€” a new era.

Stop scrolling through console spam. See every log, API call, crash, route and rebuild β€” live, inside your running app β€” with automatic blame analysis, API response diffing and a one-line setup.

pub version pub points platforms license getx


Why LayerX Debugger? #

Traditional Flutter debugging means squinting at a flood of print statements in a tiny console, far from the device QA is actually holding. LayerX Debugger flips that β€” the debugger lives inside the app. Your testers tap a floating πŸ› button and instantly see a beautiful, searchable timeline of everything that happened, plus answers to the question that wastes the most time on every team:

"Who owns this bug β€” the app, the backend, or the network?"

One call, zero boilerplate, and it never ships to your users (it's environment-aware).

await LayerXDebugger.initialize(); // ✨ that's the whole setup

✨ What you get #

  • πŸ› In-app log viewer β€” a draggable floating button + edge-swipe open a searchable, filterable, color-coded log list with a live session-health banner.
  • πŸ•΅οΈ "Who owns this bug?" blame engine β€” every error is attributed to app / backend / network with a QA-ready note.
  • πŸ”€ API response diffing β€” when a backend silently changes its JSON shape, LayerX shows a field-level diff (added / removed / type-changed / value-changed).
  • 🎨 Gorgeous console logs β€” LayerXLog.d/i/w/e/s with colors, emojis & timestamps, plus boxed β”Œβ”€ β”‚ β”” API blocks.
  • 🌐 Automatic network capture β€” LayerXHttp (primary) logs every request/response/error with timings; secrets (password, token, authorization, apiKey, secret) are masked.
  • πŸ’₯ Crash capture β€” FlutterError, PlatformDispatcher and zoned errors, with an onCrash hook for Crashlytics / Sentry.
  • 🧩 GetX-native β€” LayerXController / LayerXService / LayerXDebugMixin lifecycle logs, and auto-registered GetX services with duplicate & double-init guards.
  • ⏱ Profiling & rebuild tracking β€” LayerXProfiler.measure(...), LayerXDebugWidget(tag:).
  • 🌱 Environment-aware β€” dev / staging / prod control verbosity, colors and whether the viewer is even available.

πŸ“Έ See it in action #

Add doc/viewer.png, doc/detail.png and doc/demo.gif to showcase the viewer here.

Searchable log list Rich detail + blame API response diff
doc/viewer.png doc/detail.png doc/diff.png

πŸš€ Install #

dependencies:
  layerx_debugger: ^1.0.1
import 'package:layerx_debugger/layerx_debugger.dart';

⚑ Auto-Setup β€” One Command, Zero Boilerplate #

Added in v1.0.1 β€” the fastest way to integrate LayerX Debugger into any Flutter project.

After adding the package, just run this once from your Flutter project root:

dart run layerx_debugger:setup

That's it. The CLI will automatically:

Step What happens
πŸ“¦ pubspec Adds layerx_debugger: ^1.0.1 and runs flutter pub get
πŸ”§ main.dart Wraps main() with runZonedGuarded + initialize()
🎨 MaterialApp Injects LayerXDebugOverlay builder + navigatorObservers
πŸ’Ύ Backup Creates .bak copies before modifying any file
πŸ” Idempotent Safe to run multiple times β€” already-configured files are skipped

Before (your original main.dart):

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: const HomeView());
  }
}

After (auto-generated by the CLI):

import 'package:layerx_debugger/layerx_debugger.dart';

void main() {
  LayerXDebugger.runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();
    await LayerXDebugger.initialize(
      config: const LayerXDebugConfig(appName: 'My App'),
    );
    runApp(const MyApp());
  });
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) => LayerXDebugOverlay(child: child!),
      navigatorObservers: [LayerXDebugger.routeObserver],
      home: const HomeView(),
    );
  }
}

Run the app β€” the floating πŸ› button appears automatically. No other changes needed.

You can also target a specific project path:

dart run layerx_debugger:setup /path/to/my_flutter_app

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:layerx_debugger/layerx_debugger.dart';

void main() {
  LayerXDebugger.runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();
    await LayerXDebugger.initialize(
      config: const LayerXDebugConfig(appName: 'My App'),
    );
    runApp(const MyApp());
  });
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      navigatorObservers: [LayerXDebugger.routeObserver],            // 🧭 route logs
      builder: (context, child) => LayerXDebugOverlay(child: child!), // πŸ› in-app viewer
      home: const HomeView(),
    );
  }
}

Run the app in debug mode β€” a floating πŸ› button appears. Tap it. Done.

πŸ› Opening the in-app viewer #

There are four ways to open the viewer β€” pick whatever fits your app:

// 1. Floating bug button  β†’ automatic, from LayerXDebugOverlay (just tap it)
// 2. Edge swipe           β†’ swipe in from the right edge (also automatic)

// 3. From ANY button you own:
ElevatedButton(
  onPressed: () => LayerXDebugger.openViewer(context),
  child: const Text('Open Logs'),
);

// 4. A ready-made settings tile:
const LayerXDebugSettingsButton(),

openViewer(context) works even without the overlay β€” it simply pushes the viewer screen.

πŸ“ Logging #

LayerXLog.d('User fetched');     // debug   (grey)
LayerXLog.i('Cache warmed');     // info    (blue)
LayerXLog.s('Payment captured'); // success (green)
LayerXLog.w('Retrying request'); // warning (amber)
LayerXLog.e('API error', error: e, stackTrace: st); // error (red)

LayerXLog.screen('HomeView');           // [SCREEN] HomeView opened
LayerXLog.action('Login Button Clicked'); // [ACTION] Login Button Clicked

'Saved!'.logS(); // or log any value inline

Console output:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ API GET /users
β”‚ Status   : 200 OK β€’ 142ms
β”‚ Response : {"id":1,"name":"Ada"}
└────────────────────────────────────────────────────────────

🌐 Networking β€” http first #

http is the primary, zero-config integration β€” just use LayerXHttp:

final res = await LayerXHttp.get(Uri.parse('https://api.example.com/users'));
await LayerXHttp.post(uri, headers: headers, body: jsonBody);
// get / post / put / patch / delete supported.

Dio (optional β€” never forced) #

LayerX has no dependency on dio. If your app uses Dio, add a tiny interceptor that forwards to the public LayerXNetworkLogger:

class LayerXDioInterceptor extends Interceptor {
  @override
  void onResponse(Response res, ResponseInterceptorHandler handler) {
    LayerXNetworkLogger.record(
      endpoint: res.requestOptions.uri.toString(),
      method: res.requestOptions.method,
      statusCode: res.statusCode ?? 0,
      responseBody: res.data?.toString(),
      requestBody: res.requestOptions.data?.toString(),
    );
    handler.next(res);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    LayerXNetworkLogger.recordException(
      endpoint: err.requestOptions.uri.toString(),
      method: err.requestOptions.method,
      error: err,
      stackTrace: err.stackTrace,
    );
    handler.next(err);
  }
}

final dio = Dio()..interceptors.add(LayerXDioInterceptor());

🧩 GetX integration #

class HomeController extends LayerXController {}          // lifecycle auto-logged
class AuthService   extends LayerXService {}
class CartController extends GetxController with LayerXDebugMixin {} // mix into existing

initialize() auto-registers the LayerX GetX services (LayerXLoggerService, LayerXDebugService, LayerXCrashService, LayerXNetworkService, LayerXPerformanceService, LayerXRouteService) as permanent singletons β€” with duplicate-prevention and a double-initialization guard. Modules light up incrementally as controllers and the network layer are exercised. Set isLayerXArchitecture: false (or autoInject: false) to skip all injection in a non-LayerX app.

🧭 Route debugging #

GetMaterialApp(navigatorObservers: [LayerXDebugger.routeObserver]);
// per-page GetX middleware:
GetPage(name: '/home', page: () => HomeView(), middlewares: [LayerXRouteMiddleware()]);

πŸ’₯ Crash handling #

await LayerXDebugger.initialize(
  config: LayerXDebugConfig(
    onCrash: (error, stack, fatal) {
      FirebaseCrashlytics.instance.recordError(error, stack, fatal: fatal);
      // or: Sentry.captureException(error, stackTrace: stack);
    },
  ),
);

Crashlytics & Sentry are optional β€” LayerX depends on neither and works standalone.

⏱ Performance & πŸ” rebuilds #

final users = await LayerXProfiler.measure('fetchUsers', () => api.fetchUsers());
LayerXProfiler.start('render'); /* ... */ LayerXProfiler.end('render');

LayerXDebugWidget(tag: 'HomeView', child: HomeView()); // logs "HomeView rebuilt N times"

βš™οΈ Configuration #

await LayerXDebugger.initialize(
  config: LayerXDebugConfig(
    appName: 'My App',
    environment: LayerXEnvironment.dev, // dev / staging / prod
    enableApiLogs: true,
    enableRouteLogs: true,
    enableCrashLogs: true,
    enableGetXLogs: true,
    enablePerformanceLogs: true,
    enableWidgetLogs: true,
    maskKeys: ['ssn', 'cardNumber'],
    maxStoredLogs: 500,
    edgeSwipeZone: LayerXEdgeZone.right,
    autoInject: true,
    isLayerXArchitecture: null, // null = auto (assume LayerX); false = skip injection
    onCrash: (e, s, fatal) {/* forward */},
  ),
);
Environment Console level Colors In-app viewer
dev verbose+ βœ… βœ…
staging info+ βœ… βœ…
prod warning+ ❌ ❌

πŸ› Architecture #

LayerX Debugger is itself a showcase of LayerX architecture β€” the source is organised into config/, services/, repository/, mvvm/, core/ and widgets/ under lib/src/, while lib/layerx_debugger.dart stays the single public import.

πŸ“– Example #

A full GetX example lives in example/:

cd example && flutter pub get && flutter run

🀝 Contributing #

Issues and PRs welcome at https://github.com/the-bughex-code/layerx_debugger.

πŸ“„ License #

BSD-3-Clause Β© The BugHex. See LICENSE.

5
likes
0
points
34
downloads

Documentation

Documentation

Publisher

verified publisherthebughex.com

Weekly Downloads

Drop-in debugger and logger for Flutter and GetX: pretty console logs, Dio/http capture, crash handling, route, widget and performance tracking, plus an in-app log viewer.

Repository (GitHub)
View/report issues

Topics

#logging #debugging #getx #networking #devtools

License

unknown (license)

Dependencies

flutter, get, http, intl, logger

More

Packages that depend on layerx_debugger