Registro en aplicaciones Kotlin: mejores prácticas en la práctica
El registro no es solo escribir mensajes en la consola. En las aplicaciones modernas de Kotlin (backends de servidor, Android, Ktor, Spring Boot), un registro correctamente configurado es la base para la monitorización, depuración y auditoría. Sin él, literalmente estás trabajando a ciegas. En este artículo, analizaremos las mejores prácticas de registro en Kotlin con ejemplos de código reales y configuraciones de nivel de producción.
1. Elección de la biblioteca: por qué SLF4J + Logback es el estándar de la industria
En el mundo JVM, el estándar de facto es SLF4J (Simple Logging Facade for Java) junto con Logback. Kotlin es completamente compatible con las bibliotecas de Java, por lo que esta combinación funciona de forma nativa. Para Kotlin, existe un envoltorio conveniente llamado kotlin-logging que agrega funciones de extensión y evaluación perezosa inline.
Agregar dependencias (Gradle)
// build.gradle.ktsdependencies { implementation("io.github.microutils:kotlin-logging:3.0.5") implementation("ch.qos.logback:logback-classic:1.4.14")}Uso básico
import mu.KotlinLogging
private val logger = KotlinLogging.logger {}
fun processOrder(orderId: String) { logger.info { "Procesamiento del pedido $orderId iniciado" } // lógica de negocio logger.debug { "Detalles del pedido: ${fetchOrderDetails(orderId)}" }}Observa la evaluación perezosa (lambda {}): la cadena solo se forma si el nivel de registro está activo. Esto es críticamente importante para el rendimiento.
2. Niveles de registro: cuándo usar cada uno
Elegir el nivel incorrecto es uno de los errores más comunes. Usa esta tabla como referencia rápida:
- ERROR — solo para errores fatales que requieren intervención inmediata (excepciones, pérdida de datos).
- WARN — situaciones potencialmente peligrosas que no rompen el sistema ahora (por ejemplo, superar el límite de intentos).
- INFO — eventos comerciales clave: inicio/parada del servicio, registro exitoso, finalización del pago.
- DEBUG — información para el desarrollador: parámetros de entrada, estado de objetos, pasos del algoritmo.
- TRACE — máxima granularidad, generalmente para activación temporal al buscar errores.
Ejemplo de uso correcto
class PaymentService(private val paymentGateway: PaymentGateway) { private val logger = KotlinLogging.logger {}
fun processPayment(userId: String, amount: BigDecimal): PaymentResult { logger.info { "Pago iniciado: userId=$userId, amount=$amount" }
return try { val result = paymentGateway.charge(userId, amount) if (result.success) { logger.info { "Pago exitoso: transactionId=${result.transactionId}" } } else { logger.warn { "Pago rechazado: userId=$userId, reason=${result.reason}" } } result } catch (e: PaymentException) { logger.error(e) { "Error crítico de la pasarela de pago para userId=$userId" } throw e } }}3. Registro estructurado: JSON y contexto
Los sistemas modernos (ELK, Grafana Loki, Datadog) funcionan mejor con registros estructurados. Logback puede escribir JSON, y Kotlin permite agregar contexto fácilmente a través de MDC (Mapped Diagnostic Context).
Configuración de Logback para JSON (logback.xml)
<?xml version="1.0" encoding="UTF-8"?><configuration> <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.JsonEncoder"/> </appender>
<root level="INFO"> <appender-ref ref="JSON"/>