SnapLogs
Retour au blog
Flutter

Debug Flutter en production : le guide ultime pour diagnostiquer les erreurs

Debugguer Flutter en local est facile. Debugguer en production en est une autre affaire : obfuscation, symbolication, crash groups, redéploiement, performance tracing, alertes et post-mortem. Ce guide ultime couvre toutes les techniques pour diagnostiquer les erreurs Flutter en production en 2026, avec des exemples de code, des case studies réels, et l'intégration de SnapLogs pour un workflow complet d'incident response.

S

SnapLogs Team

Équipe produit

Debug Flutter en production : le guide ultime pour diagnostiquer les erreurs

Debug Flutter en production : le guide ultime pour diagnostiquer les erreurs

Debugguer Flutter sur son simulateur avec un hot reload est une expérience fluide. Debugguer en production, sur 100k devices hétérogènes, sans accès direct, est un autre sport. Ce guide ultime couvre toutes les techniques pour diagnostiquer les erreurs Flutter en production en 2026 : release mode, obfuscation, symbolication, crash groups, performance tracing, alertes, et workflow post-mortem.

Les défis du debug Flutter en production

Le debug local et le debug production diffèrent sur six dimensions.

| Dimension | Local | Production | | --- | --- | --- | | Accès device | Direct (simulateur) | Aucun | | Stack trace | Lisible | Obfusquée | | Logs | debugPrint visibles | Disparaissent | | Reproduction | Trivial | Rarement possible | | Volume | 1 device | 100k devices | | Contexte | Hot reload | Build figé |

En production, vous n'avez accès qu'à ce que votre app décide de remonter. Le socle est donc : instrumenter avant le bug, pas après.

Comprendre les modes de build Flutter

Flutter a trois modes :

  • debug : assertions activées, hot reload, stack traces lisibles, pas d'obfuscation.
  • profile : pas d'assertions, pas de hot reload, perfs réalistes, stack traces lisibles.
  • release : obfuscation, tree-shaking, pas de logs, stack traces obfusquées.
flutter run                 # debug
flutter run --profile       # profile
flutter run --release       # release
flutter build apk --release # release build

Le mode release est celui que vos utilisateurs vivent. Testez toujours votre instrumentation en release avant de déployer.

Obfuscation et symbolication

Ce que fait l'obfuscation

En release, Flutter obfusque les noms de classes, méthodes et variables. La stack trace devient :

package:app/main.dart:0x4a3b2c1
package:app/payment.dart:0x7f8e9d2

au lieu de :

package:app/main.dart:42
package:app/payment.dart:128

Sans symbolication, la stack est inutilisable.

Générer les symbols map

Lors du build release, générez les symbols :

flutter build apk --release --obfuscate --split-debug-info=./build/symbols

Cela crée un dossier ./build/symbols/ avec un fichier par target (arm64-v8a, armeabi-v7a, x86_64). Conservez ces fichiers : sans eux, la symbolication est impossible.

Symbolication côté serveur

SnapLogs et Sentry symbolisent les stacks côté serveur si vous uploadez les symbols. Configuration SnapLogs :

# snaplogs.yaml
upload_symbols: true
symbols_path: ./build/symbols

À chaque release, le CLI SnapLogs upload les symbols :

npx snaplogs symbols upload --path=./build/symbols --version=1.4.2

Les stacks reçues sont symbolisées automatiquement. Vous voyez payment.dart:128 au lieu de 0x7f8e9d2.

Symbolication manuelle

Si vous n'avez pas uploadé, vous pouvez symboliser localement :

flutter symbolize -i stack.txt -d ./build/symbols

stack.txt contient la stack obfusquée. Utile pour un crash ponctuel.

Crash groups : trier et prioriser

Un crash peut générer 1000 tickets. Il faut grouper.

Groupage par signature

Les crash reporters groupent par signature de stack trace. SnapLogs et Sentry le font automatiquement. Les stacks avec le même premier frame sont groupées.

Groupage par fingerprint personnalisé

Parfois, des crashs avec stacks différentes ont la même cause métier. Forcez un fingerprint :

await SnapLogs.captureException(
  e,
  stackTrace: st,
  fingerprint: ['payment', 'charge', 'provider_declined'],
);

Tous les crashs avec ce fingerprint sont groupés, indépendamment de la stack.

Priorisation

Priorisez par :

  • Volume : 10k crashes > 10 crashes.
  • Impact : crash sur payment > crash sur settings.
  • Récurrence : crash persistant sur 5 versions > crash ponctuel.

