Log Level — clasificación de los mensajes de registro según su nivel de criticidad, que permite a los desarrolladores controlar el volumen de información mostrada en las distintas etapas del funcionamiento de la aplicación. Según Google Android Developers, 2024, elegir el nivel de registro adecuado reduce el volumen de logs en producción en un 85–95% y acelera el diagnóstico de errores. Cada nivel cumple su función, desde la depuración en la fase de desarrollo hasta la supervisión de fallos críticos en producción.
Puntos clave
Log Level es un atributo de cada mensaje de registro que determina su importancia y urgencia de procesamiento. Las plataformas modernas iOS y Android admiten una escala unificada de 6 a 7 niveles: desde el más detallado (Verbose/Trace) hasta el crítico (Error/Assert). La elección del nivel determina si el mensaje se escribirá en el registro con la configuración actual de la aplicación.
El concepto de Log Level se basa en el principio de la pirámide de criticidad: cuanto más alto es el nivel, menos mensajes se muestran en él. Según Semaphore CI, 2024, en una aplicación de producción la distribución es la siguiente: Info — 60% de los mensajes, Warn — 25%, Error — 10%, Debug — 5%. Los mensajes Verbose deben estar completamente desactivados en producción.
Cada plataforma implementa Log Level a través de su propia API. Android usa android.util.Log con los métodos v(), d(), i(), w(), e(). Apple usa OSLog con los niveles default, info, debug, error, fault. Bibliotecas como Timber y CocoaLumberjack añaden funcionalidades adicionales sobre estas API estándar.
Según Google I/O 2023, la elección incorrecta del Log Level es la causa del 40% de los problemas de rendimiento en producción. Los desarrolladores dejan logs Debug en las compilaciones de lanzamiento, lo que provoca escritura excesiva en disco y un desgaste acelerado de la batería.
Verbose (TRACE) — el nivel más detallado, destinado exclusivamente al desarrollo. En este nivel se muestran todos los cálculos intermedios, iteraciones de bucles y resultados de cada paso del algoritmo. En Android, este nivel corresponde a Log.v(), en iOS — OSLog con tipo debug (antes de iOS 14 se usaba os_trace).
Debug — mensajes de depuración útiles durante el desarrollo y las pruebas. Contienen información sobre el estado de objetos clave, resultados de consultas SQL y parámetros de llamadas API. A diferencia de Verbose, los mensajes Debug están estructurados y tienen significado semántico. En iOS, este nivel corresponde a OSLogType.debug.
Info — mensajes informativos sobre eventos normales de la aplicación: inicialización del SDK, autenticación exitosa, apertura de pantalla, obtención de datos del servidor. Los mensajes Info no deben contener datos personales de los usuarios y deben ser seguros para el análisis en producción. En iOS se usa OSLogType.info, en Android — Log.i().
Warn — advertencias sobre problemas potenciales. La aplicación sigue funcionando, pero la situación requiere atención: tamaño de caché cerca del límite, versión obsoleta de API, respuesta de red lenta, reintento de conexión. En Android — Log.w(), en iOS — OSLogType.default (para advertencias).
Error — errores críticos en los que la aplicación no puede realizar la operación solicitada pero sigue funcionando: solicitud API fallida, pérdida de conexión, error de escritura en la base de datos, falta de permisos. En iOS se usa OSLogType.error para errores, en Android — Log.e().
Assert (WTF) — el nivel más alto, que indica una situación que “no puede ocurrir.” Se usa para registrar errores que violan invariantes fundamentales del sistema. En Android, los mensajes Assert no se muestran en compilaciones de lanzamiento por defecto. En iOS, WTF (What a Terrible Failure) se maneja mediante OSLogType.fault.
Android Log API — el mecanismo de registro integrado del paquete android.util.Log. Proporciona 6 métodos estáticos: Log.v(), Log.d(), Log.i(), Log.w(), Log.e() y Log.wtf(). Cada método recibe un tag (cadena identificadora de la fuente) y msg (texto del mensaje).
class UserRepository {
companion object {
private val TAG = "UserRepo"
}
suspend fun loadUser(id: String): User {
Log.d(TAG, "Cargando usuario con id: $id")
return try {
val response = api.fetchUser(id)
Log.i(TAG, "Usuario cargado correctamente")
response.toUser()
} catch (e: Exception) {
Log.e(TAG, "Error al cargar el usuario: ${e.message}")
throw e
}
}
}
Filtrado por niveles en Android Logcat se realiza mediante ADB: adb logcat *:E mostrará solo mensajes Error. En compilaciones de producción, todas las llamadas Log.v() y Log.d() se eliminan con ProGuard/R8 cuando la minificación está activada. Log.i(), Log.w() y Log.e() permanecen, por lo que es importante no mostrar datos sensibles a través de estos métodos.
Para filtrado personalizado en tiempo de ejecución, Android proporciona Log.isLoggable(tag, level) — un método que comprueba si el nivel especificado está activado para el tag dado. Esto permite activar dinámicamente el registro detallado para un módulo específico sin recompilar la aplicación.
OSLog — el sistema de registro unificado de Apple, que reemplaza al obsoleto NSLog. OSLog proporciona 5 niveles: debug, info, default (notice), error y fault. La principal ventaja es el registro estructurado con soporte para cadenas formateadas y filtrado dinámico a través de la consola.
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
func fetchData(from url: URL) {
logger.debug("Starting request to \(url.absoluteString)")
do {
let data = try Data(contentsOf: url)
logger.info("Received \(data.count) bytes")
} catch {
logger.error("Request failed: \(error.localizedDescription)")
}
}
El sistema de filtrado de OSLog funciona a nivel del sistema operativo. Los mensajes Debug solo se escriben cuando el depurador está conectado o cuando se activa el argumento -com.apple.CoreData.Logging.debug 1. Los mensajes Info se recogen en la memoria del dispositivo (hasta 512 KB) y son accesibles a través de Console.app. Los mensajes Error y fault se escriben continuamente y están disponibles para su recogida a través de sistemas de informes de fallos.
Una característica importante de OSLog: cadenas formateadas con marcadores de posición. En lugar de la interpolación de cadenas de Swift (que se evalúa siempre, independientemente del nivel), OSLog usa el formato os_log con %{public}@ y %{private}@ para distinguir datos sensibles. Los parámetros privados se enmascaran en los logs de producción.
La regla principal — un conjunto mínimo de niveles en producción: Info, Warn, Error, Assert. Debug y Verbose deben estar desactivados. La razón no es tanto la seguridad como el rendimiento: cada llamada de registro consume tiempo de CPU para formatear la cadena, incluso si el mensaje no se muestra.
Optimización crítica — nunca uses interpolación de cadenas en llamadas de registro. Si la cadena se construye antes de la llamada log(), se desperdicia tiempo de CPU incluso cuando el nivel está desactivado. Usa formateo perezoso mediante lambdas o condiciones de guardia.
En Android, el método Log.isLoggable() cumple este propósito; en OSLog, se admiten cadenas formateadas nativas con marcadores de posición. Timber para Android resuelve el problema mediante timber.log.Tree con verificación de nivel dentro del árbol.
Remote Log Level — una práctica en la que el nivel de registro se controla desde el servidor mediante Firebase Remote Config o un servicio similar. Si ocurre un error complejo en producción, el desarrollador puede activar remotamente el registro Debug para un módulo específico en los dispositivos de un grupo de usuarios seleccionado.
Según Firebase, 2024, esta práctica reduce el tiempo de diagnóstico de errores raros en un 60% y permite obtener una imagen completa del problema sin instalar una compilación de depuración. La principal limitación es que el registro solo se activa en el siguiente inicio de la aplicación después de recibir la configuración.
BuildConfig.DEBUG en Android y #if DEBUG en Swift son mecanismos estándar de compilación condicional que desactivan los niveles de depuración en compilaciones de lanzamiento. Para una arquitectura limpia, se recomienda mover la selección del Log Level a un contenedor DI o fábrica de registradores para no saturar la lógica de negocio con directivas condicionales.
Primera regla — cada llamada de registro debe responder a la pregunta “quién, qué, cuándo.” Quién — el componente o módulo (tag en Android, category en iOS). Qué — el evento específico o cambio de estado. Cuándo — la marca de tiempo, añadida automáticamente por el sistema de registro.
Segunda regla — no registres datos sensibles a través de Info y superiores. Contraseñas, tokens, correos electrónicos, números de teléfono, coordenadas geográficas precisas están categóricamente prohibidos en cualquier registro que llegue a producción. Si es necesario, usa enmascaramiento: “email: us***@example.com.”
Tercera regla — el nivel Warn es responsabilidad del desarrollador, Error es del equipo. Warn significa “aquí hay un problema potencial, vigílalo.” Error significa “aquí hay un problema, arréglalo.” No uses Error para situaciones que son esperadas y manejadas (por ejemplo, un error 404 de API).
Cuarta regla — consistencia. Todo el proyecto debe usar convenciones de nomenclatura unificadas para tags y categorías. Se recomienda ClassName.methodName para tags de Android y module.subsystem para categorías de iOS. Esto permite filtrar rápidamente los registros por componente.
Quinta regla — prueba tus registros. En pruebas unitarias, verifica que se llame al Log Level correcto en escenarios específicos. Existen bibliotecas mock de registro para este propósito: Mockito para Android, Cuckoo para iOS. Verificar los niveles en las pruebas evita que los mensajes de depuración se filtren a producción.
Preguntas frecuentes
Desgaste acelerado de la batería y escritura excesiva en disco. Cada log Debug formatea una cadena y escribe datos en el búfer. En dispositivos con memoria Flash, esto acelera el desgaste del almacenamiento. Además, los logs Debug pueden contener datos sensibles que no deberían verse en producción.
Debug — para el cuerpo de la solicitud y respuesta, encabezados y código de estado. Info — para el hecho de la solicitud completada (URL, método, duración). Error — para solicitudes fallidas con códigos 4xx/5xx. Nunca uses Verbose para logs de red en producción.
OSLogType.default (nivel notice) — mensajes de importancia media, guardados en el registro del sistema y visibles en Console.app. OSLogType.info — mensajes técnicos, no se guardan permanentemente, solo están disponibles durante la creación de perfiles activa mediante Instruments.
R8/ProGuard elimina Log.v() y Log.d() cuando la minificación está activada en compilaciones de lanzamiento. Log.i(), Log.w() y Log.e() se conservan. Para eliminar completamente todos los logs, se requiere una regla personalizada -assumenosideeffects class android.util.Log con todos los niveles especificados.
No — el registro excesivo perjudica la legibilidad y el rendimiento. Registra la entrada solo en métodos complejos o asíncronos. Para métodos síncronos, basta con un solo registro en el punto de retorno o error. Usa el nivel Debug para el rastreo de llamadas.
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