Mobilni razvoj
FlutterObservabilnost mobilnih aplikacijaSentryFirebase CrashlyticsLogiranjePraćenje performansiMonitoringDevOps

Observabilnost Fluttera u produkciji: izvještavanje o rušenjima, logiranje i praćenje performansi

AO
Adrijan Omićević
·13 min čitanja

# Što ovaj vodič pokriva#

Observabilnost Flutter aplikacije u produkciji je razlika između nagađanja i stvarnog uvida. Kada korisnik kaže „aplikacija je spora” ili „srušila se”, trebate dovoljno konteksta da reproducirate problem, kvantificirate utjecaj i potvrdite ispravak.

Ovaj vodič se fokusira na to što instrumentirati u Flutter aplikaciji i kako to sigurno isporučiti: izvještavanje o rušenjima, izvještavanje o nefatalnim pogreškama, strukturirano logiranje, latenciju API-ja, vrijeme starta aplikacije i frame timinge. Uključuje i praktičnu usporedbu Crashlytics vs Sentry te checklistu za produkcijsko izdanje.

Za širi pogled na observabilnost kroz različite stackove, pogledajte naš vodič fokusiran na web: Observabilnost web aplikacija: logovi, metrike, tracing. Za Flutter-specifičan rad na performansama izvan samog monitoringa, pročitajte: Optimizacija performansi u Flutteru za 60fps. Za automatizaciju izdanja i upload simbola, koristite: Flutter CI CD s GitHub Actions, Codemagic i Fastlane.

# Zašto observabilnost Fluttera pada na stvarnim aplikacijama#

Većina timova doda crash reporting i stane na tome. To hvata fatalne crashove, ali propušta probleme koji u praksi najviše štete retentionu i prihodima.

Tipični produkcijski failure modeovi koje crash reporting sam po sebi neće riješiti:

  • Korisnici zapnu na loading stanju jer API poziv timeouta, a vi ste „progutali” iznimku.
  • Aplikacija se nakon izdanja „osjeća sporo” jer neki put rebuilda widgeta uzrokuje jank na mid-range Android uređajima.
  • Rollout poveća cold start za 400ms zbog skupog sinkronog init koraka.
  • Određeni backend endpoint postane spor samo u jednoj regiji, uzrokujući retryje i pražnjenje baterije.

Observabilnost brzo odgovara na tri pitanja:

  1. 1
    Što se dogodilo (error i stack trace, uz breadcrumbs).
  2. 2
    Koga pogađa (uređaj, OS, verzija aplikacije, postotak roll-outa).
  3. 3
    Koliko je loše (učestalost, pogođene sesije, distribucija latencije, dropani frameovi).

🎯 Ključna poruka: Produkcijski monitoring je koristan samo ako hvata signale i za ispravnost i za performanse: rušenja, nefatalne pogreške, latenciju API-ja, vrijeme starta i frame timinge.

# Što instrumentirati u Flutter produkciji#

Želite signale koji se poklapaju s korisničkom boli i rizikom izdanja. Najprije instrumentirajte ovih pet područja.

1) Rušenja: fatalne pogreške i native crashovi#

Hvatajte fatalne Dart iznimke i native crashove. U Flutteru „crash” može biti:

  • Native crash u iOS ili Android kodu, uključujući plugine.
  • Fatalna pogreška koja prekida proces.
  • Neobrađena Dart iznimka koja sruši aplikaciju ili je ostavi neupotrebljivom.

Minimalni zahtjevi:

  • Stack traceovi sa simbolikacijom i source mapovima.
  • Razdioba po uređajima i OS-ovima.
  • Verzija aplikacije i build broj.
  • Tagovi za release i okruženje: production, staging.

2) Nefatalne pogreške: incidenti koje korisnici prvo osjete#

Nefatalne pogreške često uzrokuju najgori UX. Hvatajte:

  • API greške koje obrađujete, ali ih ipak trebate promatrati: 401, 403, 500, timeoutovi.
  • Greške parsiranja JSON-a koje završe fallbackom na default vrijednosti.
  • Nedosljednosti business logike: nevažeći prijelazi stanja, nedostaju obavezna polja.
  • Greške pri plaćanju i kupnjama koje pokažu poruku „pokušajte ponovno”.

