El monitoreo tradicional se limita a saber si una aplicación está encendida o apagada. La observabilidad, en cambio, busca explicar por qué el sistema se comporta de cierta manera. En una arquitectura de microservicios, donde cada petición atraviesa docenas de componentes, es imprescindible medir latencia, tasas de error, registros estructurados y trazas distribuidas que permitan reconstruir los flujos. Este capítulo describe los pilares de observabilidad y cómo implementarlos con herramientas modernas.
Las métricas cuantifican el estado y rendimiento del sistema. Entre las más relevantes destacan la latencia (tiempo de respuesta), el throughput (cantidad de peticiones procesadas), los errores, el uso de recursos (CPU, memoria) y la capacidad disponible. Publicar métricas por servicio, instancia y versión permite identificar cuellos de botella y detectar regresiones tras un despliegue.
Se recomienda utilizar bibliotecas instrumentadas que expongan métricas en un formato estándar. En el ecosistema Java, Micrometer ofrece integraciones con Prometheus, Datadog o New Relic y permite definir contadores, histogramas y timers.
El siguiente código registra un temporizador para medir la duración de un proceso y expone contadores de errores.
@Service
public class PaymentProcessor {
private final Timer processingTime;
private final Counter errorCounter;
public PaymentProcessor(MeterRegistry registry) {
this.processingTime = Timer.builder("payments.processing.time")
.publishPercentileHistogram()
.publishPercentiles(0.5, 0.95, 0.99)
.tag("service", "payments")
.register(registry);
this.errorCounter = Counter.builder("payments.errors.total")
.tag("service", "payments")
.register(registry);
}
public void process(PaymentRequest request) {
processingTime.record(() -> {
try {
executeWorkflow(request);
} catch (Exception ex) {
errorCounter.increment();
throw ex;
}
});
}
}
Las métricas se exponen en el endpoint /actuator/prometheus y Prometheus las recolecta periódicamente para analizar tendencias y generar alertas.
Los registros locales se pierden cuando una instancia falla o se recrea. La centralización de logs recopila eventos de todas las instancias y los almacena en una plataforma consultable. Tecnologías como Elastic Stack, Fluentd y Grafana Loki permiten indexar, consultar y correlacionar logs con métricas y trazas.
Los servicios deben registrar eventos en formato estructurado (JSON) con campos como timestamp, nivel, servicio, instancia, identificador de correlación y mensaje. Así se facilita construir dashboards y reglas de detección de incidentes.
El siguiente fragmento de Logback genera registros JSON que luego son recolectados por un agente de logs.
<configuration>
<appender name="JSON" class="net.logstash.logback.appender.LoggingEventCompositeJsonEncoder">
<encoder>
<providers>
<timestamp></timestamp>
<pattern>
<pattern>{"level":"%level","logger":"%logger","message":"%message","traceId":"%X{traceId}"}</pattern>
</pattern>
<provider class="net.logstash.logback.composite.loggingevent.StackTraceJsonProvider"/>
</providers>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON"/>
</root>
</configuration>
Con los logs centralizados se pueden correlacionar incidentes con despliegues recientes, detectar anomalías y cumplir requisitos normativos de auditoría.
Las trazas distribuidas permiten seguir una petición a través de todos los servicios. Cada llamada se identifica con un trace ID y los segmentos internos se agrupan como spans. Herramientas como OpenTelemetry, Jaeger y Zipkin simplifican la instrumentación y visualizan los flujos.
Los agentes y SDKs de OpenTelemetry capturan automáticamente solicitudes HTTP, llamadas a bases de datos y operaciones de mensajería. Las trazas ayudan a detectar servicios lentos, errores intermitentes y problemas de configuración de red.
El ejemplo muestra cómo configurar un tracer y exportar las trazas a Jaeger desde Java.
@Configuration
public class TracingConfig {
@Bean
public OpenTelemetry openTelemetry() {
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint("http://jaeger-collector.observability:4317")
.build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.setResource(Resource.getDefault().toBuilder()
.put(AttributeKey.stringKey("service.name"), "orders-service")
.build())
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
.build();
return OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.build();
}
}
Una vez instrumentados los servicios, Jaeger o Zipkin permiten explorar las trazas, filtrar por latencia y analizar la jerarquía de llamadas.
Las alertas permiten actuar antes de que un incidente impacte al usuario. Se definen reglas con umbrales o condiciones de rate of change que disparan notificaciones hacia canales como correo, Slack o PagerDuty. Prometheus es ampliamente usado para recolectar métricas y generar alertas a través de Alertmanager.
Los tableros de control ofrecen una vista ejecutiva y operativa del estado de la plataforma. Grafana permite combinar métricas, logs y trazas en paneles interactivos y compartirlos con equipos de negocio.
A continuación se define una alerta de Prometheus que verifica el percentil 95 de latencia y un panel de Grafana que muestra la evolución.
# Alertmanager rule
groups:
- name: latency
rules:
- alert: HighLatencyP95
expr: histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{service="orders-service"}[5m])) by (le))
for: 10m
labels:
severity: critical
annotations:
summary: "Latencia elevada en orders-service"
description: "El percentil 95 supera 800ms durante 10 minutos."
# Grafana panel (JSON abreviado)
{
"title": "Latencia P95 orders-service",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{service=\"orders-service\"}[5m])) by (le))",
"legendFormat": "P95"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.6 },
{ "color": "red", "value": 0.8 }
]
}
}
}
}
Las alertas deben revisarse periódicamente para evitar fatiga y calibrarse con datos históricos. Los tableros se respaldan con anotaciones automáticas que indiquen despliegues, incidentes o cambios significativos en el tráfico.