Observabilidad en Kotlin: trazado, métricas y registros en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Por qué la observabilidad es imprescindible para las aplicaciones Kotlin

\n\n

Imagina: tu aplicación Kotlin funciona en producción y, de repente, los usuarios se quejan de que las solicitudes tardan 10 segundos. Revisas los registros: silencio. Las métricas muestran un 100% de CPU, pero no indican qué endpoint específico está ralentizando. ¿Te suena familiar?

\n\n

Bienvenido al mundo donde la observabilidad no es una opción, sino una necesidad. A diferencia del monitoreo tradicional, que simplemente responde «sí/no» a la pregunta «¿el sistema está vivo?», la observabilidad permite hacer preguntas que antes ni siquiera imaginabas. Y Kotlin, con su concisión y su potente ecosistema, es ideal para adoptar esta cultura.

\n\n

En este artículo, analizaremos los tres pilares de la observabilidad —trazado, métricas y registros— y mostraremos cómo integrarlos con Kotlin. Sin rodeos, solo ejemplos de código reales.

\n\n

Trazado: el viaje de una solicitud a través de los microservicios

\n\n

El trazado distribuido (tracing) es como un GPS para tu solicitud. Ves por qué servicios pasó la solicitud, cuánto tiempo tomó cada paso y dónde ocurrió la demora. Para Kotlin, el mejor aliado en esto es OpenTelemetry (OTel).

\n\n

Configuración de OpenTelemetry en Kotlin

\n\n

Añade las dependencias en build.gradle.kts:

\n\n
dependencies {\n    implementation("io.opentelemetry:opentelemetry-api:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-sdk:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.36.0")\n    implementation("io.opentelemetry:opentelemetry-extension-kotlin:1.36.0")\n}
\n\n

Ahora creamos un trazador simple:

\n\n
import io.opentelemetry.api.GlobalOpenTelemetry\nimport io.opentelemetry.api.trace.Span\nimport io.opentelemetry.api.trace.Tracer\nimport io.opentelemetry.context.Scope\n\nclass OrderService(private val tracer: Tracer = GlobalOpenTelemetry.getTracer("order-service")) {\n\n    fun processOrder(orderId: String) {\n        val span: Span = tracer.spanBuilder("processOrder")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use { // use() cierra automáticamente el span\n            try {\n                // Simulación de trabajo\n                Thread.sleep(100)\n                validateOrder(orderId)\n                chargePayment(orderId)\n            } catch (e: Exception) {\n                span.recordException(e)\n                span.setStatus(StatusCode.ERROR, "Order processing failed")\n                throw e\n            }\n        }\n    }\n\n    private fun validateOrder(orderId: String) {\n        val span: Span = tracer.spanBuilder("validateOrder")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use {\n            Thread.sleep(50) // Simulación de validación\n        }\n    }\n\n    private fun chargePayment(orderId: String) {\n        val span: Span = tracer.spanBuilder("chargePayment")\n            .setAttribute("order.id", orderId)\n            .startSpan()\n\n        span.use {\n            Thread.sleep(150) // Simulación de pago\n        }\n    }\n}
\n\n

Observa span.use — es una función de extensión de opentelemetry-extension-kotlin que cierra automáticamente el span después de ejecutar el bloque. ¡La belleza de Kotlin en acción!

\n\n

Transmisión de contexto a través de corrutinas

\n\n

En Kotlin usamos activamente corrutinas. OpenTelemetry se lleva muy bien con ellas mediante el mecanismo de Context:

\n\n
import kotlinx.coroutines.withContext\nimport io.opentelemetry.api.trace.Span\nimport io.opentelemetry.context.Context\n\nsuspend fun processOrderAsync(orderId: String) = withContext(Context.current()) {\n    val span = tracer.spanBuilder("processOrderAsync").startSpan()\n    span.use {\n        // Tu lógica asíncrona\n    }\n}
\n\n

El trazado revela el panorama completo: ves que el 80% del tiempo se destina al pago

Blogs

Book Recommendations