Umjesto da to tretirate kao obične logove, hvatajte ih kao evente sa strukturiranim metapodacima.

3) Latencija i pouzdanost API-ja: najbrži način da otkrijete backend incidente#

Instrumentirajte mrežne pozive sa:

  • Naziv endpointa ili route template, ne puni URL s id-jevima.
  • Metoda, status kod i tip greške.
  • Trajanje u milisekundama.
  • Broj retryja, ako postoji.

Pratite barem p50, p95 i p99 latenciju. U većini consumer aplikacija, primjetna regresija UX-a često kreće oko p95, a ne oko prosjeka.

⚠️ Upozorenje: Nemojte logirati request bodyje ili auth headere u observability alate. To je čest compliance i sigurnosni propust, posebno s tokenima i osobnim podacima.

4) Vrijeme starta aplikacije: cold start i vrijeme do prvog ekrana#

Korisnici odmah primijete sporo pokretanje. Pratite:

  • Trajanje cold starta: od starta procesa do prvog renderanog framea.
  • Vrijeme do prvog smislenog ekrana, često nakon autentikacije i inicijalnih API poziva.

Povežite startup regresije s verzijom aplikacije i klasom uređaja. Regresija od 200ms može biti nevidljiva na flagship uređaju, ali bolna na 4 godine starom Androidu.

5) Frame timinzi: jank, dropani frameovi i trzaji#

Metrike frame timinga direktno mapiraju na „aplikacija šteka”. Pratite:

  • Frame timeove raster i UI threada.
  • Broj sporih frameova po sesiji.
  • Spikove povezane s promjenama ruta ili teškim ekranima.

Ako aktivno optimizirate rendering pathove, uparite monitoring s praksama iz Optimizacija performansi u Flutteru za 60fps.

# Crashlytics vs Sentry za Flutter: praktična usporedba#

Oba alata rješavaju crash reporting. Razlika je u tome koliko idu dalje od toga i koliko se dobro uklapaju u vaš workflow.

ZnačajkaFirebase CrashlyticsSentry
Brzina postavljanjaVrlo brzo ako već koristite FirebaseBrzo, jedan SDK, ali više opcija
Kvaliteta crash reportingaOdličnaOdlična
Hvatanje nefatalnih pogrešakaDobroOdlično, fleksibilnije
Praćenje performansiZaseban proizvod u Firebase ekosustavuUgrađeno, traceovi i spanovi
Praćenje releasovaOsnovnoSnažno: releases, commitovi, deploy tracking
Source mapovi i simbolikacijaPodržanoSnažna podrška i workflow
BreadcrumbsOgraničenoSnažno, automatsko i custom
Alerting i issue workflowOsnovnoSnažniji triage, assignment, kontrola groupinga
Model cijenaČesto povoljan u manjem opseguMože postati skupo uz velik volumen eventova
Najbolje odgovaraTimovima na Firebaseu kojima prvo treba crash reportingTimovima kojima treba end-to-end observabilnost i bolji kontekst za debug

Kada je Crashlytics pravi izbor#

Odaberite Crashlytics ako:

  • Već ste snažno investirani u Firebase i želite najkraći put do pouzdanih crash reportova.
  • Primarno trebate fatal crash reporting uz malo nefatalnog logiranja.
  • Vaš tim preferira jednostavniji UI i manje konfiguracijskih odluka.

Kada je Sentry pravi izbor#

Odaberite Sentry ako:

  • Želite jedno mjesto za greške, performanse, releasove i bogatiji kontekst.
  • Trebate bolje grupiranje issueova i workflow, posebno kroz više aplikacija i okruženja.
  • Želite instrumentirati custom spanove za API pozive, start aplikacije i navigaciju bez spajanja više proizvoda.

ℹ️ Napomena: Firebase ima i Firebase Performance Monitoring, koji može pokriti dio potreba za latencijom i startupom. U praksi, timovi često primijete da Sentryjev objedinjeni pristup „greške + performanse + releasovi” skraćuje vrijeme do dijagnostike jer je kontekst priložen uz isti stream issueova.