Un crash à 10k occurrences sur le flow payment est P0. Un crash à 3 occurrences sur settings est P3.

Volume de crashs Flutter en production sur 7 jours

Le volume de crashs par jour permet d'identifier les pics et de mesurer l'impact d'un deploy. Un pic soudain = regression.

Error monitoring en production

Capture des erreurs

Configurez les trois points de capture :

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:snaplogs/snaplogs.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await SnapLogs.init(
    apiKey: const String.fromEnvironment('SNAPLOGS_KEY'),
    environment: 'production',
    sampleRate: 0.05,
    errorSampleRate: 1.0,
  );

  // 1. Erreurs framework
  FlutterError.onError = (FlutterErrorDetails details) {
    FlutterError.presentError(details);
    SnapLogs.captureException(details.exception, stackTrace: details.stack);
  };

  // 2. Erreurs async hors framework
  runZonedGuarded<Future<void>>(() async {
    runApp(const MyApp());
  }, (Object error, StackTrace stack) {
    SnapLogs.captureException(error, stackTrace: stack);
  });

  // 3. Erreurs d'isolate
  Isolate.current.addErrorListener(
    RawReceivePort((dynamic pair) {
      final List<dynamic> data = pair as List<dynamic>;
      SnapLogs.captureException(
        data.first as Object,
        stackTrace: data.last as StackTrace,
      );
    }).sendPort,
  );
}

Sans ces trois, vous ratez une partie des crashes.

Filtrage du bruit

Certaines erreurs ne méritent pas un ticket. Utilisez beforeSend :

await SnapLogs.init(
  apiKey: key,
  beforeSend: (event) {
    if (event.tags['flow'] == 'health_check') return null;
    if (event.message.contains('SocketException')) return null;
    return event;
  },
);

SnapLogs capture automatiquement :

  • Taps (onTap, onPressed).
  • Navigations (push, pop).
  • Requêtes réseau (http.get, http.post).

Ces breadcrumbs sont attachés au crash. Vous voyez la timeline :

T 12:04:31 TAP "Login"
T 12:04:31 NAV push /dashboard
T 12:04:32 NET POST /auth/token → 200
T 12:04:34 NAV push /payments
T 12:04:35 TAP "Pay"
T 12:04:35 NET POST /payments/charge → 500
T 12:04:35 ERR PaymentException

Le dev voit immédiatement : le token a expiré entre login et payment.

Performance tracing en production

Mesurer le jank

Le jank (frame qui met >16ms à rendre) est invisible dans les crashs. Utilisez :

  • Flutter DevTools en profile mode pendant le dev.
  • Firebase Performance en production.
  • Sentry Performance en production.

SnapLogs ne fait pas de perf monitoring mais capture les breadcrumbs qui aident à identifier les écrans lents (ex : tous les crashes surviennent après /dashboard qui met 3s à charger).

Tracer les écrans lents

Instrumentez vos écrans :

class DashboardScreen extends StatefulWidget {
  const DashboardScreen({super.key});

  @override
  State<DashboardScreen> createState() => _DashboardScreenState();
}

class _DashboardScreenState extends State<DashboardScreen> {
  DateTime? _loadStart;

  @override
  void initState() {
    super.initState();
    _loadStart = DateTime.now();
    _loadData();
  }

