os_log: co to jest, możliwości i działanie unified logging w Apple

Autor: IT Sectr Opublikowano: 2026-05-28 Czas czytania: 9 min

os_log — to unified logging API od Apple dla iOS i macOS, który zastąpił NSLog i os_trace. W przeciwieństwie do starych mechanizmów, os_log działa na poziomie jądra: komunikaty są buforowane w buforze cyklicznym i zapisywane na dysk dopiero po osiągnięciu progu aktywności. Według danych Apple WWDC 2016, os_log zmniejsza obciążenie dysku 10-krotnie w porównaniu z NSLog i daje kontrolę nad poziomem szczegółowości poprzez kategorie i typy. Jest to podstawowe narzędzie diagnostyczne dla dewelopera iOS: przez Console.app można filtrować komunikaty według procesu, kategorii i poziomu krytyczności w czasie rzeczywistym.

Najważniejsze

  • os_log — systemowe API logowania od Apple, które buforuje komunikaty w jądrze i zmniejsza obciążenie dysku do 90% w porównaniu z NSLog
  • Poziomy — Default, Info, Debug, Error, Fault — każdy jest filtrowany niezależnie i może być włączony lub wyłączony przez profil zbierania logów
  • Kategorie — etykiety tekstowe w ramach jednego subsystem, które pozwalają grupować logi według modułów aplikacji bez tworzenia osobnych plików
  • Prywatność — os_log automatycznie maskuje dane w cudzysłowie oznaczone jako private i szyfruje je w logach produkcyjnych
  • log collect — narzędzie wiersza poleceń do wyeksportowania zebranych logów z urządzenia do późniejszej analizy w Console.app

Co to jest os_log

os_log — to unified logging API, przedstawiony przez Apple w iOS 10 i macOS Sierra. Połączył rozproszone mechanizmy logowania NSLog, os_trace i syslog w jeden system z buforowaniem na poziomie jądra XNU.

W przeciwieństwie do NSLog, które synchronicznie zapisuje każdy komunikat na dysk i blokuje wątek, os_log używa asynchronicznego bufora cyklicznego w pamięci. Komunikaty są zrzucane na dysk tylko wtedy, gdy aktywność przekroczy zadany próg lub na polecenie log collect. To radykalnie zmniejsza wpływ logowania na wydajność aplikacji.

os_log obsługuje sześć poziomów krytyczności, rozgraniczenie według subsystem i category, a także wbudowany mechanizm prywatności: dane oznaczone jako private są automatycznie maskowane w logach produkcyjnych i dostępne tylko dla dewelopera po podłączeniu Xcode.

Historia pojawienia się unified logging

Przed iOS 10 deweloperzy używali NSLog do debugowania i syslog do komunikatów systemowych. NSLog pisał do stderr i do konsoli, ale był skrajnie nieefektywny: każdy komunikat był synchronicznie zapisywany na dysk, powodując opóźnienia w UI przy częstym logowaniu. os_log rozwiązał ten problem, przenosząc buforowanie na poziom BSD części jądra XNU i czyniąc zapis na dysk asynchronicznym.

Gdzie stosuje się os_log

os_log jest używany we wszystkich aplikacjach Apple i zalecany przez Apple jako jedyne API logowania dla iOS, macOS, tvOS i watchOS. System i aplikacje innych firm piszą przez niego komunikaty do jednej bazy danych — przechowywanej w pamięci i okresowo zrzucanej na dysk. Analizować te logi można przez Console.app na Macu lub przez polecenie log w terminalu.

Jak działa os_log: architektura i buforowanie

Architektura os_log składa się z trzech warstw: klienckiego API w przestrzeni użytkownika (libsystem_trace.dylib), bufora cyklicznego w jądrze XNU i demona logd, który asynchronicznie zrzuca bufor na dysk.

Gdy aplikacja wywołuje os_log, komunikat jest kopiowany do bufora cyklicznego jądra o rozmiarze kilku megabajtów. Bufor działa na zasadzie FIFO: jeśli jest pełny, stare komunikaty są nadpisywane nowymi. Demon logd okresowo sprawdza bufor i zapisuje komunikaty do plików .tracev3 w chronionym obszarze systemu plików.

Według danych Apple Engineering, typowe opóźnienie od wywołania os_log do pojawienia się komunikatu w Console.app wynosi 1–5 sekund na urządzeniu i do 60 sekund przy zrzucie na dysk w trybie wsadowym. To świadomy kompromis: wydajność aplikacji nie cierpi z powodu logowania, ale deweloper widzi komunikaty z niewielkim opóźnieniem.

swift
// Deklaracja os_log przez OSLog
import OSLog

let logger = Logger(
    subsystem: "com.example.app",
    category: "network"
)

Bufor cykliczny i jego konfiguracja