# Koraci integracije: Firebase Crashlytics u Flutteru#

Ovaj dio pretpostavlja da već imate postavljen Firebase. Ako nemate, krenite dodavanjem Firebasea na iOS i Android te generiranjem config datoteka.

Korak 1: Dodajte pakete i inicijalizirajte Firebase#

Dodajte ovisnosti:

YAML
# pubspec.yaml
dependencies:
  firebase_core: ^3.0.0
  firebase_crashlytics: ^4.0.0

Inicijalizirajte i povežite globalne error handlere:

Dart
// main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
 
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
 
  FlutterError.onError = (details) {
    FirebaseCrashlytics.instance.recordFlutterFatalError(details);
  };
 
  PlatformDispatcher.instance.onError = (error, stack) {
    FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
    return true;
  };
 
  runZonedGuarded(() {
    runApp(const MyApp());
  }, (error, stack) {
    FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
  });
}

Korak 2: Hvatajte nefatalne pogreške s kontekstom#

Primjer za API greške koje obrađujete u UI-ju:

Dart
await FirebaseCrashlytics.instance.recordError(
  Exception('API request failed'),
  StackTrace.current,
  reason: 'GET /v1/orders timed out',
  fatal: false,
  information: ['endpoint=/v1/orders', 'timeoutMs=15000', 'retry=1'],
);

Korak 3: Dodajte ključeve za brži triage#

Ključevi omogućuju filtriranje issueova po tipu korisnika, feature flagovima ili okruženju.

Dart
await FirebaseCrashlytics.instance.setCustomKey('env', 'production');
await FirebaseCrashlytics.instance.setCustomKey('feature_checkout', true);
await FirebaseCrashlytics.instance.setCustomKey('api_region', 'eu-central-1');

Korak 4: Provjerite simbolikaciju i mapping#

Crash reportovi bez simbolikacije troše vrijeme. Provjerite da:

  • iOS dSYM-ovi budu uploadani za svaki release build.
  • Android mapping datoteke budu uploadane ako koristite R8 ili ProGuard.

To je najbolje rješavati u CI-u. Koristite workflow uzorke iz Flutter CI CD s GitHub Actions, Codemagic i Fastlane.

💡 Savjet: Tretirajte upload simbola kao blokirajući korak builda. Ako upload simbola padne, neka padne i pipeline. To je jeftinije nego debugiranje nesimboliciranih crashova nakon izdanja.

# Koraci integracije: Sentry u Flutteru#

Sentry vam daje greške plus performanse i vidljivost releasova s jednim SDK-om.

Korak 1: Dodajte Sentry Flutter paket#

YAML
# pubspec.yaml
dependencies:
  sentry_flutter: ^9.0.0

Inicijalizirajte Sentry rano:

Dart
// main.dart
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
 
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
 
  await SentryFlutter.init(
    (options) {
      options.dsn = 'https://YOUR_DSN';
      options.environment = 'production';
      options.tracesSampleRate = 0.1;
      options.profilesSampleRate = 0.0;
    },
    appRunner: () => runApp(const MyApp()),
  );
}

Korak 2: Hvatajte nefatalne pogreške i dodajte tagove#

Dart
try {
  // risky operation
} catch (e, st) {
  await Sentry.captureException(
    e,
    stackTrace: st,
    withScope: (scope) {
      scope.setTag('feature', 'checkout');
      scope.setTag('endpoint', '/v1/orders');
      scope.setExtra('timeoutMs', 15000);
    },
  );
}

Korak 3: Instrumentirajte latenciju API-ja sa spanovima#

Koristite spanove oko mrežnih poziva. Imena držite stabilnima, koristeći route templateove.

Dart
final transaction = Sentry.startTransaction('api', 'http.client');
 
try {
  final span = transaction.startChild('http', description: 'GET /v1/orders');
  final sw = Stopwatch()..start();
 
  final response = await client.get(uri);
 
  sw.stop();
  span.setData('statusCode', response.statusCode);
  span.setData('durationMs', sw.elapsedMilliseconds);
  await span.finish();
} finally {
  await transaction.finish();
}