  Future<void> _loadData() async {
    try {
      await fetchDashboard();
    } finally {
      final duration = DateTime.now().difference(_loadStart!);
      SnapLogs.log(
        level: LogLevel.info,
        message: 'dashboard_loaded',
        fields: {'duration_ms': duration.inMilliseconds},
      );
      if (duration.inMilliseconds > 2000) {
        SnapLogs.log(
          level: LogLevel.warning,
          message: 'dashboard_slow',
          fields: {'duration_ms': duration.inMilliseconds},
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) => const Scaffold(body: Center(child: Text('Dashboard')));
}

Vous pouvez ensuite filtrer les dashboards >2s dans SnapLogs et investiguer.

Tracer les appels réseau

import 'package:http/http.dart' as http;

Future<void> tracedGet(String url) async {
  final start = DateTime.now();
  try {
    final response = await http.get(Uri.parse(url));
    final duration = DateTime.now().difference(start);
    SnapLogs.log(
      level: LogLevel.info,
      message: 'http_get',
      fields: {
        'url': url,
        'status': response.statusCode,
        'duration_ms': duration.inMilliseconds,
      },
    );
    if (duration.inMilliseconds > 1000) {
      SnapLogs.log(
        level: LogLevel.warning,
        message: 'http_slow',
        fields: {'url': url, 'duration_ms': duration.inMilliseconds},
      );
    }
  } catch (e, st) {
    SnapLogs.log(
      level: LogLevel.error,
      message: 'http_error',
      fields: {'url': url},
      error: e,
      stackTrace: st,
    );
    rethrow;
  }
}

DevTools en production : limites et alternatives

Flutter DevTools est conçu pour le dev local. En production, vous ne pouvez pas brancher DevTools sur le device d'un user. Alternatives :

  • SnapLogs dashboard : les breadcrumbs et logs remplacent le widget inspector.
  • Sentry replay : rejoue la session utilisateur (beta).
  • Firebase Remote Config : active des flags de debug à distance.

Pour les rares cas où vous pouvez demander à un user de brancher son téléphone (beta test), utilisez flutter attach :

flutter attach --app-id com.example.app

Mais cela reste exceptionnel.

Alertes et incident response

Configurer les alertes

SnapLogs alerte sur :

  • Pic d'erreurs (ex : >100 erreurs/5min).
  • Nouveau type de crash (signature inconnue).
  • Erreur P0 (fingerprint taggé p0).

Configuration Slack :

# snaplogs.yaml
alerts:
  - name: error_spike
    condition: error_rate > 1%
    channel: "#alerts-prod"
  - name: new_crash
    condition: new_signature
    channel: "#alerts-prod"
  - name: p0
    condition: tag == "p0"
    channel: "#alerts-p0"

Workflow d'incident response

Voici le workflow recommandé pour une équipe mature.

  • Détection : alerte Slack / on-call paging.
  • Triage : qualifier la sévérité (P0 à P3).
  • Investigation : ouvrir le crash dans SnapLogs, lire les breadcrumbs.
  • Mitigation : rollback, feature flag, hotfix.
  • Communication : status page, message aux users.
  • Résolution : fix, test, deploy.
  • Post-mortem : doc rédigé dans les 72h.

Exemple d'alerte Slack

{
  "severity": "P0",
  "title": "Payment crash spike",
  "count": 234,
  "window": "5min",
  "fingerprint": "payment_charge_provider_declined",
  "last_stack": "package:app/payment.dart:128",
  "dashboard_url": "https://app.snaplogs.pro/incidents/abc123"
}

Workflow post-mortem

Le post-mortem est obligatoire pour tout incident P0/P1. Template :

### Incident : Payment crash spike 2026-08-09

### Impact
- 234 users affectés
- ~12k€ de revenu perdu
- 4h de downtime partiel

### Timeline
- 11:03 : premier crash
- 11:08 : alerte Slack
- 11:10 : on-call ack
- 11:15 : investigation, root cause identifiée
- 11:30 : feature flag désactivé
- 11:45 : hotfix déployé
- 12:00 : résolution

### Root cause
Le provider de paiement a changé son API sans notice.
Le champs `currency` est devenu obligatoire.
Notre code ne l'envoyait pas pour EUR (défaut).

### Fix
- Ajout du champs currency dans tous les calls.
- Test ajouté (payment_eur_test.dart).
- Alert ajoutée sur tout 500 provider.

### Lessons
- Toujours logger le payload envoyé au provider (censuré).
- Ajouter un contract test sur l'API provider.
- Monitorer les 500 provider comme des P1.

Redéploiement et rollback

Hotfix

Pour un hotfix Flutter :

git checkout -b hotfix/payment-currency
# fix
flutter test
flutter build apk --release --obfuscate --split-debug-info=./build/symbols
npx snaplogs symbols upload --path=./build/symbols --version=1.4.3
# deploy

N'oubliez pas d'uploader les symbols : sinon les nouveaux crashes ne seront pas symbolisables.

Rollback

Si le hotfix aggrave, rollback à la version N-1 :

# Play Store : rollback via console
# App Store : pas de rollback, mais on peut expedier l'ancienne version en review express

Préparez toujours un rollback avant de déployer un hotfix sur un flux critique.

Feature flags

Le vrai game changer est le feature flag. Au lieu de redéployer, désactivez le feature :

if (await FeatureFlags.isEnabled('new_payment_flow')) {
  await newPaymentFlow();
} else {
  await legacyPaymentFlow();
}

SnapLogs s'intègre avec LaunchDarkly, Flagsmith, ou un système maison via webhook. Voyez la documentation.

Case study : debug d'un crash iOS en production

Contexte

App Flutter e-commerce, 200k DAU. Crash iOS 16.4 uniquement, sur iPhone 14 Pro. Android stable.

Étape 1 : qualifier

SnapLogs dashboard : 89 crashes en 2h, tous iOS 16.4, tous iPhone 14 Pro. P0.

Étape 2 : lire les breadcrumbs

T 12:04:31 NAV push /product/42
T 12:04:32 NET GET /products/42 → 200
T 12:04:32 TAP "Add to cart"
T 12:04:32 NAV push /cart
T 12:04:33 CRASH EXC_BAD_ACCESS

Le crash survient à l'ouverture du cart, après ajout au panier.

Étape 3 : lire la stack

#0  CartScreen.build (package:app/cart.dart:84)
#1  StatelessElement.build (package:flutter/.../widget.dart:512)
#2  ComponentElement.performRebuild (package:flutter/.../widget.dart:432)

Le crash est dans cart.dart:84. Code :

Widget build(BuildContext context) {
  final item = cart.items.firstWhere((i) => i.id == lastAddedId); // ligne 84
  return Text(item.title);
}

firstWhere throw si l'item n'existe pas. Mais c'est un StatelessWidget reconstruit à chaque push, et lastAddedId peut être null.

Étape 4 : reproduire

Sur iPhone 14 Pro simulator, iOS 16.4 : on reproduit au 3e essai. Sur Android : jamais. Pourquoi ? iOS 16.4 a un timing de rebuild légèrement différent qui expose la race condition.

Étape 5 : fix

final item = cart.items.where((i) => i.id == lastAddedId).firstOrNull;
if (item == null) {
  return const SizedBox.shrink();
}
return Text(item.title);

Plus test :

test('Cart handles missing item gracefully', () {
  final cart = Cart(items: []);
  cart.lastAddedId = 'unknown';
  expect(() => buildCartWidget(cart), returnsNormally);
});

Étape 6 : déployer

Hotfix 1.4.3, symbols uploadés, deploy. Crashes tombent à 0 en 1h.

Étape 7 : post-mortem

Documenté. Lesson : toujours utiliser firstOrNull plutôt que firstWhere sur des collections mutables.

Intégration SnapLogs pour le debug production

Voici la configuration complète recommandée.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:snaplogs/snaplogs.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await SnapLogs.init(
    apiKey: const String.fromEnvironment('SNAPLOGS_KEY'),
    environment: 'production',
    sampleRate: 0.05,
    errorSampleRate: 1.0,
    captureLayoutWarnings: true,
    redactPatterns: [
      r'\b[\w.]+@[\w.]+\b',
      r'\b\d{16}\b',
      r'\b[A-Z]{2}\d{2}[A-Z0-9]{12,30}\b',
    ],
    beforeSend: (event) {
      if (event.tags['flow'] == 'health_check') return null;
      return event;
    },
  );

  FlutterError.onError = (details) {
    FlutterError.presentError(details);
    SnapLogs.captureException(
      details.exception,
      stackTrace: details.stack,
      tags: {'flow': 'framework'},
    );
  };

  runZonedGuarded<Future<void>>(() async {
    runApp(const MyApp());
  }, (Object error, StackTrace stack) {
    SnapLogs.captureException(
      error,
      stackTrace: stack,
      tags: {'flow': 'async'},
    );
  });

  Isolate.current.addErrorListener(
    RawReceivePort((dynamic pair) {
      final List<dynamic> data = pair as List<dynamic>;
      SnapLogs.captureException(
        data.first as Object,
        stackTrace: data.last as StackTrace,
        tags: {'flow': 'isolate'},
      );
    }).sendPort,
  );
}

Avec cette config, vous captez :

  • Toutes les exceptions framework, async, isolate.
  • Les breadcrumbs et logs structurés en contexte.
  • Les crashes obfusqués, symbolisés côté serveur.
  • Les alertes Slack sur pics et nouveaux crashes.

Outils complémentaires

Sentry (crash natif deep)

Pour les crashes NDK ou les kernel panics, Sentry est plus profond. SnapLogs + Sentry = couverture maximale.

Firebase Performance

Pour le jank et la latence réseau, Firebase Performance est pertinent.

n8n (incident automation)

SnapLogs peut déclencher un workflow n8n à chaque incident :

  • Créer un ticket Linear.
  • Pager l'on-call.
  • Mettre à jour une status page.

Voyez la doc d'intégration n8n.

Stratégies de mitigation sans redéploiement

Le redéploiement iOS prend 24-48h en review App Store. Pour les P0, c'est trop long. Voici les stratégies de mitigation sans redeploy.

Feature flags

Le feature flag est la première arme. Désactivez le feature buggy à distance :

final isEnabled = await FeatureFlags.isEnabled('new_checkout_flow');
if (isEnabled) {
  await newCheckoutFlow();
} else {
  await legacyCheckoutFlow();
}

SnapLogs s'intègre avec LaunchDarkly, Flagsmith, ou un système maison. Désactiver un flag prend 10 secondes, contre 24h pour un redeploy.

Remote config

Pour les valeurs (seuils, timeouts, URLs), utilisez le remote config :

final timeout = await RemoteConfig.getInt('payment_timeout_ms', defaultValue: 5000);
await api.post('/charge', body: {...}).timeout(Duration(milliseconds: timeout));

Si l'API est lente, montez le timeout à 10s via remote config, sans redeploy.

Kill switches

Pour les flows critiques, ajoutez un kill switch :

if (await FeatureFlags.isEnabled('payment_enabled')) {
  await paymentFlow();
} else {
  await showMaintenanceScreen();
}

En cas de bug majeur, désactivez le flow entier et affichez un message.

Hot patching (avancé)

Pour les équipes matures, le hot patching (code push sans review) existe sur Android (via CodePush React Native, ou des solutions maison Flutter). iOS est plus restrictif, mais des solutions comme Shorebird (Flutter) émergent. SnapLogs s'intègre avec Shorebird pour tracer les versions patchées séparément.

Case study : debug d'un bug de performance en production

Le debug production ne se limite pas aux crashs. Les bugs de perf (jank, lent, freeze) sont tout aussi critiques et souvent plus difficiles à diagnostiquer.

Contexte

App Flutter fitness, 500k DAU. Les utilisateurs se plaignent d'un écran « qui lag ». Pas de crash, pas d'erreur. Difficile à diagnostiquer car subjectif.

Étape 1 : instrumenter

Ajout d'un timer sur l'écran suspecté :

class WorkoutScreen extends StatefulWidget {
  const WorkoutScreen({super.key});

  @override
  State<WorkoutScreen> createState() => _WorkoutScreenState();
}

class _WorkoutScreenState extends State<WorkoutScreen> {
  DateTime? _frameStart;

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

  void _trackFrames() {
    WidgetsBinding.instance.addPersistentFrameCallback((_) {
      final now = DateTime.now();
      if (_frameStart != null) {
        final duration = now.difference(_frameStart!);
        if (duration.inMilliseconds > 100) {
          SnapLogs.log(
            level: LogLevel.warning,
            message: 'slow_frame',
            fields: {'duration_ms': duration.inMilliseconds, 'screen': 'workout'},
          );
        }
      }
      _frameStart = now;
    });
  }

  @override
  Widget build(BuildContext context) => const Scaffold(body: Center(child: Text('Workout')));
}

Étape 2 : collecter

Après 24h, SnapLogs reçoit 12k slow_frame warnings. Tous sur l'écran workout. Durée médiane : 180ms (au lieu de moins de 16ms pour 60fps).

Étape 3 : lire les breadcrumbs

Le breadcrumbs type avant un slow_frame :

T 12:04:31 NAV push /workout
T 12:04:32 NET GET /exercises → 200 (1.2s)
T 12:04:32 slow_frame duration_ms=180
T 12:04:33 slow_frame duration_ms=210
T 12:04:34 slow_frame duration_ms=190

Le slow frame arrive juste après le GET /exercises qui prend 1.2s. Hypothèse : le parsing JSON bloque l'UI thread.

Étape 4 : confirmer

DevTools en profile mode confirme : 800ms de parsing JSON sur l'UI thread pendant la navigation.

Étape 5 : fix

Isoler le parsing dans un isolate :

Future<List<Exercise>> fetchExercises() async {
  final response = await http.get(Uri.parse('https://api.example.com/exercises'));
  return await compute(_parseExercises, response.body);
}

List<Exercise> _parseExercises(String body) {
  final json = jsonDecode(body) as List<dynamic>;
  return json.map((e) => Exercise.fromJson(e as Map<String, dynamic>)).toList();
}

Le compute fait tourner le parsing dans un isolate séparé. L'UI thread n'est plus bloqué.

Étape 6 : mesurer

Après le fix, les slow_frame warnings tombent de 12k/jour à 200/jour (bruit de fond). Le bug est résolu sans aucune plainte supplémentaire.

Lesson

Sans instrumentation, ce bug serait resté invisible. Les users se plaignaient subjectivement, sans stack, sans erreur. Avec SnapLogs, le bug est devenu mesurable, puis résolvable.

Case study : bug intermittent de panier

Contexte

App Flutter e-commerce. 0.3% des paniers se vident aléatoirement. Pas de crash, pas d'erreur visible.

Étape 1 : instrumenter le panier

void addToCart(Item item) {
  _cart.add(item);
  SnapLogs.log(
    level: LogLevel.info,
    message: 'cart_add',
    fields: {
      'item_id': item.id,
      'count': _cart.length,
      'session_id': sessionId,
      'total': _cartTotal,
    },
  );
}

void removeFromCart(String itemId) {
  _cart.removeWhere((i) => i.id == itemId);
  SnapLogs.log(
    level: LogLevel.info,
    message: 'cart_remove',
    fields: {
      'item_id': itemId,
      'count': _cart.length,
      'session_id': sessionId,
      'total': _cartTotal,
    },
  );
}

void clearCart(String reason) {
  _cart.clear();
  SnapLogs.log(
    level: LogLevel.warning,
    message: 'cart_clear',
    fields: {'reason': reason, 'session_id': sessionId},
  );
}

Étape 2 : analyser

Après 48h, SnapLogs montre une séquence récurrente :

cart_add  item=A count=1
cart_add  item=B count=2
cart_add  item=C count=3
auth_token_refresh
cart_clear reason=auth_reset

Le clear survient juste après un refresh du token d'auth. Le coupable : la fonction refreshToken appelle clearCart('auth_reset') par erreur, copiée d'un vieux code.

Étape 3 : fix

Retirer l'appel clearCart dans refreshToken. Ajouter un test :

test('refreshToken does not clear cart', () async {
  final cart = Cart()..add(Item(id: 'A'));
  await refreshToken();
  expect(cart.items.length, 1);
});

Lesson

Un bug sans erreur ni crash est invisible aux crash reporters. Seul le logging structuré permet de remonter la séquence d'événements qui révèle la cause.

Gestion des crashes sur Flutter Web

Flutter Web a des particularités. Les crashes se traduisent par :

  • Erreurs JavaScript capturées par window.onerror.
  • CORS errors (souvent silencieuses côté client).
  • Layout overflow (invisible en console).

Pour capter les crashes web :

import 'dart:html' as html;

void setupWebErrorCapture() {
  html.window.onError.listen((html.Event event) {
    final errorEvent = event as html.ErrorEvent;
    SnapLogs.captureException(
      Exception(errorEvent.message),
      stackTrace: StackTrace.fromString(errorEvent.error ?? ''),
      tags: {'flow': 'web_window_error'},
    );
  });

  html.window.onUnhandledError.listen((event) {
    SnapLogs.captureException(
      event.error,
      stackTrace: event.stackTrace,
      tags: {'flow': 'web_unhandled'},
    );
  });
}

Les CORS errors nécessitent de logger le network côté Dart (pas seulement le browser), car le browser masque les détails CORS pour des raisons de sécurité.

Conclusion

Le debug Flutter en production n'est pas un art mystérieux. C'est un système. Les principes :

  • Instrumenter avant le bug : capture framework, async, isolate.
  • Symboliser : uploadez les symbols à chaque release.
  • Grouper : par signature et par fingerprint métier.
  • Prioriser : par volume, impact, récurrence.
  • Tracer les perfs : logs de durée sur les écrans et le réseau.
  • Alerter : pics, nouveaux crashes, P0.
  • Post-mortem : pour tout incident P0/P1.

SnapLogs intègre tous ces éléments dans un SDK unique. Pour adopter ce workflow :

Pour aller plus loin, voyez notre guide complet du bug report Flutter, notre comparatif des bug trackers, et notre guide du logging mobile moderne. Le debug production n'est pas une option : c'est ce qui sépare une app qui scale d'une app qui churn.

#flutter#debugging#errors#crash-reporting#performance#logs#testing

Articles liés

Des 9 EUR/mois, sans engagement

Annulez a tout moment. Mobile Money disponible en Afrique.

Voir les tarifs