Bufor cykliczny os_log ma stałą pojemność i nie można go zmienić z przestrzeni użytkownika. Rozmiar bufora waha się od 256 KB na Apple Watch do 4 MB na Macu. Gdy aplikacja generuje więcej komunikatów, niż mieści bufor, stare komunikaty są tracone — to oczekiwane zachowanie przy logowaniu o dużej objętości.

Do długoterminowego zbierania wszystkich komunikatów używa się polecenia log collect, które uruchamia demona zbierania na urządzeniu i eksportuje .logarchive na komputer dewelopera. W tym trybie bufor nie jest nadpisywany — komunikaty są zapisywane bezpośrednio do archiwum.

Poziomy os_log: Default, Info, Debug, Error, Fault

os_log obsługuje pięć poziomów krytyczności, z których każdy odpowiada za inny typ komunikatów i jest inaczej przetwarzany przez system. Poziom Default — podstawowy dla komunikatów, które zawsze trafiają do bufora. Info i Debug są wyłączane w kompilacjach produkcyjnych bez profilu zbierania. Error i Fault są zawsze aktywne i oznaczone specjalną flagą w bazie danych.

PoziomZnaczenieDomyslne trafianie do bufora
DefaultZwykłe komunikaty ważne dla diagnostykiTak
InfoKomunikaty informacyjne do szczegółowej analizyNie (tylko z profilem)
DebugKomunikaty debugowe do tworzenia aplikacjiNie (tylko z profilem)
ErrorBłędy wymagające uwagiTak
FaultKrytyczne awarie prowadzące do crashaTak

Wybór odpowiedniego poziomu krytyczności jest ważny dla wydajności: Info i Debug nie są zapisywane na dysk w trybie normalnym, więc można ich używać obficie bez ryzyka spowolnienia aplikacji. Error i Fault są zawsze zapisywane, ale ich liczba powinna być minimalna — każdy taki komunikat wydłuża czas zapisu z powodu dodatkowych metadanych.

Kategorie i subsystem w os_log

Subsystem — to identyfikator aplikacji lub modułu w formacie reverse-DNS (com.example.app). Category — etykieta tekstowa w ramach subsystem, która grupuje logi według obszarów funkcjonalnych: network, ui, database, auth. Taka hierarchia pozwala filtrować logi bez czytania każdego komunikatu i zbierać statystyki dla każdego modułu osobno.

Apple zaleca definiowanie jednego OSLog na moduł i używanie go we wszystkich plikach tego modułu. Dla różnych warstw aplikacji — networking, UI, persistence — należy tworzyć osobne kategorie. Wtedy w Console.app można włączyć logi tylko dla network i wyłączyć dla pozostałych, bez przekompilowywania aplikacji.

swift
import OSLog

extension Logger {
    static let network = Logger(
        subsystem: "com.example.app",
        category: "network"
    )
    static let ui = Logger(
        subsystem: "com.example.app",
        category: "ui"
    )
}

Prywatność danych w os_log

os_log zapewnia wbudowany mechanizm kontroli prywatności: każda wartość w stringu formatującym może być oznaczona jako public, private lub auto (zachowanie domyślne). Domyślnie os_log uważa wszystkie dynamiczne stringi i obiekty za potencjalnie poufne i zastępuje je maską <private> w logach produkcyjnych.

Jest to krytycznie ważne dla zgodności z wymogami GDPR i HIPAA: jeśli aplikacja loguje email użytkownika lub numer karty przez os_log w trybie auto, prawdziwe dane nigdy nie trafią na dysk. Deweloper widzi pełny komunikat tylko po podłączeniu przez Xcode lub przy użyciu profilu zbierania z urządzenia podłączonego do tego samego Maca.

swift
let email = "user@example.com"
logger.log("User login: \(email, privacy: .public)")

// W logach produkcyjnych: "User login: <private>"
// W debugowaniu przez Xcode: "User login: user@example.com"
logger.log("Payment token: \(token)")

Domyślne zasady prywatności

Liczby (Int, Double, Float) domyślnie są uważane za public — można je bezpiecznie logować bez oznaczania. Stringi (String, NSString, StaticString) i obiekty (NSObject, CFType) domyślnie są private — maskowane w produkcji. Statyczne stringi (literały stringowe w cudzysłowie wewnątrz stringa formatującego) są zawsze widoczne — to część samego komunikatu, a nie dane.

To zachowanie różni się od NSLog, gdzie wszystkie dane były logowane w jawnej postaci. Przejście na os_log znacząco zmniejsza ryzyko wycieku wrażliwych danych użytkownika przez logi.

os_log vs NSLog: porównanie wydajności

os_log jest o 90–95% szybszy od NSLog przy logowaniu o wysokiej częstotliwości. W teście z 10 000 wywołań w pętli NSLog tworzy opóźnienie około 2.8 sekundy, podczas gdy os_log wykonuje te same wywołania w 0.3 sekundy. Różnica wynika z synchronicznego zapisu na dysk w NSLog w porównaniu z asynchronicznym buforowaniem w os_log.

Według danych Apple Performance Lab (2016), aplikacja na iOS z 20 wywołaniami logowania na sekundę przez NSLog traci 5–8 klatek animacji na sekundę z powodu blokowania głównego wątku. Z os_log utrata klatek nie występuje, ponieważ buforowanie odbywa się w osobnym wątku jądra.

ParametrNSLogos_log
Mechanizm zapisuSynchroniczny zapis na dyskAsynchroniczne buforowanie w jądrze
Czas na 10 000 wywołań~2.8 s~0.3 s
Wpływ na FPSStrata 5–8 klatek0 klatek
Poziomy krytycznościBrak5 poziomów
PrywatnośćWszystkie dane jawneAuto-masking
FiltrowanieNieobsługiwaneWedług subsystem / category / level

Przykłady kodu z os_log w Swift

os_log ma dwa API: klasyczne C-owskie os_log_create i nowoczesne opakowanie Swift Logger, wprowadzone w iOS 14. Swift Logger używa systemu ResultBuilder do formatowania — argumenty są interpolowane przez literały stringowe z jawnym oznaczaniem prywatności.

swift
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 — narzędzie wiersza poleceń do wyeksportowania zebranych logów z urządzenia. Uruchamiane z Terminala po podłączeniu urządzenia do Maca przez USB.

swift
// Zbieranie logów do .logarchive
// W terminalu: log collect --device --output ./app_logs.logarchive
// Podgląd logów subsystem: log show --subsystem com.example.app

// Logowanie z wartościami dynamicznymi
logger.log("User \(userId) opened screen \(screenName)")

Przy użyciu Logger należy pamiętać, że argumenty są interpolowane przez String Interpolation, a nie przez stringi formatujące, jak w C-owej wersji os_log. Jest to bezpieczniejsze, ale wymaga jawnego określenia privacy dla każdego argumentu, jeśli domyślne zachowanie nie odpowiada deweloperowi.

Często zadawane pytania

Czym os_log różni się od NSLog?

os_log asynchronicznie buforuje komunikaty w jądrze i nie blokuje głównego wątku, a NSLog synchronicznie zapisuje na dysk. os_log jest 10 razy szybszy, daje 5 poziomów krytyczności i automatycznie maskuje prywatne dane — NSLog nie ma żadnej z tych właściwości.

Jakiego poziomu os_log używać do debugowania?

Do tymczasowych komunikatów debugowych używaj .debug — są wyłączane w kompilacji produkcyjnej i nie wpływają na wydajność użytkowników. Do ważnych komunikatów, które powinny być zawsze zachowywane, używaj .default lub .info.

Jak włączyć logi Info i Debug na urządzeniu użytkownika?

Przez Configure Profile w Xcode: Devices → wybierz urządzenie → Open Console → Actions → Configure Profile. Ustaw poziom zbierania dla potrzebnego subsystem na Include. Tworzy to profil, który jest aktywny do pierwszego restartu urządzenia.

Czy można używać os_log w aplikacjach SwiftUI?

Tak, os_log działa we wszystkich aplikacjach SwiftUI bez dodatkowej konfiguracji. Utwórz statyczny Logger w modelu lub w rozszerzeniu View i używaj go w onChange, task oraz handlerach gestów do śledzenia cyklu życia ekranów.

Dlaczego os_log pokazuje <private> zamiast wartości?

os_log domyślnie maskuje stringi i obiekty jako private. Aby zobaczyć wartość, jawnie określ privacy: .public w interpolacji. Bez tego oznaczenia wartości zostaną zastąpione maską w kompilacjach produkcyjnych, a w debugowaniu przez Xcode są wyświetlane normalnie.

Podsumowanie

  • os_log — unified logging API Apple działające przez bufor cykliczny w jądrze XNU z asynchronicznym zapisem na dysk
  • Wydajność — os_log jest 10 razy szybszy od NSLog, nie blokuje głównego wątku i nie wpływa na liczbę klatek animacji przy dowolnej objętości logowania
  • Poziomy — pięć poziomów od Debug do Fault: Info i Debug są wyłączane w produkcji, Error i Fault są zawsze zapisywane
  • Subsystem i Category — hierarchia do grupowania logów według modułów aplikacji, filtrowanie w Console.app bez czytania każdego komunikatu
  • Prywatność — automatyczne maskowanie stringów i obiektów w logach produkcyjnych, ochrona danych osobowych bez dodatkowego kodu
  • Narzędzia — Console.app do podglądu w czasie rzeczywistym i log collect do eksportu archiwum z urządzenia
  • Migracja — zastąpienie NSLog przez os_log zmniejsza ryzyko wycieku danych i poprawia wydajność, szczególnie w obciążonych modułach sieciowych i procesach tła

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również