Observabilidad moderna con OpenTelemetry: De la detección a la Causa Raíz – Parte II

Introducción

Hace unas semanas, en la primera entrega de esta serie sobre Observabilidad moderna con OpenTelemetry, nos sumergimos de lleno en el complejo mundo de las arquitecturas de microservicios y cloud native. Dejamos claro que, hoy en día, limitarse a la monitorización tradicional y saber simplemente si un servicio está «vivo» ya no es suficiente. Para dominar los temidos problemas desconocidos o «unknown unknowns», necesitamos ir un paso más allá del ¿qué está pasando? y ser capaces de responder al crucial ¿por qué está pasando?

Para refrescar la memoria, en el artículo anterior desgranamos los pilares que hacen esto posible:

  • Las tres señales orquestadas: Vimos cómo las métricas detectan que algo ocurre, las trazas distribuidas localizan exactamente dónde está el cuello de botella y el viaje de la petición, y los logs aportan el contexto final explicando el porqué exacto del fallo.
  • El superpoder de la correlación: Cómo la unión de estos datos reduce drásticamente el MTTK (Mean Time to Know) y el MTTR, permitiendo a los equipos diagnosticar incidentes complejos de forma ágil y con un impacto directo en el negocio.
  • OpenTelemetry como el estándar definitivo: Analizamos este proyecto de la CNCF como la solución vendor-agnostic perfecta para instrumentar nuestras aplicaciones una sola vez. Además, exploramos las dos vías para implementarlo: la rapidez de la instrumentación automática (Zero-Code) frente al control total de la lógica de negocio que ofrece la manual a través del SDK.
 

Con los cimientos teóricos bien asentados y el ecosistema de OpenTelemetry claro, ha llegado el momento de dar el siguiente paso y ponernos manos a la obra. En esta segunda parte, pasaremos de la teoría a la acción para descubrir cómo instrumentar nuestra aplicación, para ello, utilizaremos un ejemplo muy sencillo.  

Ahora vamos a aterrizar estos conceptos, vamos a analizar un ejemplo práctico: una sonda de latencia SMTP/Gmail. Esta aplicación, escrita en Python, se despliega como un Job en Google Cloud Run y se ejecuta de forma periódica. Su cometido es sencillo pero potente: envía un email vía SMTP, sondea la API de Gmail para confirmar su recepción, y mide los tiempos en cada paso. Al finalizar realiza borrado del email para evitar llenado del buzón (también medido).

A continuación, diseccionamos cómo hemos instrumentado este código para que no solo «haga su trabajo», sino que sea observable desde el primer minuto. 

1. Inicialización y configuración

El corazón de nuestra telemetría reside en la función init_otel. Aquí definimos el Resource (con metadatos como la versión del servicio o el entorno) y los exportadores OTLP. Es crucial configurar tanto el TracerProvider como el MeterProvider para que nuestra sonda pueda emitir datos de forma estructurada.

2. Instrumentación: El viaje de los datos (Spans)

La magia ocurre mediante la creación de spans que envuelven las operaciones críticas. Cada fase tiene su propio contexto:

  • `probe_run` (Span padre): Engloba toda la ejecución. Aquí añadimos atributos semánticos como messaging.destination o el UID de la prueba, permitiendo una trazabilidad total.
  • `smtp_send`: Mide el tiempo de conexión y envío. Hemos enriquecido este span con atributos específicos como smtp.response_code y smtp.server_message, capturando datos reales del protocolo SMTP que nos ayudan a entender fallos de comunicación.
  • `gmail_poll`: Un bucle de sondeo donde cada iteración es un span independiente. Esto es vital: nos permite visualizar en nuestro backend de observabilidad cuántos intentos fueron necesarios hasta encontrar el email, ofreciendo una visibilidad granular de la latencia de recepción.
  • `gmail_delete`: La etapa final de limpieza, también instrumentada para medir tiempos de latencia con la API de Google.
 

Implementar esto es muy sencillo gracias al SDK. Utilizamos tracer.start_as_current_span para delimitar cada operación y set_attribute para inyectar información de contexto crucial que será vital durante el debug:

Ejemplo de visualización de ejecución completa, donde se puede observar el tiempo de envío, la conexión con google, las peticiones a gmail y las esperas hasta confirmar la recepción y la posterior limpieza.

3. El "Superpoder": Correlación de Logs

Un punto destacado es nuestra implementación de TraceContextFilter. Al heredar de logging.Filter, inyectamos automáticamente el trace_id y el span_id en cada línea de log. ¿El resultado? Cuando algo falla, no solo ves el mensaje de error en tus logs; tienes un enlace directo a la traza exacta que causó ese error, permitiéndote saltar del «por qué» (log) al «dónde» (traza) en un solo clic.

Para lograr esta correlación automática entre logs y trazas, inyectamos el contexto de OpenTelemetry mediante un filtro de logging personalizado. Este filtro captura el trace_id y span_id activos en el momento del log y los añade al registro:

Con este simple cambio ya podemos obtener información acerca de modelo utilizado, parámetros, tokens de input y output, costes de cada llamada y costes por usuario, entre otros indicadores.

4. Gestión de Métricas: Asegurando la entrega

En aplicaciones de corta duración o procesos efímeros, como un Job de Cloud Run, el ciclo de vida es crítico. Si el programa finaliza abruptamente, los datos que OpenTelemetry tiene en memoria (pendientes de exportación) podrían perderse. Por ello, es imperativo realizar un ‘flush’ manual y un ‘shutdown’ controlado.

El bloque ‘finally’ asegura que, independientemente de si la ejecución fue exitosa o terminó en error, las señales (métricas y trazas) se envíen al backend antes de que el contenedor desaparezca, garantizando la integridad de nuestros datos de observabilidad.

Ejemplo de visualización de los tiempos gastados en cada uno de los servicios dependiente, en nuestro ejemplo, muy simple, únicamente el servidor STMP y la api de google/gmail.

Conclusión

Instrumentar nuestra aplicación, incluso en escenarios sencillos como un Job de ejecución periódica, cambia radicalmente nuestra capacidad para entender el comportamiento de nuestros sistemas. Hemos visto cómo, con unos pocos bloques de código y una correcta estrategia de instrumentación, pasamos de «sospechar» qué ocurre a tener certezas basadas en datos. La observabilidad no es una meta, sino un proceso continuo de mejora. Os animo a aplicar estos mismos patrones en vuestros propios servicios; la claridad que aporta OpenTelemetry no solo facilita el diagnóstico de errores, sino que os dará una confianza inigualable en vuestro código. ¡Es hora de empezar a observar vuestros sistemas como nunca antes lo habíais hecho!

Ejemplo de visualización con los tiempos de ejecución a lo largo de la última noche.

¿Te has quedado con alguna duda sobre cómo instrumentar tu código, correlacionar tus logs o reducir tu MTTR? No tienes porqué hacer este viaje solo. ¡Escríbenos en LinkedIn o déjanos un comentario!

Álvaro Olmedo.

Imagen de Ivan Blanco

Ivan Blanco

¿Te ha resultado interesante?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Entradas relacionadas

Observabilidad moderna con OpenTelemetry: De la detección a la Causa Raíz – Parte II

Observabilidad para IA Generativa: más allá de métricas, logs y trazas

ExpoRetail Iberoamérica impulsa nuestra visibilidad en los principales medios del sector

¿Quieres saber más?