Korak 4: Instrumentirajte start aplikacije i navigaciju#

Sentry podržava praćenje starta aplikacije i može hvatati navigation breadcrumbs. Za custom startup milestoneove, napravite startup transaction i dodajte spanove za init korake.

Primjeri milestoneova za praćenje:

  • Vrijeme čitanja secure storagea
  • Vrijeme refreshanja tokena
  • Vrijeme dohvaćanja inicijalne konfiguracije
  • Vrijeme do prvog ekrana

Korak 5: Upload debug simbola i source mapova u CI-u#

Za dobre stack traceove u release modu, uploadajte:

  • iOS dSYM-ove
  • Android ProGuard mappinge
  • Dart source mapove, ovisno o buildu i Sentry postavkama

Automatizirajte to u CI-u zajedno s buildom i deployem. Referenca: Flutter CI CD s GitHub Actions, Codemagic i Fastlane.

# Strategija logiranja: učinite logove korisnima i sigurnima#

Logovi su i dalje važni, ali samo ako su strukturirani, pretraživi i nisu preglasni.

Što logirati#

Logirajte događaje koji objašnjavaju ponašanje koje utječe na korisnika:

  • Auth tranzicije: login, logout, greške pri refreshanju tokena.
  • API lifecycle: start, sažetak odgovora, broj retryja.
  • Feature flagovi i remote config vrijednosti na početku sesije.
  • Lifecycle aplikacije: background, foreground, terminated.
  • Plaćanja i kupnje: result kodovi i kategorije grešaka.

Kako logirati: strukturirano i uz sampling#

Izbjegavajte sirove, nestrukturirane stringove. Koristite konzistentnu shemu i prilažite mala metadata polja.

PoljePrimjerZašto je važno
eventapi_request_failedOmogućuje filtriranje i dashboarde
endpoint/v1/ordersAgregira preko id-jeva
statusCode504Razdvaja pouzdanost od grešaka logike
durationMs15342Korelacija latencije
retryCount1Objašnjava spikove i utjecaj na bateriju
appVersion2.8.1Otkriva regresije po izdanju

Pravila redakcije koja trebate provoditi#

U najmanju ruku redaktirajte:

  • Authorization headere i tokene
  • Email adrese i brojeve telefona
  • Puni URL s query parametrima ako sadrže identifikatore
  • Request i response bodyje, osim ako su eksplicitno scrubani

Ovo je važno jer observability alati postaju spremišta podataka. Tretirajte ih kao produkcijske sustave podataka, s istim očekivanjima oko usklađenosti kao i vaš backend.

# Praćenje performansi: što pratiti i kako izgleda „dobro”#

Rad na performansama bez mjerenja je nagađanje. Pratite mali set metrika konzistentno.

Ciljevi za latenciju API-ja#

Ciljevi ovise o proizvodu, ali praktični pragovi za consumer aplikacije:

  • p50 ispod 300ms za čitanja koja su česta na dobrim mrežama
  • p95 ispod 1.5s za interaktivne endpointe
  • Timeoutovi ispod 1 posto zahtjeva po endpointu

Ako p95 raste dok p50 ostaje stabilan, vjerojatno imate probleme s tail latencijom, regionalne probleme ili contention na serveru.

Ciljevi za start aplikacije#

Ciljevi za cold start ovise o uređaju. Ono što želite je:

  • Bez regresija između izdanja
  • Stabilan startup na mid-tier uređajima
  • Vidljivost koji je init korak postao sporiji

Odvojeno pratite „time to first frame” i „time to first meaningful screen”. Česta greška je optimizirati prvi frame, dok i dalje blokirate smisleni UI sinkronim pozivima.

Ciljevi za frame timinge#

Ako ciljate 60Hz uređaje, želite većinu frameova ispod ~16ms. Na 120Hz uređajima prag je stroži, ali cilj je konzistentnost i nizak jank.

Koristite frame timinge da odgovorite na:

  • Koje rute ili ekrani koreliraju sa spikovima janka?
  • Je li izdanje povećalo broj sporih frameova po sesiji?
  • Postoje li device-specifični uzorci janka, npr. low-end Android GPU-ovi?

