os_log es la API de registro unificado de Apple para iOS y macOS que reemplazó a NSLog y os_trace. A diferencia de los mecanismos antiguos, os_log funciona a nivel del núcleo: los mensajes se almacenan en un búfer circular y se escriben en el disco solo cuando se alcanza un umbral de actividad. Según Apple WWDC 2016, os_log reduce la carga del disco en 10 veces en comparación con NSLog y brinda control sobre el nivel de detalle a través de categorías y tipos. Es la herramienta de diagnóstico principal para el desarrollador de iOS: a través de Console.app se pueden filtrar mensajes por proceso, categoría y nivel de criticidad en tiempo real.
Puntos clave
os_log es una API de registro unificado presentada por Apple en iOS 10 y macOS Sierra. Unificó los mecanismos de registro dispares NSLog, os_trace y syslog en un solo sistema con almacenamiento en búfer a nivel del núcleo XNU.
A diferencia de NSLog, que escribe de forma síncrona cada mensaje en el disco y bloquea el hilo, os_log utiliza un búfer circular asíncrono en memoria. Los mensajes se vacían al disco solo cuando la actividad supera un umbral establecido o mediante el comando log collect. Esto reduce radicalmente el impacto del registro en el rendimiento de la aplicación.
os_log admite seis niveles de criticidad, diferenciación por subsystem y category, y un mecanismo de privacidad integrado: los datos marcados como private se enmascaran automáticamente en los registros de producción y solo están disponibles para el desarrollador cuando está conectado a través de Xcode.
Antes de iOS 10, los desarrolladores usaban NSLog para la depuración y syslog para los mensajes del sistema. NSLog escribía en stderr y en la consola, pero era extremadamente ineficiente: cada mensaje se escribía de forma síncrona en el disco, causando retrasos en la UI con el registro frecuente. os_log resolvió este problema trasladando el almacenamiento en búfer a la parte BSD del núcleo XNU y haciendo que las escrituras en el disco fueran asíncronas.
os_log se utiliza en todas las aplicaciones de Apple y es recomendado por Apple como la única API de registro para iOS, macOS, tvOS y watchOS. El sistema y las aplicaciones de terceros escriben mensajes a través de él en una base de datos unificada — se almacena en memoria y se vacía periódicamente al disco. Estos registros se pueden analizar a través de Console.app en Mac o mediante el comando log en la terminal.
La arquitectura de os_log consta de tres capas: una API del lado del cliente en el espacio de usuario (libsystem_trace.dylib), un búfer circular en el núcleo XNU y el demonio logd que vacía el búfer de forma asíncrona al disco.
Cuando una aplicación llama a os_log, el mensaje se copia en un búfer circular del núcleo de varios megabytes. El búfer funciona según el principio FIFO: si está lleno, los mensajes antiguos se sobrescriben con los nuevos. El demonio logd verifica periódicamente el búfer y guarda los mensajes en archivos .tracev3 en un área protegida del sistema de archivos.
Según Apple Engineering, el retraso típico desde la llamada a os_log hasta la aparición del mensaje en Console.app es de 1 a 5 segundos en un dispositivo y de hasta 60 segundos al vaciar al disco en modo lote. Esta es una compensación deliberada: el rendimiento de la aplicación no se ve afectado por el registro, pero el desarrollador ve los mensajes con un ligero retraso.
// Declaración de os_log a través de OSLog
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
El búfer circular de os_log tiene un tamaño fijo y no se puede cambiar desde el espacio de usuario. El tamaño del búfer varía de 256 KB en Apple Watch a 4 MB en Mac. Cuando una aplicación genera más mensajes de los que el búfer puede contener, los mensajes antiguos se pierden — este es un comportamiento esperado para el registro de alto volumen.
Para la recopilación a largo plazo de todos los mensajes, se utiliza el comando log collect. Este inicia un demonio de recopilación en el dispositivo y exporta un .logarchive a la computadora del desarrollador. En este modo, el búfer no se sobrescribe — los mensajes se escriben directamente en el archivo.
os_log admite cinco niveles de criticidad, cada uno responsable de un tipo diferente de mensaje y procesado de forma diferente por el sistema. Default es el nivel base para los mensajes que siempre entran en el búfer. Info y Debug están deshabilitados en las compilaciones de producción sin un perfil de recolección. Error y Fault siempre están activos y se marcan con una bandera especial en la base de datos.
| Nivel | Significado | Entrada al búfer por defecto |
|---|---|---|
| Default | Mensajes normales importantes para el diagnóstico | Sí |
| Info | Mensajes informativos para análisis detallado | No (solo con perfil) |
| Debug | Mensajes de depuración para desarrollo | No (solo con perfil) |
| Error | Errores que requieren atención | Sí |
| Fault | Fallos críticos que provocan bloqueos | Sí |
Elegir el nivel de criticidad correcto es importante para el rendimiento: Info y Debug no se escriben en el disco en modo normal, por lo que se pueden usar abundantemente sin riesgo de ralentizar la aplicación. Error y Fault siempre se guardan, pero su cantidad debe ser mínima — cada uno de estos mensajes aumenta el tiempo de escritura debido a los metadatos adicionales.
Subsystem es un identificador de aplicación o módulo en formato reverse-DNS (com.example.app). Category es una etiqueta de texto dentro de un subsystem que agrupa los registros por áreas funcionales: network, ui, database, auth. Esta jerarquía permite filtrar registros sin leer cada mensaje y recopilar estadísticas para cada módulo por separado.
Apple recomienda definir un OSLog por módulo y usarlo en todos los archivos de ese módulo. Para las diferentes capas de la aplicación — networking, UI, persistencia — se deben crear categorías separadas. Luego, en Console.app se pueden habilitar los registros solo para network y deshabilitarlos para otros sin recompilar la aplicación.
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 proporciona un mecanismo de control de privacidad integrado: cada valor en una cadena de formato se puede marcar como public, private o auto (comportamiento predeterminado). Por defecto, os_log considera todas las cadenas dinámicas y objetos como potencialmente confidenciales y los reemplaza con la máscara <private> en los registros de producción.
Esto es fundamental para el cumplimiento de GDPR y HIPAA: si una aplicación registra el correo electrónico o el número de tarjeta de un usuario a través de os_log en modo automático, los datos reales nunca llegan al disco. El desarrollador ve el mensaje completo solo cuando está conectado a través de Xcode o cuando usa un perfil de recolección de un dispositivo conectado al mismo Mac.
let email = "user@example.com"
logger.log("User login: \(email, privacy: .public)")
// En registros de producción: "User login: "
// En depuración con Xcode: "User login: user@example.com"
logger.log("Payment token: \(token)")
Los números (Int, Double, Float) se consideran públicos por defecto — se pueden registrar de forma segura sin marcar. Las cadenas (String, NSString, StaticString) y los objetos (NSObject, CFType) son privados por defecto — se enmascaran en producción. Las cadenas estáticas (literales de cadena entre comillas dentro de la cadena de formato) siempre son visibles — son parte del mensaje en sí, no datos.
Este comportamiento difiere de NSLog, donde todos los datos se registraban en texto plano. La migración a os_log reduce significativamente el riesgo de filtración de datos confidenciales del usuario a través de los registros.
os_log es un 90–95% más rápido que NSLog en el registro de alta frecuencia. En una prueba con 10 000 llamadas en un bucle, NSLog crea un retraso de aproximadamente 2.8 segundos, mientras que os_log realiza las mismas llamadas en 0.3 segundos. La diferencia se explica por las escrituras síncronas en el disco en NSLog frente al almacenamiento en búfer asíncrono en os_log.
Según Apple Performance Lab (2016), una aplicación de iOS con 20 llamadas de registro por segundo a través de NSLog pierde de 5 a 8 fotogramas de animación por segundo debido al bloqueo del hilo principal. Con os_log no hay pérdida de fotogramas porque el almacenamiento en búfer ocurre en un hilo separado del núcleo.
| Parámetro | NSLog | os_log |
|---|---|---|
| Mecanismo de escritura | Escritura síncrona en disco | Almacenamiento en búfer asíncrono en el núcleo |
| Tiempo para 10 000 llamadas | ~2.8 s | ~0.3 s |
| Impacto en FPS | Pérdida de 5–8 fotogramas | 0 fotogramas |
| Niveles de criticidad | Ninguno | 5 niveles |
| Privacidad | Todos los datos visibles | Enmascaramiento automático |
| Filtrado | No compatible | Por subsystem / category / level |
os_log tiene dos API: la clásica en C os_log_create y el envoltorio moderno de Swift Logger presentado en iOS 14. El Logger de Swift utiliza el sistema ResultBuilder para el formateo — los argumentos se interpolan a través de literales de cadena con marcado explícito de privacidad.
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 es una utilidad de línea de comandos para exportar los registros recopilados de un dispositivo. Se ejecuta desde Terminal después de conectar el dispositivo a un Mac mediante USB.
// Recopilación de registros en .logarchive
// En Terminal: log collect --device --output ./app_logs.logarchive
// Visualización de registros de subsystem: log show --subsystem com.example.app
// Registro con valores dinámicos
logger.log("User \(userId) opened screen \(screenName)")
Al usar Logger, es importante recordar que los argumentos se interpolan mediante String Interpolation, no a través de cadenas de formato como en la versión C de os_log. Esto es más seguro, pero requiere el marcado explícito de privacidad para cada argumento si el comportamiento predeterminado no es adecuado para el desarrollador.
Preguntas frecuentes
os_log almacena mensajes en el búfer de forma asíncrona en el núcleo y no bloquea el hilo principal, mientras que NSLog escribe de forma síncrona en el disco. os_log es 10 veces más rápido, ofrece 5 niveles de criticidad y enmascara automáticamente los datos privados — NSLog no tiene ninguna de estas características.
Para mensajes de depuración temporales, use .debug — se deshabilitan en las compilaciones de producción y no afectan el rendimiento de los usuarios. Para mensajes importantes que deben conservarse siempre, use .default o .info.
A través de Configure Profile en Xcode: Devices → seleccione el dispositivo → Open Console → Actions → Configure Profile. Establezca el nivel de recolección para el subsystem deseado en Include. Esto crea un perfil que permanece activo hasta el primer reinicio del dispositivo.
Sí, os_log funciona en todas las aplicaciones SwiftUI sin configuración adicional. Cree un Logger estático en su modelo o en una extensión de View y úselo en onChange, task y manejadores de gestos para rastrear el ciclo de vida de las pantallas.
Por defecto, os_log enmascara las cadenas y los objetos como private. Para ver el valor, especifique explícitamente privacy: .public en la interpolación. Sin esta marcación, los valores se reemplazarán por la máscara en las compilaciones de producción, pero en la depuración con Xcode se muestran normalmente.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también