Skip to main content

LeanCode Debug Page

A debug page that gathers HTTP requests and logger logs with detailed filtering, sharing capabilities, and configurable entry points. Essential for debugging network requests and application logs during development and testing.

Features

  • HTTP Request Tracking: Capture and display detailed information about all HTTP requests and responses
  • Logger Integration: Gather and display logs from the logging package
  • Advanced Filtering:
    • Requests by status code and search query
    • Logs by log level and search query
  • Sharing Capabilities:
    • Share all logs or requests
    • Share individual items
  • Flexible Entry Points:
    • Draggable floating action button
    • Device shake detection

Installation

1

Add dependency

Add leancode_debug_page to your pubspec.yaml:
flutter pub add leancode_debug_page
2

Update your app

Follow the integration steps below to set up the debug page in your application.

Integration

1

Create LoggingHttpClient

Wrap your HTTP client with LoggingHttpClient to enable request tracking:
import 'package:leancode_debug_page/leancode_debug_page.dart';
import 'package:http/http.dart' as http;

final loggingHttpClient = LoggingHttpClient(
  client: http.Client(), // Optional: provide your own client
);
LoggingHttpClient is a wrapper over the standard http.Client that logs all requests and responses while maintaining full compatibility with the HTTP package.
2

Create DebugPageController

Initialize the controller with your logging client and navigator key:
class _MyAppState extends State<MyApp> {
  final navigatorKey = GlobalKey<NavigatorState>();
  late DebugPageController _debugPageController;

  @override
  void initState() {
    super.initState();

    _debugPageController = DebugPageController(
      showEntryButton: true,  // Show floating button
      showOnShake: true,      // Enable shake detection
      loggingHttpClient: widget._loggingHttpClient,
      navigatorKey: navigatorKey,
    );
  }

  @override
  void dispose() {
    _debugPageController.dispose();
    super.dispose();
  }
}
3

Wrap MaterialApp with DebugPageOverlay

Add the overlay and configure the navigator:
@override
Widget build(BuildContext context) {
  return DebugPageOverlay(
    controller: _debugPageController,
    child: MaterialApp(
      navigatorKey: navigatorKey,
      navigatorObservers: [_debugPageController.navigatorObserver],
      home: MyHomePage(
        loggingHttpClient: widget._loggingHttpClient,
      ),
    ),
  );
}
Important: You must pass _debugPageController.navigatorObserver to the navigatorObservers list for the debug page to function correctly.

Complete Example

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

void main() {
  final loggingHttpClient = LoggingHttpClient();
  runApp(MyApp(loggingHttpClient: loggingHttpClient));
}

class MyApp extends StatefulWidget {
  const MyApp({
    super.key,
    required LoggingHttpClient loggingHttpClient,
  }) : _loggingHttpClient = loggingHttpClient;

  final LoggingHttpClient _loggingHttpClient;

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final navigatorKey = GlobalKey<NavigatorState>();
  late DebugPageController _debugPageController;

  @override
  void initState() {
    super.initState();

    _debugPageController = DebugPageController(
      showEntryButton: true,
      loggingHttpClient: widget._loggingHttpClient,
      navigatorKey: navigatorKey,
    );
  }

  @override
  Widget build(BuildContext context) {
    return DebugPageOverlay(
      controller: _debugPageController,
      child: MaterialApp(
        title: 'Debug Page Demo',
        navigatorKey: navigatorKey,
        navigatorObservers: [_debugPageController.navigatorObserver],
        home: MyHomePage(
          loggingHttpClient: widget._loggingHttpClient,
        ),
      ),
    );
  }

  @override
  void dispose() {
    _debugPageController.dispose();
    super.dispose();
  }
}

Configuration

DebugPageController Options

Entry Point Configuration

DebugPageController(
  showEntryButton: true,  // default: false
  showOnShake: true,      // default: true
  ignoredBasePath: '/api',
  loggingHttpClient: loggingHttpClient,
  navigatorKey: navigatorKey,
)
Parameters:
  • showEntryButton: Display a draggable floating action button for quick access
  • showOnShake: Enable shake gesture to open the debug page (requires sensors_plus)
  • ignoredBasePath: Optional base path to exclude from request URLs in the display

Shake Detection

By default, shaking your device will open the debug page. The shake detector uses:
  • Threshold: 4 gravity units
  • Auto-start: Automatically begins listening when enabled
  • Auto-stop: Stops listening when controller is disposed
To disable shake detection:
DebugPageController(
  showOnShake: false,
  // ... other parameters
)

Debug Information Exposed

HTTP Requests

For each HTTP request, the debug page displays:
  • Request Details:
    • HTTP method (GET, POST, PUT, DELETE, etc.)
    • Full URL
    • Request headers
    • Request body (for applicable methods)
    • Timestamp (start time)
  • Response Details:
    • Status code
    • Response headers
    • Response body
    • Duration (time taken)
  • Filtering:
    • Filter by status code ranges (1xx, 2xx, 3xx, 4xx, 5xx)
    • Search by URL or content

Logger Logs

The debug page captures logs from Logger.root:
  • Log Information:
    • Log level (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
    • Message
    • Timestamp
    • Logger name
    • Error and stack trace (if available)
  • Filtering:
    • Filter by log level
    • Search by message content
Logger Integration: This package listens to Logger.root. Changing Logger.root.level affects the debug page’s behavior. Logs are only collected from the current isolate.

API Reference

LoggingHttpClient

class LoggingHttpClient extends http.BaseClient {
  LoggingHttpClient({http.Client? client});

  // Access all logged requests
  List<RequestLogRecord> get logs;
  Stream<List<RequestLogRecord>> get logStream;

  // Clear all logged requests
  void clear();
}

DebugPageController

class DebugPageController {
  DebugPageController({
    bool showEntryButton = false,
    bool showOnShake = true,
    String? ignoredBasePath,
    required LoggingHttpClient loggingHttpClient,
    required GlobalKey<NavigatorState> navigatorKey,
  });

  // Navigation observer (must be added to MaterialApp)
  NavigatorObserver get navigatorObserver;

  // Programmatically open/close debug page
  void open();
  void close();

  // Clear logs
  void clearRequestsLogs();
  void clearLoggerLogs();

  // Filters
  ValueNotifier<List<Filter<RequestLogRecord>>> requestsFilters;
  ValueNotifier<List<Filter<LogRecord>>> loggerFilters;

  // Dispose when done
  void dispose();
}

Use Cases

View all API requests and responses in real-time. Useful for:
  • Debugging API integration issues
  • Verifying request/response payloads
  • Checking authentication headers
  • Monitoring response times
Collect and filter application logs. Perfect for:
  • Troubleshooting runtime issues
  • Monitoring error patterns
  • Reviewing debug information
  • Sharing logs with team members
Enable QA teams to:
  • Report issues with detailed network logs
  • Share complete request/response data
  • Filter and search through logs efficiently
  • Verify API behavior without development tools

Package Information

Dependencies

  • http: ^1.1.0 - HTTP client integration
  • logging: ^1.2.0 - Logger integration
  • rxdart: ^0.28.0 - Reactive stream handling
  • sensors_plus: ^6.0.0 - Shake detection
  • share_plus: ^10.0.0 - Sharing capabilities
The debug page automatically uses the current isolate’s logger. Make sure your logging setup directs logs to Logger.root for them to appear in the debug page.

Build docs developers (and LLMs) love