Log Level — clasificarea mesajelor de logare după gradul de criticitate, permițând dezvoltatorilor să controleze volumul de informații afișate în diferite etape de funcționare a aplicației. Conform datelor Google Android Developers, 2024, alegerea corectă a nivelului de logare reduce volumul logurilor în producție cu 85–95% și accelerează diagnosticarea erorilor. Fiecare nivel își rezolvă sarcina — de la depanare în etapa de dezvoltare până la monitorizarea defecțiunilor critice în producție.
Principalele idei
Log Level — este un atribut al fiecărui mesaj de log care determină importanța și urgența procesării sale. Platformele moderne iOS și Android suportă o scară unitară de 6–7 niveluri: de la maxim de detaliat (Verbose/Trace) la critic (Error/Assert). Alegerea nivelului determină dacă mesajul va fi scris în log la configurația curentă a aplicației.
Conceptul de Log Level se bazează pe principiul piramidei de criticitate: cu cât nivelul este mai ridicat, cu atât mai puține mesaje sunt afișate la acel nivel. Conform datelor Semaphore CI, 2024, într-o aplicație de producție distribuția arată astfel: Info — 60% mesaje, Warn — 25%, Error — 10%, Debug — 5%. Mesajele Verbose trebuie să fie complet dezactivate în producție.
Fiecare platformă implementează Log Level prin propriul API. Android folosește android.util.Log cu metodele v(), d(), i(), w(), e(). Apple — OSLog cu nivelurile default, info, debug, error, fault. Bibliotecile precum Timber și CocoaLumberjack adaugă funcționalități suplimentare peste aceste API-uri standard.
Conform datelor Google I/O 2023, alegerea incorectă a Log Level este cauza a 40% din problemele de performanță în producție. Dezvoltatorii lasă logurile Debug în construcția release, ceea ce duce la scrierea excesivă pe disc și descărcarea accelerată a bateriei.
Verbose (TRACE) — cel mai detaliat nivel, destinat exclusiv dezvoltării. La acest nivel sunt afișate toate calculele intermediare, iterațiile buclelor, rezultatele fiecărui pas al algoritmului. Pe Android acest nivel corespunde cu Log.v(), pe iOS — OSLog cu tipul debug (înainte de iOS 14 se folosea os_trace).
Debug — mesaje de depanare utile în timpul dezvoltării și testării. Conțin informații despre starea obiectelor cheie, rezultatele interogărilor SQL, parametrii apelurilor API. Spre deosebire de Verbose, mesajele Debug sunt structurate și semnificative semantic. Pe iOS acest nivel corespunde cu OSLogType.debug.
Info — mesaje informative despre evenimentele normale ale aplicației: inițializarea SDK, autentificare reușită, deschiderea ecranului, primirea datelor de pe server. Mesajele Info nu trebuie să conțină date personale ale utilizatorilor și trebuie să fie sigure pentru analiza în producție. Pe iOS se folosește OSLogType.info, pe Android — Log.i().
Warn — avertismente despre probleme potențiale. Aplicația continuă să funcționeze, dar situația necesită atenție: dimensiunea cache-ului aproape de limită, versiunea învechită a API, răspuns lent al rețelei, încercare repetată de conectare. Pe Android — Log.w(), pe iOS — OSLogType.default (pentru avertismente).
Error — erori critice în care aplicația nu poate executa operația solicitată, dar continuă să funcționeze: cerere eșuată la API, pierderea conexiunii, eroare de scriere în baza de date, lipsa permisiunilor. Pe iOS pentru erori se folosește OSLogType.error, pe Android — Log.e().
Assert (WTF) — cel mai înalt nivel, care indică o situație „asta nu se poate întâmpla”. Folosit pentru logarea bug-urilor care încalcă invarianții fundamentali ai sistemului. Pe Android mesajele Assert nu sunt afișate în construcțiile release în mod implicit. Pe iOS, WTF (What a Terrible Failure) este procesat prin OSLogType.fault.
Android Log API — mecanismul încorporat de logare din pachetul android.util.Log. Oferă 6 metode statice: Log.v(), Log.d(), Log.i(), Log.w(), Log.e() și Log.wtf(). Fiecare metodă primește un tag (șir de identificare a sursei) și msg (textul mesajului).
class UserRepository {
companion object {
private val TAG = "UserRepo"
}
suspend fun loadUser(id: String): User {
Log.d(TAG, "Se încarcă utilizatorul cu id: $id")
return try {
val response = api.fetchUser(id)
Log.i(TAG, "Utilizator încărcat cu succes")
response.toUser()
} catch (e: Exception) {
Log.e(TAG, "Eroare la încărcarea utilizatorului: ${e.message}")
throw e
}
}
}
Filtrarea după niveluri în Android Logcat se realizează prin ADB: adb logcat *:E va afișa doar mesajele Error. În construcțiile de producție, toate apelurile Log.v() și Log.d() sunt eliminate de ProGuard/R8 când minificarea este activată. Log.i(), Log.w() și Log.e() rămân, deci este important să nu afișați date sensibile prin aceste metode.
Pentru filtrarea personalizată în runtime, Android oferă Log.isLoggable(tag, level) — o metodă care verifică dacă nivelul specificat este activat pentru tag-ul dat. Aceasta permite activarea dinamică a logării detaliate pentru un modul specific fără recompilarea aplicației.
OSLog — sistemul unificat de logare Apple, care a înlocuit NSLog-ul învechit. OSLog oferă 5 niveluri: debug, info, default (notice), error și fault. Principalul avantaj este logarea structurată cu suport pentru șiruri formatate și filtrare dinamică prin consolă.
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
func fetchData(from url: URL) {
logger.debug("Starting request to \(url.absoluteString)")
do {
let data = try Data(contentsOf: url)
logger.info("Received \(data.count) bytes")
} catch {
logger.error("Request failed: \(error.localizedDescription)")
}
}
Sistemul de filtrare OSLog funcționează la nivelul sistemului de operare. Mesajele Debug sunt scrise doar când debugger-ul este conectat sau când argumentul -com.apple.CoreData.Logging.debug 1 este activat. Mesajele Info sunt colectate în memoria dispozitivului (până la 512 KB) și sunt accesibile prin Console.app. Error și fault sunt scrise constant și sunt disponibile pentru colectare prin sistemele de raportare a crash-urilor.
O caracteristică importantă a OSLog: șiruri formatate cu placeholder-e. În loc de interpolarea șirurilor Swift (care este calculată întotdeauna, indiferent de nivel), OSLog folosește formatul os_log cu %{public}@ și %{private}@ pentru delimitarea datelor sensibile. Parametrii privați sunt mascați în logurile de producție.
Regula de bază — setul minim de niveluri în producție: Info, Warn, Error, Assert. Debug și Verbose trebuie dezactivate. Motivul nu este atât securitatea, cât performanța: fiecare apel de log consumă timp CPU pentru formatarea șirului, chiar dacă mesajul nu este afișat.
Optimizare critică — nu utilizați niciodată interpolarea șirurilor în apelurile de log. Dacă șirul este format înainte de apelul log(), timpul CPU este irosit chiar și când nivelul este dezactivat. Folosiți formatarea lentă prin lambde sau condiții de gardă.
În Android, acest scop este servit de metoda Log.isLoggable(), în OSLog — suportul nativ pentru șiruri formatate cu placeholder-e. Timber pentru Android rezolvă problema prin timber.log.Tree cu verificarea nivelului în interiorul arborelui.
Remote Log Level — practica în care nivelul de logare este controlat de pe server prin Firebase Remote Config sau un serviciu similar. Dacă în producție apare o eroare complexă, dezvoltatorul poate activa de la distanță logarea Debug pentru un modul specific pe dispozitivele unui grup selectat de utilizatori.
Conform datelor Firebase, 2024, această practică reduce timpul de diagnosticare a bug-urilor rare cu 60% și permite obținerea unei imagini complete a problemei fără a instala o construcție debug. Principala limitare este că logurile se activează doar la următoarea pornire a aplicației după primirea configurării.
BuildConfig.DEBUG pe Android și #if DEBUG în Swift — mecanisme standard de compilare condiționată care dezactivează nivelurile de depanare în construcțiile release. Pentru o arhitectură curată, se recomandă mutarea alegerii Log Level în containerul DI sau fabrica de logger-e, pentru a nu aglomera logica de business cu directive condiționate.
Prima regulă — fiecare apel de log trebuie să răspundă la întrebarea „cine, ce, când”. Cine — componentă sau modul (tag pe Android, category pe iOS). Ce — eveniment specific sau schimbare de stare. Când — marcaj temporal, stabilit automat de sistemul de logare.
A doua regulă — nu logați date sensibile prin Info și niveluri superioare. Parole, token-uri, emailuri, numere de telefon, coordonate geografice exacte — sunt strict interzise în orice log care ajunge în producție. La nevoie, folosiți mascarea: „email: us***@example.com”.
A treia regulă — nivelul Warn este zona de responsabilitate a dezvoltatorului, Error — a echipei. Warn înseamnă „aici este o problemă potențială, monitorizează”. Error — „aici este o problemă, repară”. Nu folosiți Error pentru situații care sunt așteptate și gestionate (de exemplu, eroarea API 404).
A patra regulă — consistență. Întregul proiect trebuie să folosească convenții unitare de denumire a tag-urilor și categoriilor. Se recomandă ClassName.methodName pentru tag-urile Android și module.subsystem pentru categoriile iOS. Aceasta permite filtrarea rapidă a logurilor după componentă.
A cincea regulă — testați logurile. În testele unitare, verificați că în scenarii specifice este apelat nivelul corect de Log Level. În acest scop există biblioteci de logare mock: Mockito pentru Android, Cuckoo pentru iOS. Verificarea nivelurilor în teste previne scurgerea mesajelor de depanare în producție.
Întrebări frecvente
Descărcarea accelerată a bateriei și scriere excesivă pe disc. Fiecare log Debug formatează șirul și scrie datele în buffer. Pe dispozitivele cu memorie Flash, aceasta accelerează uzura memoriei. În plus, logurile Debug pot conține date sensibile care nu sunt disponibile pentru vizualizare în producție.
Debug — pentru corpul cererii și răspunsului, anteturi și codul de stare. Info — pentru faptul executării cererii (URL, metodă, durată). Error — pentru cererile eșuate cu codul 4xx/5xx. Nu utilizați niciodată Verbose pentru logurile de rețea în producție.
OSLogType.default (nivelul notice) — mesaje de importanță medie, salvate în logul de sistem și vizibile în Console.app. OSLogType.info — mesaje tehnice, nu sunt salvate permanent, disponibile doar la profilare activă prin Instruments.
R8/ProGuard elimină Log.v() și Log.d() când minificarea este activată în construcția release. Log.i(), Log.w(), Log.e() sunt păstrate. Pentru eliminarea completă a tuturor logurilor este necesară o regulă personalizată -assumenosideeffects class android.util.Log cu specificarea tuturor nivelurilor.
Nu — logarea excesivă degradează lizibilitatea și performanța. Logați intrarea doar în metode complexe sau asincrone. Pentru metodele sincrone, un singur log în punctul de returnare sau eroare este suficient. Folosiți nivelul Debug pentru trasarea apelurilor.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și