El resultado final del código desarrollado en este documento se puede encontrar en el monorepo de GitHub springboot-demo-projects, bajo el tag observability.
La observabilidad se trata de entender qué está haciendo tu aplicación en producción sin tener que agregar print statements y redeployar. Cuando algo se rompe a las 3 de la mañana, necesitás rastrear requests entre servicios, ver logs de errores en contexto y entender cuellos de botella de performance sin adivinar.
Recolección de datos (La Aplicación): Modificás la app para incluir código especializado que recolecta varios tipos de datos sobre el estado interno de la app y el entorno del servidor host.
Almacenamiento de datos (Los Backends de Telemetría): Los datos recolectados se envían fuera del proceso de la aplicación y van a backends de telemetría correspondientes y optimizados, bases de datos diseñadas específicamente para logs, métricas o traces.
Visualización (El Dashboard): Usás una herramienta de visualización poderosa (como Grafana) para extraer los datos almacenados de los backends y presentarlos en dashboards coherentes y legibles.
Grafana actúa como el "único panel de vidrio" que unifica los tres tipos de datos. Es una plataforma de visualización basada en web que se conecta a múltiples backends de telemetría simultáneamente.
Estas son las opciones más comunes en el ecosistema de Grafana, pero no son las únicas. Las alternativas incluyen Elasticsearch para logs, InfluxDB para métricas, y Jaeger para traces.
Visión general de la arquitectura de observabilidad
Así es como las partes móviles se integran entre sí:
Scroll to zoom • Drag corner to resize
El flujo funciona así:
Las apps de Spring Boot exponen métricas vía Micrometer y envían traces vía OTLP a Tempo
Promtail scrapea los logs de contenedores Docker y los envía a Loki
Prometheus scrapea métricas del endpoint /actuator/prometheus de cada app
Grafana consulta los tres backends para mostrar dashboards unificados
A continuación, un resumen de los archivos nuevos y modificados:
Cada servicio de Spring Boot recibe dos adiciones:
depends_on: Asegura que Tempo inicie antes que las apps
networks: Se une a la red monitoring para que las apps puedan llegar a Tempo
El stack de observabilidad incluye:
Prometheus: Scrapea métricas de todos los servicios
Loki: Almacena e indexa datos de logs
Promtail: Recolecta logs de contenedores Docker y los reenvía a Loki
Tempo: Recibe y almacena traces distribuidos
Grafana: Visualiza métricas, logs y traces en dashboards unificados
En la práctica, los setups son diferentes
En algunos proyectos, es común encontrar los servicios de observabilidad
viviendo en un proyecto de Docker Compose completamente separado, o incluso
gestionados por proveedores terceros como
Datadog o Grafana
Cloud. Meter todo en un solo
docker-compose.yml acá mantiene las cosas simples para la documentación y
hace que el setup sea más fácil de seguir.
Loki es un sistema de agregación de logs horizontalmente escalable, altamente disponible y multi-tenant inspirado en Prometheus.
Dockerfile:
observability/loki.Dockerfile
FROM alpine:latest AS builder RUN mkdir -p /loki/chunks /loki/rules FROM grafana/loki:3.5.10 COPY--from=builder--chown=10001:10001 /loki /loki COPY observability/loki-config.yml /etc/loki/local-config.yaml USER 10001
Usa un build multi-stage para crear directorios con permisos correctos (Loki corre como usuario 10001).
Configuración:
observability/loki-config.yml
auth_enabled:false server: http_listen_port:3100 grpc_listen_port:9096 common: instance_addr: 127.0.0.1 path_prefix: /loki storage: filesystem: chunks_directory: /loki/chunks rules_directory: /loki/rules replication_factor:1 ring: kvstore: store: inmemory query_range: results_cache: cache: embedded_cache: enabled:true max_size_mb:100 schema_config: configs: -from:2020-10-24 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h ruler: alertmanager_url: http://localhost:9093 compactor: working_directory: /loki/compactor compaction_interval: 10m retention_enabled:true retention_delete_delay: 2h retention_delete_worker_count:150 delete_request_store: filesystem limits_config: retention_period: 360h # 15 days, matches Prometheus and Tempo # By default, Loki will send anonymous usage data to Grafana. # This can be disabled by setting this to false analytics: reporting_enabled:false
auth_enabled: false: Deshabilita la autenticación para desarrollo local
storage.filesystem: Usa almacenamiento de filesystem local (adecuado para configuraciones de un solo nodo)
retention_period: Mantiene logs por 15 días (360 horas)
analytics.reporting_enabled: false: Deshabilita el reporte de uso anónimo
relabel_configs: Filtra solo servicios spring-* y renombra labels
pipeline_stages: Parsea líneas de log para extraer el nivel de log y crear labels indexadas
El patrón regex trace_id=\S+ span_id=\S+ trace_flags=\S+ (?P<type>\w+) \S+ --- extrae el nivel de log de tu formato de log de Spring Boot, habilitando el filtrado por tipo de log (INFO, ERROR, DEBUG, etc.) en Grafana.
Loki: Para logs, con extracción de trace ID para correlación
Tempo: Para traces, con links de vuelta a logs de Loki
Las configuraciones exemplarTraceIdDestinations y derivedFields habilitan la correlación de trace a log. Cuando ves un pico de métrica, podés clickear para ver el trace; cuando ves logs, podés clickear el trace ID para ver el trace distribuido completo.
): Métricas a nivel de aplicación con tasas de requests HTTP, tiempos de
respuesta y tasas de error
Estos se omiten del patch debido a su tamaño (miles de líneas de JSON), pero
podés encontrarlos en el repositorio en
observability/grafana/dashboards/.
Cuando deployás a Coolify, la plataforma detecta automáticamente los nuevos servicios definidos en tu docker-compose.yml y los inicia junto con tus aplicaciones de Spring Boot. No necesitás configurar manualmente el stack de monitoreo.
El único paso adicional es asignar un dominio a Grafana para que puedas acceder a los dashboards:
En Coolify, encontrá el servicio de Grafana en tu proyecto
Clickeá en él y configurá un dominio (ej., grafana.tudominio.com)
Coolify se encargará de los certificados SSL y el routing
Variables de entorno de Grafana
Grafana espera que las variables de entorno
GF_SECURITY_ADMIN_USER y GF_SECURITY_ADMIN_PASSWORD
estén configuradas. Asegurate de definirlas en la configuración del servicio
de Coolify antes de iniciar el stack.