os_log — este API-ul unified logging de la Apple pentru iOS și macOS, care a înlocuit NSLog și os_trace. Spre deosebire de mecanismele vechi, os_log funcționează la nivel de kernel: mesajele sunt bufferate într-un buffer circular și scrise pe disc doar la atingerea pragului de activitate. Conform datelor Apple WWDC 2016, os_log reduce încărcarea discului de 10 ori comparativ cu NSLog și oferă control asupra nivelului de detaliere prin categorii și tipuri. Este instrumentul principal de diagnosticare pentru dezvoltatorul iOS: prin Console.app se pot filtra mesajele după proces, categorie și nivel de criticitate în timp real.
Principalele puncte
os_log — este API-ul unified logging introdus de Apple în iOS 10 și macOS Sierra. A unit mecanismele de logare dispersate NSLog, os_trace și syslog într-un singur sistem cu bufferizare la nivel de kernel XNU.
Spre deosebire de NSLog, care scrie sincron fiecare mesaj pe disc și blochează firul de execuție, os_log utilizează un buffer circular asincron în memorie. Mesajele sunt descărcate pe disc doar când activitatea depășește un prag stabilit sau la comanda log collect. Aceasta reduce radical impactul logării asupra performanței aplicației.
os_log suportă șase niveluri de criticitate, diferențierea după subsystem și category, precum și un mecanism încorporat de confidențialitate: datele marcate ca private sunt mascate automat în logurile de producție și sunt accesibile doar dezvoltatorului la conectarea Xcode.
Înainte de iOS 10, dezvoltatorii foloseau NSLog pentru depanare și syslog pentru mesajele sistemice. NSLog scria în stderr și în consolă, dar era extrem de ineficient: fiecare mesaj era scris sincron pe disc, cauzând întârzieri în UI la logarea frecventă. os_log a rezolvat această problemă mutând bufferizarea la nivelul părții BSD a kernelului XNU și făcând scrierea pe disc asincronă.
os_log este utilizat în toate aplicațiile Apple și este recomandat de Apple ca unic API de logare pentru iOS, macOS, tvOS și watchOS. Sistemul și aplicațiile terțe scriu prin el mesaje într-o bază de date unică — stocată în memorie și descărcată periodic pe disc. Aceste loguri pot fi analizate prin Console.app pe Mac sau prin comanda log în terminal.
Arhitectura os_log constă din trei straturi: API client în spațiul utilizatorului (libsystem_trace.dylib), buffer circular în kernelul XNU și demonul logd, care descarcă asincron bufferul pe disc.
Când aplicația apelează os_log, mesajul este copiat în bufferul circular al kernelului de câțiva megaocteți. Bufferul funcționează pe principiul FIFO: dacă este plin, mesajele vechi sunt suprascrise cu cele noi. Demonul logd verifică periodic bufferul și salvează mesajele în fișiere .tracev3 într-o zonă protejată a sistemului de fișiere.
Conform datelor Apple Engineering, întârzierea tipică de la apelul os_log până la apariția mesajului în Console.app este de 1–5 secunde pe dispozitiv și până la 60 de secunde la descărcarea pe disc în modul lot. Acesta este un compromis conștient: performanța aplicației nu are de suferit din cauza logării, dar dezvoltatorul vede mesajele cu o mică întârziere.
// Declararea os_log prin OSLog
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
Bufferul circular os_log are un volum fix și nu poate fi modificat din spațiul utilizatorului. Dimensiunea bufferului variază de la 256 KB pe Apple Watch până la 4 MB pe Mac. Când aplicația generează mai multe mesaje decât poate stoca bufferul, mesajele vechi se pierd — acesta este un comportament așteptat pentru logarea de volum mare.
Pentru colectarea pe termen lung a tuturor mesajelor se utilizează comanda log collect, care pornește demonul de colectare pe dispozitiv și exportă .logarchive pe calculatorul dezvoltatorului. În acest mod, bufferul nu este suprascris — mesajele se scriu direct în arhivă.
os_log suportă cinci niveluri de criticitate, fiecare răspunzând pentru un tip separat de mesaje și fiind procesat diferit de sistem. Nivelul Default — de bază pentru mesajele care ajung întotdeauna în buffer. Info și Debug sunt dezactivate în build-urile de producție fără profil de colectare. Error și Fault sunt întotdeauna active și marcate cu un flag special în baza de date.
| Nivel | Semnificație | Intrarea în buffer implicit |
|---|---|---|
| Default | Mesaje obișnuite importante pentru diagnosticare | Da |
| Info | Mesaje informaționale pentru analiză detaliată | Nu (doar cu profil) |
| Debug | Mesaje de depanare pentru dezvoltare | Nu (doar cu profil) |
| Error | Erori care necesită atenție | Da |
| Fault | Defecțiuni critice care duc la crash | Da |
Alegerea nivelului corect de criticitate este importantă pentru performanță: Info și Debug nu se scriu pe disc în modul normal, deci pot fi utilizate abundent fără riscul de a încetini aplicația. Error și Fault se salvează întotdeauna, dar numărul lor trebuie să fie minim — fiecare astfel de mesaj crește timpul de scriere din cauza metadatelor suplimentare.
Subsystem — este identificatorul aplicației sau modulului în format reverse-DNS (com.example.app). Category — etichetă text în cadrul subsystem, care grupează logurile pe domenii funcționale: network, ui, database, auth. Această ierarhie permite filtrarea logurilor fără a citi fiecare mesaj și colectarea de statistici pentru fiecare modul separat.
Apple recomandă definirea unui OSLog pe modul și utilizarea lui în toate fișierele acelui modul. Pentru diferitele straturi ale aplicației — networking, UI, persistence — trebuie create categorii separate. Atunci în Console.app se pot activa logurile doar pentru network și dezactiva pentru celelalte, fără a recompila aplicația.
import OSLog
extension Logger {
static let network = Logger(
subsystem: "com.example.app",
category: "network"
)
static let ui = Logger(
subsystem: "com.example.app",
category: "ui"
)
}
os_log oferă un mecanism încorporat de control al confidențialității: fiecare valoare din șirul de formatare poate fi marcată ca public, private sau auto (comportament implicit). Implicit, os_log consideră toate șirurile și obiectele dinamice ca potențial confidențiale și le înlocuiește cu masca <private> în logurile de producție.
Acest lucru este critic pentru conformitatea cu cerințele GDPR și HIPAA: dacă aplicația loghează emailul utilizatorului sau numărul cardului prin os_log în modul auto, datele reale nu ajung niciodată pe disc. Dezvoltatorul vede mesajul complet doar la conectarea prin Xcode sau la utilizarea profilului de colectare de pe un dispozitiv conectat la același Mac.
let email = "user@example.com"
logger.log("User login: \(email, privacy: .public)")
// În logurile de producție: "User login: <private>"
// În depanarea prin Xcode: "User login: user@example.com"
logger.log("Payment token: \(token)")
Numerele (Int, Double, Float) sunt implicit considerate public — pot fi logate în siguranță fără marcare. Șirurile (String, NSString, StaticString) și obiectele (NSObject, CFType) sunt implicit private — mascate în producție. Șirurile statice (literali de șir între ghilimele în șirul de format) sunt întotdeauna vizibile — fac parte din mesajul propriu-zis, nu sunt date.
Acest comportament diferă de NSLog, unde toate datele erau logate în formă deschisă. Trecerea la os_log reduce semnificativ riscul de scurgere a datelor sensibile ale utilizatorului prin loguri.
os_log este cu 90–95% mai rapid decât NSLog la logarea de înaltă frecvență. Într-un test cu 10 000 de apeluri în buclă, NSLog creează o întârziere de aproximativ 2.8 secunde, în timp ce os_log execută aceleași apeluri în 0.3 secunde. Diferența se explică prin scrierea sincronă pe disc în NSLog față de bufferizarea asincronă în os_log.
Conform datelor Apple Performance Lab (2016), o aplicație iOS cu 20 de apeluri de logare pe secundă prin NSLog pierde 5–8 cadre de animație pe secundă din cauza blocării firului principal. Cu os_log nu are loc pierdere de cadre, deoarece bufferizarea are loc într-un fir separat al kernelului.
| Parametru | NSLog | os_log |
|---|---|---|
| Mecanism de scriere | Scriere sincronă pe disc | Bufferizare asincronă în kernel |
| Timp pentru 10 000 de apeluri | ~2.8 s | ~0.3 s |
| Impact asupra FPS | Pierdere 5–8 cadre | 0 cadre |
| Niveluri de criticitate | Nu | 5 niveluri |
| Confidențialitate | Toate datele deschise | Auto-mascare |
| Filtrare | Neacceptată | După subsystem / category / level |
os_log are două API-uri: clasicul C os_log_create și învelișul modern Swift Logger, introdus în iOS 14. Swift Logger utilizează sistemul ResultBuilder pentru formatare — argumentele sunt interpolate prin literali de șir cu marcarea explicită a confidențialității.
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
func handleResponse(statusCode: Int) {
if statusCode > 399 {
logger.error("HTTP error: \(statusCode, privacy: .public)")
} else {
logger.info("Response OK: \(statusCode)")
}
}
log collect — utilitar de linie de comandă pentru exportul logurilor colectate de pe dispozitiv. Se rulează din Terminal după conectarea dispozitivului la Mac prin USB.
// Colectarea logurilor în .logarchive
// În terminal: log collect --device --output ./app_logs.logarchive
// Vizualizarea logurilor subsystem: log show --subsystem com.example.app
// Logarea cu valori dinamice
logger.log("User \(userId) opened screen \(screenName)")
La utilizarea Logger, este important de reținut că argumentele sunt interpolate prin String Interpolation, nu prin șiruri de format ca în versiunea C. Acest lucru este mai sigur, dar necesită specificarea explicită a privacy pentru fiecare argument, dacă comportamentul implicit nu îl satisface pe dezvoltator.
Întrebări frecvente
os_log bufferizează asincron mesajele în kernel și nu blochează firul principal, iar NSLog scrie sincron pe disc. os_log este de 10 ori mai rapid, oferă 5 niveluri de criticitate și maschează automat datele private — NSLog nu are niciuna dintre aceste proprietăți.
Pentru mesaje temporare de depanare utilizați .debug — acestea sunt dezactivate în build-ul de producție și nu afectează performanța utilizatorilor. Pentru mesaje importante care trebuie păstrate întotdeauna, utilizați .default sau .info.
Prin Configure Profile în Xcode: Devices → selectați dispozitivul → Open Console → Actions → Configure Profile. Setați nivelul de colectare pentru subsystem-ul dorit pe Include. Acest lucru creează un profil activ până la prima repornire a dispozitivului.
Da, os_log funcționează în toate aplicațiile SwiftUI fără setări suplimentare. Creați un Logger static în model sau în extensia View și utilizați-l în onChange, task și handler-ele de gesturi pentru urmărirea ciclului de viață al ecranelor.
os_log maschează implicit șirurile și obiectele ca private. Pentru a vedea valoarea, specificați explicit privacy: .public în interpolare. Fără această marcare, valorile vor fi înlocuite cu masca în build-urile de producție, iar la depanarea prin Xcode se afișează normal.
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