Registro en aplicaciones Kotlin: mejores prácticas
El registro no es solo una grabación de eventos, sino una herramienta clave para la depuración, el monitoreo y el análisis del funcionamiento de una aplicación. En el ecosistema de Kotlin, gracias a la compatibilidad total con Java, están disponibles todas las bibliotecas populares, como SLF4J y Logback. Sin embargo, Kotlin ofrece sus propios enfoques idiomáticos que hacen que el código sea más limpio y seguro. En este artículo, analizaremos las mejores prácticas de registro en Kotlin: desde la elección de la biblioteca hasta la configuración de registros estructurados para producción.
1. Elección de la biblioteca para el registro en Kotlin
La pila más popular para aplicaciones Kotlin es SLF4J (fachada) + Logback (implementación). Sin embargo, para Kotlin se recomienda usar el envoltorio kotlin-logging, que añade funciones inline y evita gastos generales innecesarios.
// build.gradle.ktsdependencies { implementation("io.github.microutils:kotlin-logging:3.0.5") implementation("ch.qos.logback:logback-classic:1.4.14")}Ventajas de kotlin-logging:
- Inicialización perezosa del logger — el logger se crea solo en la primera invocación.
- Funciones inline — la comprobación del nivel de registro ocurre en la etapa de compilación, lo que reduce la sobrecarga.
- Soporte para funciones suspend — funcionamiento correcto en corrutinas.
Ejemplo de declaración del logger:
import mu.KotlinLogging
private val logger = KotlinLogging.logger {}2. Niveles de registro correctos
El uso del nivel correcto es la base de los registros legibles. En Kotlin, al igual que en Java, están disponibles 5 niveles: TRACE, DEBUG, INFO, WARN, ERROR.
Recomendaciones:
- TRACE — solo para depuración detallada (por ejemplo, entrada/salida de un método).
- DEBUG — información para el desarrollador (valores de variables, estado de objetos).
- INFO — eventos de negocio (solicitud procesada, usuario autenticado).
- WARN — situaciones anómalas que no rompen la aplicación (reintento de conexión).
- ERROR — excepciones y fallos que requieren atención.
Ejemplo con diferentes niveles:
logger.debug { "Procesando solicitud: $requestId" }logger.info { "Usuario ${user.name} registrado exitosamente" }logger.warn { "El pool de conexiones está al 90%, tamaño actual: $poolSize" }logger.error(ex) { "Error al guardar el pedido ${orderId}" }Importante: En Kotlin, para pasar una excepción use logger.error(throwable) { "mensaje" }, no logger.error("mensaje", throwable) — esto es más idiomático.
3. Registro estructurado (JSON)
En las arquitecturas modernas de microservicios, los registros de texto son incómodos para el análisis. Es mejor usar registros estructurados en formato JSON. Esto permite filtrar fácilmente los registros en ELK, Grafana o Splunk.
Configuración de Logback para registros JSON:
// logback.xml<configuration> <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="net.logstash.logback.encoder.LogstashEncoder"/> </appender>
<root level="INFO"> <appender-ref ref="JSON"/> </root></configuration>Para agregar campos personalizados, use MDC (Mapped Diagnostic Context):
import org.slf4j.MDC
fun processOrder(orderId: String) { MDC.put("orderId", orderId) MDC.put("userId", currentUserId()) logger.info { "Inicio del procesamiento del pedido" } // ... lógica MDC.clear()}