os_log é a API de registro unificado da Apple para iOS e macOS que substituiu o NSLog e o os_trace. Ao contrário dos mecanismos antigos, o os_log funciona no nível do kernel: as mensagens são armazenadas em um buffer circular e gravadas no disco somente quando um limite de atividade é atingido. De acordo com a Apple WWDC 2016, o os_log reduz a carga do disco em 10 vezes em comparação com o NSLog e oferece controle sobre o nível de detalhes por meio de categorias e tipos. É a principal ferramenta de diagnóstico para o desenvolvedor iOS: através do Console.app é possível filtrar mensagens por processo, categoria e nível de criticidade em tempo real.
Principais pontos
os_log é uma API de registro unificado apresentada pela Apple no iOS 10 e macOS Sierra. Ela unificou os mecanismos de registro distintos NSLog, os_trace e syslog em um único sistema com buffer no nível do kernel XNU.
Ao contrário do NSLog, que grava cada mensagem de forma síncrona no disco e bloqueia a thread, o os_log usa um buffer circular assíncrono na memória. As mensagens são liberadas para o disco somente quando a atividade excede um limite definido ou mediante o comando log collect. Isso reduz radicalmente o impacto do registro no desempenho do aplicativo.
O os_log suporta seis níveis de criticidade, diferenciação por subsystem e category, e um mecanismo de privacidade integrado: dados marcados como private são automaticamente mascarados nos logs de produção e ficam disponíveis apenas para o desenvolvedor quando conectado via Xcode.
Antes do iOS 10, os desenvolvedores usavam NSLog para depuração e syslog para mensagens do sistema. O NSLog gravava no stderr e no console, mas era extremamente ineficiente: cada mensagem era gravada de forma síncrona no disco, causando atrasos na interface do usuário com registro frequente. O os_log resolveu esse problema movendo o buffer para a parte BSD do kernel XNU e tornando as gravações em disco assíncronas.
os_log é usado em todos os aplicativos da Apple e é recomendado pela Apple como a única API de registro para iOS, macOS, tvOS e watchOS. O sistema e aplicativos de terceiros usam-no para gravar mensagens em um banco de dados unificado — ele é armazenado na memória e liberado periodicamente para o disco. Esses logs podem ser analisados através do Console.app no Mac ou através do comando log no terminal.
A arquitetura do os_log consiste em três camadas: uma API do lado do cliente no espaço do usuário (libsystem_trace.dylib), um buffer circular no kernel XNU e o daemon logd que libera o buffer de forma assíncrona para o disco.
Quando um aplicativo chama o os_log, a mensagem é copiada para um buffer circular do kernel de vários megabytes. O buffer opera no princípio FIFO: se estiver cheio, as mensagens antigas são sobrescritas pelas mais novas. O daemon logd verifica periodicamente o buffer e salva as mensagens em arquivos .tracev3 em uma área protegida do sistema de arquivos.
De acordo com a Apple Engineering, o atraso típico desde a chamada do os_log até o aparecimento da mensagem no Console.app é de 1 a 5 segundos em um dispositivo e de até 60 segundos ao liberar para o disco em modo lote. Esta é uma compensação deliberada: o desempenho do aplicativo não é afetado pelo registro, mas o desenvolvedor vê as mensagens com um pequeno atraso.
// Declaração do os_log através do OSLog
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
O buffer circular do os_log tem um tamanho fixo e não pode ser alterado do espaço do usuário. O tamanho do buffer varia de 256 KB no Apple Watch a 4 MB no Mac. Quando um aplicativo gera mais mensagens do que o buffer pode comportar, as mensagens antigas são perdidas — este é um comportamento esperado para registro de alto volume.
Para coleta de longo prazo de todas as mensagens, é usado o comando log collect. Ele inicia um daemon de coleta no dispositivo e exporta um .logarchive para o computador do desenvolvedor. Neste modo, o buffer não é sobrescrito — as mensagens são gravadas diretamente no arquivo.
os_log suporta cinco níveis de criticidade, cada um responsável por um tipo diferente de mensagem e processado de forma diferente pelo sistema. Default é o nível base para mensagens que sempre entram no buffer. Info e Debug são desabilitados em compilações de produção sem um perfil de coleta. Error e Fault estão sempre ativos e são marcados com um sinalizador especial no banco de dados.
| Nível | Significado | Entrada no buffer por padrão |
|---|---|---|
| Default | Mensagens normais importantes para diagnóstico | Sim |
| Info | Mensagens informativas para análise detalhada | Não (apenas com perfil) |
| Debug | Mensagens de depuração para desenvolvimento | Não (apenas com perfil) |
| Error | Erros que requerem atenção | Sim |
| Fault | Falhas críticas que levam a travamentos | Sim |
Escolher o nível de criticidade correto é importante para o desempenho: Info e Debug não são gravados no disco no modo normal, portanto podem ser usados abundantemente sem risco de retardar o aplicativo. Error e Fault são sempre salvos, mas sua quantidade deve ser mínima — cada uma dessas mensagens aumenta o tempo de gravação devido aos metadados adicionais.
Subsystem é um identificador de aplicativo ou módulo no formato reverse-DNS (com.example.app). Category é um rótulo de texto dentro de um subsystem que agrupa os logs por áreas funcionais: network, ui, database, auth. Essa hierarquia permite filtrar logs sem ler cada mensagem e coletar estatísticas para cada módulo separadamente.
A Apple recomenda definir um OSLog por módulo e usá-lo em todos os arquivos desse módulo. Para diferentes camadas do aplicativo — networking, UI, persistência — devem ser criadas categorias separadas. Então no Console.app você pode habilitar logs apenas para network e desabilitar para outros sem recompilar o aplicativo.
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 fornece um mecanismo de controle de privacidade integrado: cada valor em uma string de formato pode ser marcado como public, private ou auto (comportamento padrão). Por padrão, o os_log considera todas as strings dinâmicas e objetos como potencialmente confidenciais e os substitui pela máscara <private> nos logs de produção.
Isso é fundamental para a conformidade com GDPR e HIPAA: se um aplicativo registrar o e-mail ou número de cartão de um usuário através do os_log no modo automático, os dados reais nunca chegam ao disco. O desenvolvedor vê a mensagem completa apenas quando conectado via Xcode ou ao usar um perfil de coleta de um dispositivo conectado ao mesmo Mac.
let email = "user@example.com"
logger.log("User login: \(email, privacy: .public)")
// Em logs de produção: "User login: "
// Na depuração com Xcode: "User login: user@example.com"
logger.log("Payment token: \(token)")
Números (Int, Double, Float) são considerados públicos por padrão — podem ser registrados com segurança sem marcação. Strings (String, NSString, StaticString) e objetos (NSObject, CFType) são privados por padrão — são mascarados em produção. Strings estáticas (literais de string entre aspas dentro da string de formato) são sempre visíveis — fazem parte da própria mensagem, não são dados.
Esse comportamento difere do NSLog, onde todos os dados eram registrados em texto simples. A migração para o os_log reduz significativamente o risco de vazamento de dados confidenciais do usuário através dos logs.
os_log é 90–95% mais rápido que o NSLog em registro de alta frequência. Em um teste com 10.000 chamadas em loop, o NSLog cria um atraso de aproximadamente 2,8 segundos, enquanto o os_log executa as mesmas chamadas em 0,3 segundos. A diferença é explicada pelas gravações síncronas em disco no NSLog versus o buffer assíncrono no os_log.
De acordo com o Apple Performance Lab (2016), um aplicativo iOS com 20 chamadas de registro por segundo através do NSLog perde de 5 a 8 quadros de animação por segundo devido ao bloqueio da thread principal. Com o os_log não há perda de quadros porque o buffer ocorre em uma thread separada do kernel.
| Parâmetro | NSLog | os_log |
|---|---|---|
| Mecanismo de gravação | Gravação síncrona em disco | Buffer assíncrono no kernel |
| Tempo para 10.000 chamadas | ~2,8 s | ~0,3 s |
| Impacto no FPS | Perda de 5–8 quadros | 0 quadros |
| Níveis de criticidade | Nenhum | 5 níveis |
| Privacidade | Todos os dados visíveis | Mascaramento automático |
| Filtragem | Não suportada | Por subsystem / category / level |
os_log tem duas APIs: a clássica em C os_log_create e o wrapper moderno em Swift Logger apresentado no iOS 14. O Logger do Swift usa o sistema ResultBuilder para formatação — os argumentos são interpolados através de literais de string com marcação explícita de privacidade.
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 é um utilitário de linha de comando para exportar logs coletados de um dispositivo. Ele é executado no Terminal após conectar o dispositivo a um Mac via USB.
// Coleta de logs em .logarchive
// No Terminal: log collect --device --output ./app_logs.logarchive
// Visualização de logs de subsystem: log show --subsystem com.example.app
// Registro com valores dinâmicos
logger.log("User \(userId) opened screen \(screenName)")
Ao usar Logger, é importante lembrar que os argumentos são interpolados via String Interpolation, não através de strings de formato como na versão C do os_log. Isso é mais seguro, mas requer marcação explícita de privacidade para cada argumento se o comportamento padrão não for adequado para o desenvolvedor.
Perguntas frequentes
O os_log armazena mensagens em buffer de forma assíncrona no kernel e não bloqueia a thread principal, enquanto o NSLog grava de forma síncrona no disco. O os_log é 10 vezes mais rápido, oferece 5 níveis de criticidade e mascara automaticamente dados privados — o NSLog não tem nenhuma dessas características.
Para mensagens de depuração temporárias, use .debug — elas são desabilitadas em compilações de produção e não afetam o desempenho dos usuários. Para mensagens importantes que devem ser sempre preservadas, use .default ou .info.
Através de Configure Profile no Xcode: Devices → selecione o dispositivo → Open Console → Actions → Configure Profile. Defina o nível de coleta para o subsystem desejado como Include. Isso cria um perfil que permanece ativo até a primeira reinicialização do dispositivo.
Sim, os_log funciona em todos os aplicativos SwiftUI sem configuração adicional. Crie um Logger estático no seu modelo ou em uma extensão de View e use-o em onChange, task e manipuladores de gestos para rastrear o ciclo de vida das telas.
Por padrão, o os_log mascara strings e objetos como private. Para ver o valor, especifique explicitamente privacy: .public na interpolação. Sem essa marcação, os valores serão substituídos pela máscara em compilações de produção, mas na depuração com Xcode eles são exibidos normalmente.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também