Za tehnike smanjenja janka, pogledajte Optimizacija performansi u Flutteru za 60fps.

# Alerting: pretvorite signale u akciju bez pager fatiguea#

Želite alarme koji odražavaju stvarni utjecaj na korisnike. Praktičan baseline:

  • Crash-free sessions ispod praga, npr. 99.5 posto za consumer aplikacije i 99.9 posto za kritične flowove.
  • Novi crash uveden u novom releaseu, alarm odmah.
  • Regresija API p95 veća od 30 posto za ključne endpointe kroz 15 minuta.
  • Stopa timeoutova veća od 1 posto za kritičan endpoint.

Vlasništvo nad alertima držite jasnim: app tim je vlasnik client crashova i janka, backend tim je vlasnik latencije endpointa i error ratea, ali triage treba raditi na jednom mjestu.

# Checklist za produkcijski monitoring prije izdanja#

Koristite ovu checklistu prije svakog izdanja. Sprječava situaciju „shipali smo, ali ne možemo debugirati”.

StavkaZašto je važnoKriterij prolaza
Crash reporting uključen u release buildovimaOsigurava da se stvarna rušenja hvatajuTestni crash se pojavi na dashboardu
Hvatanje nefatalnih pogrešaka u kritičnim flowovimaSprječava tihe kvaroveAPI failurei se vide s endpoint tagovima
Uploadani simboli i mapping datotekeOmogućuje čitljive stack traceoveCrash u releaseu prikazuje točnu datoteku i liniju
Postavljeni environment i release tagoviRazdvaja staging od produkcijeDashboard može filtrirati po env-u i verziji
Provjerena redakcija PII-jaSprječava curenje podatakaNema tokena, emailova ni bodyja u eventovima
Konfiguriran sampling performansiKontrolira trošak i overheadtracesSampleRate postavljen i validiran
Instrumentirani ključni endpointiRano otkriva backend incidenteLatencija dostupna za top endpointe
Praćenje starta aplikacijeSprječava startup regresijePostoji baseline za cold start
Praćenje frame timinga na ključnim ekranimaHvata jank regresijePrati se stopa sporih frameova po ruti
Alerti konfigurirani i testiraniOsigurava brzu reakcijuTestni alert dođe na pravi kanal
CI automatizira release metapodatkeSmanjuje ljudske greškePipeline uploada simbole i označi release

💡 Savjet: Napravite staged rollout na jedan do pet posto korisnika i pratite crash-free sessions, API p95 i spore frameove barem 30 do 60 minuta prije širenja.

# Ključne poruke#

  • Instrumentirajte više od crashova: hvatajte nefatalne pogreške, latenciju API-ja, vrijeme starta aplikacije i frame timinge da pokrijete stvarnu korisničku bol.
  • Odaberite primarni alat: Crashlytics za brz Firebase-first crash reporting, Sentry za bogatiji kontekst uz performanse i vidljivost releasova.
  • Koristite strukturirane logove i stroga pravila redakcije kako biste izbjegli šum i curenje podataka.
  • Automatizirajte upload simbola i mappinga u CI-u kako bi svako izdanje bilo moguće debugirati u produkciji.
  • Isporučujte uz monitoring checklistu i staged rollout gateove kako biste rano uhvatili regresije.

# Zaključak#

Produkcijska observabilnost u Flutteru nije „nice-to-have”. To je sustav koji vam govori je li izdanje sigurno, koji su korisnici pogođeni i što prvo popraviti.

Ako želite pomoć pri postavljanju lean observability stacka za vašu Flutter aplikaciju, uključujući integraciju Sentryja ili Crashlyticsa, instrumentaciju performansi i CI automatizaciju, javite se Samiodi. Implementirat ćemo monitoring, definirati alarme i isporučiti checklistu za izdanje koju vaš tim može koristiti svaki put.

FAQ

Share
A
Adrijan OmićevićOsnivač i senior developer

Osnivač i senior developer u Samiodi. 8+ godina iskustva u izradi React, Next.js, Flutter i n8n rješenja za klijente diljem Europe.

Trebate pomoć s projektom?

Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.