Structured Logging este o abordare de înregistrare a logurilor în care fiecare mesaj este prezentat într-un format citibil de mașină cu perechi cheie-valoare, nu ca text nestructurat. Spre deosebire de șirurile plate, logurile structurate conțin metadate: timestamp, nivel, modul, identificatorul cererii — și pot fi indexate de sistemele de analiză. Conform datelor O'Reilly Effective Logging, trecerea la formatele structurate reduce timpul de găsire a unui incident de la ore la minute datorită posibilității de filtrare după câmpuri. Acesta este standardul de facto în dezvoltarea modernă mobilă și server: JSON și logfmt permit procesarea logurilor cu programe, nu cu ochiul.
Principalele
Structured Logging este o metodă de înregistrare a logurilor în care fiecare mesaj conține câmpuri denumite cu valori tipizate. În locul unui șir precum User 42 logged in from device ABC, un log structurat arată ca un set de câmpuri: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.
Principalul avantaj al logurilor structurate față de cele text este posibilitatea procesării programatice. Parsarea logurilor text necesită expresii regulate și presupuneri despre formatul șirului. Logurile structurate se parsează fără pierderi: fiecare câmp are un tip și un nume cunoscut, ceea ce permite construirea de interogări de tipul găsește toate erorile de autorizare din ultima oră pentru utilizatorul 42 fără procesare suplimentară.
Conform datelor Honeycomb.io (2023), echipele care folosesc structured logging în producție detectează incidente în medie de 4 ori mai rapid comparativ cu echipele care se bazează pe loguri text și grep.
Structured Logging suportă mai multe formate de serializare. Alegerea formatului depinde de infrastructură: JSON este convenabil pentru integrarea cu Elasticsearch și sistemele cloud, logfmt — pentru vizualizarea în consolă prin tail și grep, Protocol Buffers — pentru sisteme de înaltă performanță cu limitări de bandă.
| Format | Exemplu | Când se utilizează |
|---|---|---|
| JSON | {"event":"login","user_id":42} | ELK Stack, colectoare cloud, microservicii |
| Logfmt | event=login user_id=42 duration_ms=150 | Consolă, tail, heroku logs |
| MessagePack | Echivalent binar JSON | Sisteme cu încărcare mare, IoT |
JSON este cel mai răspândit format pentru loguri structurate. Este suportat nativ de toate sistemele de colectare: Logstash, Fluentd, Amazon CloudWatch, Google Cloud Logging. Logurile JSON sunt ușor de citit de om și parsat de orice limbaj de programare fără biblioteci suplimentare. Principalul dezavantaj — redundanța: fiecare pereche cheie-valoare necesită ghilimele și două puncte, ceea ce crește volumul datelor stocate cu 30–50% comparativ cu logfmt.
Logfmt a fost dezvoltat la Heroku pentru vizibilitate în consolă. Este mai compact decât JSON, păstrează lizibilitatea umană și se trunchiază ușor cu cut și awk. Exemplu: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt nu necesită escaparea majorității caracterelor și este potrivit pentru logarea stdout în containere.
În aplicațiile mobile Structured Logging rezolvă trei sarcini cheie: găsirea cauzelor crash-urilor fără reproducere pe dispozitiv, urmărirea sesiunilor utilizatorilor și analiza performanței pe versiuni ale aplicației.
Logurile text pe dispozitivele mobile sunt aproape inutile — dezvoltatorul nu poate grep-ui loguri pe dispozitivul utilizatorului. Logurile structurate sunt trimise în sistemele cloud (Firebase, Sentry, Datadog) și acolo sunt indexate. Se poate construi o interogare: arată toate crash-urile pe iOS 17.4, versiunea aplicației 3.2, în modulul checkouts — și se obține o selecție exactă în câteva secunde.
Conform datelor Sentry (2024), aplicațiile care folosesc structured breadcrumbs au cu 60% mai mult context în fiecare raport de crash comparativ cu aplicațiile care loghează doar textul erorii. Acest lucru influențează direct viteza de remediere a bug-ului.
ELK Stack — Elasticsearch, Logstash, Kibana — rămâne infrastructura standard pentru lucrul cu loguri structurate. Logstash primește logurile în JSON, le transformă și le trimite în Elasticsearch pentru indexare, Kibana oferă interfață vizuală pentru interogări și dashboard-uri.
Pentru aplicații mobile sunt populare soluțiile cloud: Firebase Crashlytics cu loguri personalizate, Sentry cu breadcrumbs, Datadog cu urmărire APM. Acestea primesc loguri structurate direct din SDK-ul mobil și nu necesită implementarea unui backend propriu. Firebase oferă un pachet gratuit pentru raportarea crash-urilor, Sentry adaugă distributed tracing, iar Datadog se integrează cu APM pentru urmărirea performanței cererilor pe client și server simultan.
Grafana Loki — alternativă la Elasticsearch, optimizată pentru loguri. Loki nu indexează conținutul mesajelor implicit, ci folosește etichete (labels) pentru filtrare. Acest lucru este semnificativ mai ieftin la stocare și mai rapid la interogări după un set fix de câmpuri.
// Structured logging prin Swift Logger în JSON
struct StructuredLog {
let event: String
let attributes: [String: Any]
let level: String
func serialize() -> String {
var base = "event=\(event) level=\(level)"
for (key, value) in attributes {
base += " \(key)=\(value)"
}
return base
}
}
Prima regulă a logării structurate: fiecare mesaj trebuie să conțină un identificator al cererii sau al sesiunii. Fără context, un singur log este inutil — nu se poate înțelege la ce utilizator sau cerere se referă. Adăugați correlation ID la începutul sesiunii și transmiteți-l prin toate straturile aplicației.
A doua regulă: tipizarea câmpurilor. Câmpurile numerice (duration_ms, status_code, retry_count) trebuie transmise ca numere, nu ca șiruri. Elasticsearch și sistemele similare indexează numerele și șirurile diferit: numerelor li se pot aplica agregări (medie, mediană, percentilă), șirurilor — căutare full-text. Tipizarea falsă elimină posibilitatea de a construi dashboard-uri analitice.
A treia regulă: evitați obiectele imbricate. Logurile JSON cu adâncimea de imbricare mai mare de 2 niveluri sunt dificil de filtrat și vizualizat. În loc de {"user": {"name": "Alice", "role": "admin"}} folosiți chei plate: user_name=Alice user_role=admin.
// Structured logging pe Android prin Timber + logfmt
class StructuredTree : Timber.Tree() {
override fun log(priority: Int, tag: String?,
message: String?, t: Throwable?) {
val level = priorityToLevel(priority)
val logfmt = "level=$level tag=$tag message=$message"
sendToRemote(logfmt)
}
}
Setul minim de câmpuri pentru fiecare mesaj structurat: timestamp în ISO 8601, level (debug/info/warn/error/fatal), logger (numele modulului sau clasei), message (descrierea evenimentului citibilă pentru om). Suplimentar: correlation_id, user_id (dacă este cunoscut), version (versiunea aplicației), platform (iOS/Android), environment (dev/staging/prod).
Fără correlation_id logurile structurate se transformă într-un set de înregistrări disparate care nu pot fi conectate într-un singur scenariu de utilizator. Generați un UUID la fiecare pornire a aplicației și adăugați-l în toate logurile sesiunii. În practică, correlation_id trebuie transmis prin toate straturile: de la evenimentele UI până la cererile de rețea și sarcinile de fundal — altfel o parte din loguri rămân fără context și nu vor participa în analitică. În urmărirea end-to-end, un singur UUID permite colectarea imaginii complete a parcursului utilizatorului.
Pe iOS logarea structurată poate fi implementată printr-un wrapper peste os_log care serializă câmpurile în format logfmt. Pe Android — prin Timber cu un Tree personalizat care transformă mesajele în JSON sau logfmt înainte de trimiterea pe server.
import OSLog
struct StructuredLogger {
let subsystem: String
let category: String
func log(level: OSLogType,
event: String,
context: [String: Any]) {
let oslogger = Logger(
subsystem: subsystem,
category: category
)
let fields = context.map {
"\($0.key)=\($0.value)"
}.joined(separator: " ")
oslogger.log(level: level,
"\(event) \(fields)")
}
}
Alegerea între logurile structurate și cele text depinde de etapa proiectului. În etapele incipiente de dezvoltare, logurile text sunt mai simple și mai rapide — dezvoltatorul scrie mesajul direct, fără wrapper-e suplimentare. Dar de îndată ce proiectul depășește limitele unei echipe sau ale unui server, logurile structurate devin obligatorii.
| Criteriu | Loguri text | Loguri structurate |
|---|---|---|
| Lizibilitate | Ridicată în consolă | Medie (necesită pretty-print) |
| Căutare | grep după subșir | Interogări după câmpuri și valori |
| Agregare | Nu este suportată | Medie, mediană, percentile |
| Integrare | Necesită parsare | Nativă în ELK/Loki/Datadog |
| Volum de stocare | Mai mic (fără metadate) | Mai mare (câmpuri + valori) |
Întrebări frecvente
Pentru trimiterea pe server folosiți JSON — este suportat nativ de Firebase Crashlytics, Sentry și Datadog. Pentru vizualizarea locală în logurile Xcode sau Android Studio folosiți logfmt — este mai compact și se citește fără formatare.
Da, logurile structurate pe client permit adăugarea de context la fiecare raport de crash: versiunea OS, starea rețelei, ultimele acțiuni ale utilizatorului. Fără breadcrumbs structurate, raportul de crash conține doar stiva de apeluri fără scenariul utilizatorului.
Logfmt este mai compact (volum cu 30–50% mai mic) și se citește mai ușor în terminal. JSON suportă obiecte imbricate și matrice, dar necesită escaparea ghilimelelor. Alegerea depinde de infrastructură: pentru ELK — JSON, pentru vizualizare în consolă — logfmt.
Creați o singură instanță UUID la pornirea aplicației, salvați-o într-un singleton sau container DI și transmiteți-o tuturor logger-elor prin constructor. Alternativa — utilizarea threading-local sau Continuation Local Storage în corutinele Kotlin.
Se poate, dar nu este recomandat — amestecarea pierde posibilitatea de indexare automată. Dacă o parte din loguri sunt text, ele trebuie parsat cu expresii regulate, ceea ce reduce performanța și fiabilitatea căutării. Mai bine să migrați toate logurile la format structurat.
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