os_log — is de unified logging API van Apple voor iOS en macOS, die NSLog en os_trace heeft vervangen. In tegenstelling tot oude mechanismen werkt os_log op kernelniveau: berichten worden gebufferd in een circulaire buffer en pas naar schijf geschreven wanneer een activiteitsdrempel wordt bereikt. Volgens Apple WWDC 2016 vermindert os_log de schijfbelasting met een factor 10 vergeleken met NSLog en geeft het controle over het detailniveau via categorieën en types. Het is het belangrijkste diagnostische hulpmiddel voor iOS-ontwikkelaars: via Console.app kunnen berichten in real-time worden gefilterd op proces, categorie en kritikaliteitsniveau.
Belangrijkste punten
os_log — is de unified logging API geïntroduceerd door Apple in iOS 10 en macOS Sierra. Het verenigt de verspreide logmechanismen NSLog, os_trace en syslog in één systeem met buffering op XNU-kernelniveau.
In tegenstelling tot NSLog, dat elk bericht synchroon naar schijf schrijft en de thread blokkeert, gebruikt os_log een asynchrone circulaire buffer in het geheugen. Berichten worden alleen naar schijf weggeschreven wanneer de activiteit een bepaalde drempel overschrijdt of op commando log collect. Dit vermindert de impact van loggen op de app-prestaties drastisch.
os_log ondersteunt zes kritikaliteitsniveaus, differentiatie per subsystem en category, en een ingebouwd privacymechanisme: gegevens gemarkeerd als private worden automatisch gemaskeerd in productielogs en zijn alleen toegankelijk voor de ontwikkelaar wanneer Xcode is aangesloten.
Vóór iOS 10 gebruikten ontwikkelaars NSLog voor debuggen en syslog voor systeemberichten. NSLog schreef naar stderr en de console, maar was uiterst inefficiënt: elk bericht werd synchroon naar schijf geschreven, wat bij frequent loggen vertragingen in de UI veroorzaakte. os_log loste dit probleem op door buffering naar het BSD-gedeelte van de XNU-kernel te verplaatsen en het schrijven naar schijf asynchroon te maken.
os_log wordt gebruikt in alle Apple-apps en wordt door Apple aanbevolen als de enige log-API voor iOS, macOS, tvOS en watchOS. Het systeem en apps van derden schrijven er berichten mee naar één database — opgeslagen in het geheugen en periodiek naar schijf weggeschreven. Deze logs kunnen worden geanalyseerd via Console.app op de Mac of via het commando log in de terminal.
De architectuur van os_log bestaat uit drie lagen: client-API in de gebruikersruimte (libsystem_trace.dylib), een circulaire buffer in de XNU-kernel en de logd-daemon, die de buffer asynchroon naar schijf wegschrijft.
Wanneer een app os_log aanroept, wordt het bericht gekopieerd naar een circulaire kernelbuffer van enkele megabytes. De buffer werkt volgens het FIFO-principe: als deze vol is, worden oude berichten overschreven door nieuwe. De logd-daemon controleert periodiek de buffer en slaat berichten op in .tracev3-bestanden in een beveiligd gebied van het bestandssysteem.
Volgens Apple Engineering bedraagt de typische vertraging van een os_log-aanroep tot het verschijnen van het bericht in Console.app 1–5 seconden op het apparaat en tot 60 seconden bij batchgewijs wegschrijven naar schijf. Dit is een bewuste afweging: de app-prestaties lijden niet onder het loggen, maar de ontwikkelaar ziet berichten met een kleine vertraging.
// Declaratie van os_log via OSLog
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
De circulaire buffer van os_log heeft een vaste capaciteit en kan niet worden gewijzigd vanuit de gebruikersruimte. De buffergrootte varieert van 256 KB op Apple Watch tot 4 MB op de Mac. Wanneer een app meer berichten genereert dan de buffer kan bevatten, gaan oude berichten verloren — dit is verwacht gedrag voor loggen met hoog volume.
Voor het langdurig verzamelen van alle berichten wordt het commando log collect gebruikt, dat de verzameldaemon op het apparaat start en .logarchive exporteert naar de computer van de ontwikkelaar. In deze modus wordt de buffer niet overschreven — berichten worden rechtstreeks naar het archief geschreven.
os_log ondersteunt vijf kritikaliteitsniveaus, elk verantwoordelijk voor een apart type bericht en verschillend verwerkt door het systeem. Niveau Default — basis voor berichten die altijd in de buffer terechtkomen. Info en Debug worden uitgeschakeld in productiebuilds zonder verzamelprofiel. Error en Fault zijn altijd actief en gemarkeerd met een speciale vlag in de database.
| Niveau | Betekenis | Standaard in buffer |
|---|---|---|
| Default | Gewone berichten belangrijk voor diagnostiek | Ja |
| Info | Informatieberichten voor gedetailleerde analyse | Nee (alleen met profiel) |
| Debug | Debugberichten voor ontwikkeling | Nee (alleen met profiel) |
| Error | Fouten die aandacht vereisen | Ja |
| Fault | Kritieke storingen die tot crashes leiden | Ja |
Het kiezen van het juiste kritikaliteitsniveau is belangrijk voor de prestaties: Info en Debug worden in de normale modus niet naar schijf geschreven, dus ze kunnen overvloedig worden gebruikt zonder het risico de app te vertragen. Error en Fault worden altijd opgeslagen, maar hun aantal moet minimaal zijn — elk dergelijk bericht verlengt de schrijftijd vanwege extra metadata.
Subsystem — is de identificatie van een app of module in reverse-DNS-formaat (com.example.app). Category — een tekstueel label binnen het subsystem dat logs groepeert op functionele gebieden: network, ui, database, auth. Deze hiërarchie maakt het mogelijk logs te filteren zonder elk bericht te lezen en per module apart statistieken te verzamelen.
Apple raadt aan om één OSLog per module te definiëren en deze in alle bestanden van die module te gebruiken. Voor verschillende lagen van de app — networking, UI, persistence — moeten aparte categorieën worden aangemaakt. Dan kunnen in Console.app de logs alleen voor network worden ingeschakeld en voor de rest worden uitgeschakeld, zonder de app opnieuw te compileren.
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 biedt een ingebouwd mechanisme voor privacycontrole: elke waarde in de opmaakstring kan worden gemarkeerd als public, private of auto (standaardgedrag). Standaard beschouwt os_log alle dynamische strings en objecten als potentieel vertrouwelijk en vervangt ze door de masker <private> in productielogs.
Dit is van cruciaal belang voor naleving van GDPR- en HIPAA-vereisten: als een app de e-mail van een gebruiker of een kaartnummer via os_log in de automatische modus logt, komen de echte gegevens nooit op de schijf. De ontwikkelaar ziet het volledige bericht alleen bij verbinding via Xcode of bij gebruik van een verzamelprofiel van een apparaat dat op dezelfde Mac is aangesloten.
let email = "user@example.com"
logger.log("User login: \(email, privacy: .public)")
// In productielogs: "User login: <private>"
// Bij debuggen via Xcode: "User login: user@example.com"
logger.log("Payment token: \(token)")
Getallen (Int, Double, Float) worden standaard als public beschouwd — ze kunnen veilig worden gelogd zonder markering. Strings (String, NSString, StaticString) en objecten (NSObject, CFType) zijn standaard private — ze worden in productie gemaskeerd. Statische strings (stringliteralen tussen aanhalingstekens binnen de opmaakstring) zijn altijd zichtbaar — ze maken deel uit van het bericht zelf, niet van de gegevens.
Dit gedrag verschilt van NSLog, waar alle gegevens in open vorm werden gelogd. De overstap naar os_log vermindert het risico op lekkage van gevoelige gebruikersgegevens via logs aanzienlijk.
os_log is 90–95% sneller dan NSLog bij hoogfrequent loggen. In een test met 10.000 aanroepen in een lus veroorzaakt NSLog een vertraging van ongeveer 2,8 seconden, terwijl os_log dezelfde aanroepen in 0,3 seconden uitvoert. Het verschil wordt verklaard door synchroon schrijven naar schijf in NSLog versus asynchrone buffering in os_log.
Volgens Apple Performance Lab (2016) verliest een iOS-app met 20 logaanroepen per seconde via NSLog 5–8 animatieframes per seconde door het blokkeren van de hoofdthread. Met os_log treedt geen frameverlies op, omdat buffering plaatsvindt in een aparte kernelthread.
| Parameter | NSLog | os_log |
|---|---|---|
| Schrijfmechanisme | Synchroon naar schijf | Asynchrone buffering in kernel |
| Tijd voor 10.000 aanroepen | ~2,8 s | ~0,3 s |
| Impact op FPS | Verlies 5–8 frames | 0 frames |
| Kritikaliteitsniveaus | Nee | 5 niveaus |
| Privacy | Alle gegevens open | Automatisch maskeren |
| Filteren | Niet ondersteund | Op subsystem / category / level |
os_log heeft twee API's: klassiek C os_log_create en de moderne Swift-wrapper Logger, geïntroduceerd in iOS 14. Swift Logger gebruikt het ResultBuilder-systeem voor opmaak — argumenten worden geïnterpoleerd via stringliteralen met expliciete privacymarkering.
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 — commandoregelhulpprogramma voor het exporteren van verzamelde logs van het apparaat. Wordt gestart vanuit Terminal na het aansluiten van het apparaat op de Mac via USB.
// Logs verzamelen in .logarchive
// In terminal: log collect --device --output ./app_logs.logarchive
// Subsystem-logs bekijken: log show --subsystem com.example.app
// Loggen met dynamische waarden
logger.log("User \(userId) opened screen \(screenName)")
Bij gebruik van Logger is het belangrijk te onthouden dat argumenten worden geïnterpoleerd via String Interpolation, niet via opmaakstrings zoals in de C-versie van os_log. Dit is veiliger, maar vereist expliciete vermelding van privacy voor elk argument als het standaardgedrag de ontwikkelaar niet bevalt.
Veelgestelde vragen
os_log buffert berichten asynchroon in de kernel en blokkeert de hoofdthread niet, terwijl NSLog synchroon naar schijf schrijft. os_log is 10 keer sneller, biedt 5 kritikaliteitsniveaus en maskeert automatisch privégegevens — NSLog heeft geen van deze eigenschappen.
Gebruik .debug voor tijdelijke debugberichten — ze worden uitgeschakeld in de productiebuild en hebben geen invloed op de prestaties van gebruikers. Gebruik .default of .info voor belangrijke berichten die altijd bewaard moeten blijven.
Via Configure Profile in Xcode: Devices → selecteer het apparaat → Open Console → Actions → Configure Profile. Stel het verzamelingsniveau voor het gewenste subsystem in op Include. Dit maakt een profiel aan dat actief is tot de eerste herstart van het apparaat.
Ja, os_log werkt in alle SwiftUI-apps zonder extra configuratie. Maak een statische Logger aan in het model of in een View-extensie en gebruik deze in onChange, task en gesture-handlers voor het volgen van de levenscyclus van schermen.
os_log maskeert standaard strings en objecten als private. Om de waarde te zien, geeft u expliciet privacy: .public op in de interpolatie. Zonder deze markering worden waarden vervangen door een masker in productiebuilds, maar in debug via Xcode worden ze normaal weergegeven.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook