os_log: какво е, възможности и работа на unified logging в Apple

Автор: IT Sectr Публикувано: 2026-05-28 Време за четене: 9 мин

os_log — това е unified logging API на Apple за iOS и macOS, което замени NSLog и os_trace. За разлика от старите механизми, os_log работи на ниво ядро: съобщенията се буферират в кръгов буфер и се записват на диска само при достигане на прага на активност. По данни на Apple WWDC 2016, os_log намалява натоварването на диска 10 пъти в сравнение с NSLog и дава контрол над нивото на детайлност чрез категории и типове. Това е основният диагностичен инструмент за iOS разработчика: чрез Console.app могат да се филтрират съобщенията по процес, категория и ниво на критичност в реално време.

Основни точки

  • os_log — системен API за логване от Apple, който буферира съобщения в ядрото и намалява натоварването на диска до 90% в сравнение с NSLog
  • Нива — Default, Info, Debug, Error, Fault — всяко се филтрира независимо и може да бъде включено или изключено чрез профил за събиране на логове
  • Категории — текстови етикети в рамките на един subsystem, които позволяват групиране на логовете по модули на приложението без създаване на отделни файлове
  • Поверителност — os_log автоматично маскира данни в кавички, отбелязани като private, и ги криптира в продуктовите логове
  • log collect — команден ред инструмент за експорт на събраните логове от устройството за последващ анализ в Console.app

Какво е os_log

os_log — това е unified logging API, представен от Apple в iOS 10 и macOS Sierra. Той обедини разпръснатите механизми за логване NSLog, os_trace и syslog в единна система с буфериране на ниво ядро XNU.

За разлика от NSLog, което синхронно записва всяко съобщение на диска и блокира нишката, os_log използва асинхронен кръгов буфер в паметта. Съобщенията се записват на диска само когато активността надхвърли определен праг или по команда log collect. Това радикално намалява влиянието на логването върху производителността на приложението.

os_log поддържа шест нива на критичност, разграничение по subsystem и category, както и вграден механизъм за поверителност: данни, отбелязани като private, автоматично се маскират в продуктовите логове и са достъпни само за разработчика при свързване на Xcode.

История на появата на unified logging

Преди iOS 10 разработчиците използваха NSLog за отстраняване на грешки и syslog за системни съобщения. NSLog пишеше в stderr и конзолата, но беше изключително неефективен: всяко съобщение се записваше синхронно на диска, причинявайки закъснения в интерфейса при често логване. os_log реши този проблем, премествайки буферирането на ниво BSD част на ядрото XNU и правейки записа на диска асинхронен.

Къде се прилага os_log

os_log се използва във всички приложения на Apple и се препоръчва от Apple като единствения API за логване за iOS, macOS, tvOS и watchOS. Системата и приложенията на трети страни пишат чрез него съобщения в единна база данни — съхранявана в паметта и периодично изхвърляна на диска. Тези логове могат да се анализират чрез Console.app на Mac или чрез командата log в терминала.

Как работи os_log: архитектура и буфериране

Архитектурата на os_log се състои от три слоя: клиентски API в потребителското пространство (libsystem_trace.dylib), кръгов буфер в ядрото XNU и демон logd, който асинхронно изхвърля буфера на диска.

Когато приложението извика os_log, съобщението се копира в кръговия буфер на ядрото с размер няколко мегабайта. Буферът работи на принципа FIFO: ако се напълни, старите съобщения се презаписват с нови. Демонът logd периодично проверява буфера и запазва съобщенията във файлове .tracev3 в защитена зона на файловата система.

Според данни на Apple Engineering, типичното закъснение от извикването на os_log до появата на съобщението в Console.app е 1–5 секунди на устройството и до 60 секунди при пакетно изхвърляне на диска. Това е съзнателен компромис: производителността на приложението не страда от логването, но разработчикът вижда съобщенията с малко закъснение.

swift
// Деклариране на os_log чрез OSLog
import OSLog

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

Кръговият буфер и неговата настройка

Кръговият буфер на os_log има фиксиран обем и не може да бъде променян от потребителското пространство. Размерът на буфера варира от 256 KB на Apple Watch до 4 MB на Mac. Когато приложението генерира повече съобщения, отколкото буферът може да побере, старите съобщения се губят — това е очаквано поведение за логване с голям обем.

За дългосрочно събиране на всички съобщения се използва командата log collect, която стартира демона за събиране на устройството и експортира .logarchive на компютъра на разработчика. В този режим буферът не се презаписва — съобщенията се записват директно в архива.

Нива на os_log: Default, Info, Debug, Error, Fault

os_log поддържа пет нива на критичност, всяко от които отговаря за отделен тип съобщения и се обработва различно от системата. Ниво Default — основно за съобщения, които винаги попадат в буфера. Info и Debug се изключват в продуктовите компилации без профил за събиране. Error и Fault винаги са активни и се отбелязват с особен флаг в базата данни.

НивоЗначениеПо подразбиране в буфера
DefaultОбикновени съобщения, важни за диагностикаДа
InfoИнформационни съобщения за подробен анализНе (само с профил)
DebugСъобщения за отстраняване на грешки за разработкаНе (само с профил)
ErrorГрешки, които изискват вниманиеДа
FaultКритични повреди, водещи до сривДа

Изборът на правилното ниво на критичност е важен за производителността: Info и Debug не се записват на диска в нормален режим, така че могат да се използват изобилно без риск от забавяне на приложението. Error и Fault винаги се запазват, но броят им трябва да бъде минимален — всяко такова съобщение увеличава времето за запис поради допълнителни метаданни.

Категории и subsystem в os_log

Subsystem — идентификатор на приложението или модула във формат reverse-DNS (com.example.app). Category — текстов етикет в рамките на subsystem, който групира логовете по функционални области: network, ui, database, auth. Такава йерархия позволява филтриране на логовете без четене на всяко съобщение и събиране на статистика за всеки модул поотделно.

Apple препоръчва дефиниране на един OSLog на модул и използването му във всички файлове на този модул. За различните слоеве на приложението — networking, UI, persistence — трябва да се създадат отделни категории. Тогава в Console.app могат да се включат логове само за network и да се изключат за останалите, без прекомпилиране на приложението.

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"
    )
}

Поверителност на данните в os_log

os_log предоставя вграден механизъм за контрол на поверителността: всяка стойност във форматиращия низ може да бъде отбелязана като public, private или auto (поведение по подразбиране). По подразбиране os_log счита всички динамични низове и обекти за потенциално поверителни и ги заменя с маска <private> в продуктовите логове.

Това е критично важно за съответствие с изискванията на GDPR и HIPAA: ако приложението логва имейла на потребителя или номера на карта чрез os_log в автоматичен режим, реалните данни никога не попадат на диска. Разработчикът вижда пълното съобщение само при свързване чрез Xcode или при използване на профил за събиране от устройство, свързано към същия Mac.

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

// В продуктови логове: "User login: <private>"
// При отстраняване на грешки чрез Xcode: "User login: user@example.com"
logger.log("Payment token: \(token)")

Правила за поверителност по подразбиране

Числата (Int, Double, Float) по подразбиране се считат за public — могат безопасно да се логват без маркиране. Низовете (String, NSString, StaticString) и обектите (NSObject, CFType) по подразбиране са private — маскират се в продукция. Статичните низове (низови литерали в кавички във форматиращия низ) винаги са видими — това е част от самото съобщение, а не данни.

Това поведение се различава от NSLog, където всички данни се логваха в открит вид. Преминаването към os_log значително намалява риска от изтичане на чувствителни потребителски данни чрез логове.

os_log срещу NSLog: сравнение на производителността

os_log е с 90–95% по-бърз от NSLog при високочестотно логване. В тест с 10 000 извиквания в цикъл, NSLog създава закъснение от около 2.8 секунди, докато os_log изпълнява същите извиквания за 0.3 секунди. Разликата се обяснява със синхронния запис на диска в NSLog срещу асинхронното буфериране в os_log.

Според данни на Apple Performance Lab (2016), iOS приложение с 20 извиквания на логване в секунда чрез NSLog губи 5–8 кадъра анимация в секунда поради блокиране на главната нишка. С os_log не се получава загуба на кадри, тъй като буферирането се извършва в отделна нишка на ядрото.

ПараметърNSLogos_log
Механизъм на записСинхронен запис на дискаАсинхронно буфериране в ядрото
Време за 10 000 извиквания~2.8 с~0.3 с
Влияние върху FPSЗагуба на 5–8 кадъра0 кадъра
Нива на критичностНяма5 нива
ПоверителностВсички данни отворениАвтоматично маскиране
ФилтриранеНе се поддържаПо subsystem / category / level

Примери за код с os_log в Swift

os_log има два API: класически C os_log_create и модерна Swift обвивка Logger, представена в iOS 14. Swift Logger използва системата ResultBuilder за форматиране — аргументите се интерполират чрез низови литерали с изрично маркиране на поверителност.

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 — команден ред инструмент за експорт на събраните логове от устройството. Стартира се от терминала след свързване на устройството към Mac чрез USB.

swift
// Събиране на логове в .logarchive
// В терминала: log collect --device --output ./app_logs.logarchive
// Преглед на логове subsystem: log show --subsystem com.example.app

// Логване с динамични стойности
logger.log("User \(userId) opened screen \(screenName)")

При използване на Logger е важно да запомните, че аргументите се интерполират чрез String Interpolation, а не чрез форматиращи низове, както в C версията на os_log. Това е по-безопасно, но изисква изрично посочване на privacy за всеки аргумент, ако поведението по подразбиране не устройва разработчика.

Често задавани въпроси

С какво os_log се различава от NSLog?

os_log асинхронно буферира съобщения в ядрото и не блокира главната нишка, а NSLog синхронно записва на диска. os_log е 10 пъти по-бърз, дава 5 нива на критичност и автоматично маскира частни данни — NSLog няма нито едно от тези свойства.

Кое ниво на os_log да използвам за отстраняване на грешки?

За временни съобщения за отстраняване на грешки използвайте .debug — те се изключват в продуктовата компилация и не влияят на производителността на потребителите. За важни съобщения, които трябва винаги да се запазват, използвайте .default или .info.

Как да включа Info и Debug логовете на устройството на потребителя?

Чрез Configure Profile в Xcode: Devices → изберете устройство → Open Console → Actions → Configure Profile. Задайте нивото на събиране за желания subsystem на Include. Това създава профил, който е активен до първото рестартиране на устройството.

Може ли да се използва os_log в SwiftUI приложения?

Да, os_log работи във всички SwiftUI приложения без допълнителни настройки. Създайте статичен Logger в модела или в разширение на View и го използвайте в onChange, task и манипулатори на жестове за проследяване на жизнения цикъл на екраните.

Защо os_log показва <private> вместо стойности?

os_log по подразбиране маскира низовете и обектите като private. За да видите стойността, изрично посочете privacy: .public в интерполацията. Без това маркиране стойностите ще бъдат заменени с маска в продуктовите компилации, а при отстраняване на грешки чрез Xcode се показват нормално.

Резюме

  • os_log — unified logging API на Apple, работещ чрез кръгов буфер в ядрото XNU с асинхронен запис на диска
  • Производителност — os_log е 10 пъти по-бърз от NSLog, не блокира главната нишка и не влияе на честотата на кадрите на анимация при всякакъв обем на логване
  • Нива — пет нива от Debug до Fault: Info и Debug се изключват в продукция, Error и Fault винаги се запазват
  • Subsystem и Category — йерархия за групиране на логовете по модули на приложението, филтриране в Console.app без четене на всяко съобщение
  • Поверителност — автоматично маскиране на низове и обекти в продуктовите логове, защита на лични данни без допълнителен код
  • Инструменти — Console.app за преглед в реално време и log collect за експорт на архив от устройството
  • Миграция — замяната на NSLog с os_log намалява риска от изтичане на данни и подобрява производителността, особено в натоварени мрежови модули и фонови процеси

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също