Plantilla de Diseño de Dashboards
Una plantilla para diseñar dashboards de observabilidad con SLOs, presupuestos de error, salud del servicio e información contextual para equipos on-call.
Visión General
Un dashboard es una interfaz visual que responde preguntas sobre la salud del sistema. Los buenos dashboards recortan el tiempo de diagnóstico durante incidentes; los malos suman ruido y confusión. Esta plantilla define la estructura de dashboards de servicio en los que un ingeniero on-call puede confiar a las 3 AM.
Funciona bien junto con la plantilla de runbook de alertas — el dashboard te dice que algo está roto, el runbook te dice qué hacer al respecto.
Cuándo Usar
- Crear un dashboard nuevo para un servicio
- Rediseñar un dashboard existente que nadie usa
- Estandarizar el layout de dashboards entre equipos
- Configurar el seguimiento de SLOs y presupuestos de error
- Preparar dashboards para el handoff de on-call
Solución
Copiá todo el bloque de abajo y completá los placeholders. El layout codifica el orden de lectura: primero el estado, después las métricas del servicio, la infraestructura, el negocio y finalmente el contexto.
# Diseño de Dashboard: `<Nombre del Servicio>`
## Metadata del Dashboard
| Campo | Valor |
|-------|-------|
| Título del Dashboard | Payment Service Health |
| URL del Dashboard | https://grafana.example.com/d/payment-service |
| Owner | Equipo de Pagos |
| Última Revisión | 2026-07-05 |
| Audiencia | Ingenieros on-call, developers, SRE |
| Intervalo de Refresh | 30 segundos |
| Rango de Tiempo Default | Última hora |
## 1. Layout del Dashboard
```
┌─────────────────────────────────────────────────────────────┐
│ FILA 1: Banner de Estado del Servicio │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Salud │ │ Estado SLO │ │ Error Budget│ │
│ │ OK/WARN/ERR │ │ 99.9% │ │ 72% restante│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ FILA 2: Métricas RED (Rate, Errors, Duration) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Request Rate│ │ Error Rate │ │ Latencia p95│ │
│ │ (req/s) │ │ (% total) │ │ (ms) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ FILA 3: Tráfico y Códigos de Estado │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ Requests por endpoint │ │ Distribución de códigos │ │
│ │ (área apilada) │ │ (gráfico de torta) │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ FILA 4: Salud de Infraestructura │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Uso de CPU │ │ Memoria │ │ Conexiones │ │
│ │ (%) │ │ (MB) │ │ (activas) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ FILA 5: Métricas de Negocio │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Órdenes/min │ │ Ingresos/min│ │ Tasa Éxito │ │
│ │ │ │ ($) │ │ (%) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ FILA 6: Contexto y Enlaces │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Runbook | Logs | Traces | Alertas | Info de Deploy │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 2. Especificación de Paneles
### Fila 1: Banner de Estado
| Panel | Tipo | Query | Umbrales | Propósito |
|-------|------|-------|----------|-----------|
| Salud | Stat | `up{service="payment"}` | OK: 1, WARN: 0.5, ERR: 0 | Chequeo rápido de salud |
| Estado SLO | Stat | `payment_slo_availability_ratio` | OK: > 0.999, WARN: > 0.99, ERR: < 0.99 | Cumplimiento del SLO de un vistazo |
| Error Budget | Gauge | `payment_error_budget_remaining_pct` | OK: > 30%, WARN: > 10%, ERR: < 10% | Cuánto presupuesto de error queda |
### Fila 2: Métricas RED
| Panel | Tipo | Query | Umbrales | Propósito |
|-------|------|-------|----------|-----------|
| Request Rate | Time series | `rate(http_requests_total{service="payment"}[5m])` | — | Volumen de tráfico |
| Error Rate | Time series | `rate(http_requests_total{service="payment",status=~"5.."}[5m]) / rate(http_requests_total{service="payment"}[5m])` | WARN: > 1%, ERR: > 5% | Porcentaje de errores |
| Latencia p95 | Time series | `histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{service="payment"}[5m]))` | WARN: > 500ms, ERR: > 1s | Tiempo de respuesta |
### Fila 3: Tráfico y Códigos de Estado
| Panel | Tipo | Query | Propósito |
|-------|------|-------|-----------|
| Requests por endpoint | Área apilada | `sum(rate(http_requests_total{service="payment"}[5m])) by (endpoint)` | Ver la distribución del tráfico |
| Distribución de códigos | Gráfico de torta | `sum(rate(http_requests_total{service="payment"}[5m])) by (status)` | Detectar patrones de error |
### Fila 4: Salud de Infraestructura
| Panel | Tipo | Query | Umbrales | Propósito |
|-------|------|-------|----------|-----------|
| Uso de CPU | Time series | `rate(container_cpu_usage_seconds_total{pod=~"payment.*"}[5m]) * 100` | WARN: > 70%, ERR: > 90% | Saturación de recursos |
| Memoria | Time series | `container_memory_working_set_bytes{pod=~"payment.*"}` | WARN: > 80% límite, ERR: > 95% | Presión de memoria |
| Conexiones DB | Time series | `payment_db_connections_active` / `payment_db_connections_max` | WARN: > 70%, ERR: > 90% | Agotamiento del pool |
### Fila 5: Métricas de Negocio
| Panel | Tipo | Query | Umbrales | Propósito |
|-------|------|-------|----------|-----------|
| Órdenes/min | Time series | `rate(payment_orders_total[5m]) * 60` | — | Throughput de negocio |
| Ingresos/min | Time series | `rate(payment_revenue_total[5m]) * 60` | — | Seguimiento de ingresos |
| Tasa de Éxito | Stat | `rate(payment_orders_total{status="success"}[5m]) / rate(payment_orders_total[5m])` | WARN: < 99%, ERR: < 95% | Salud del negocio |
### Fila 6: Contexto y Enlaces
| Enlace | URL | Propósito |
|--------|-----|-----------|
| Runbook | https://runbooks.example.com/payment-service | Respuesta a incidentes |
| Logs | https://kibana.example.com/app/discover#/?_a=(query:service:payment) | Búsqueda de logs |
| Traces | https://jaeger.example.com/search?service=payment | Trazas distribuidas |
| Alertas | https://alertmanager.example.com/#/alerts?receiver=payment | Alertas activas |
| Info de Deploy | https://grafana.example.com/d/deployments?service=payment | Deploys recientes |
## 3. Configuración de SLOs
### Definición de SLOs
| SLO | Objetivo | Ventana | Error Budget | Medición |
|-----|----------|---------|--------------|----------|
| Disponibilidad | 99.9% | 30 días | 0.1% = 43.2 min | `1 - (failed_requests / total_requests)` |
| Latencia p95 | < 500ms | 30 días | 0.1% = 43.2 min | `histogram_quantile(0.95, ...)` |
| Latencia p99 | < 2s | 30 días | 0.1% = 43.2 min | `histogram_quantile(0.99, ...)` |
### Seguimiento del Error Budget
| Métrica | Query | Propósito |
|---------|-------|-----------|
| Presupuesto restante | `1 - (rate(errors[30d]) / 0.001)` | Cuánto presupuesto queda |
| Burn rate (1h) | `rate(errors[1h]) / 0.001` | Detección de quema rápida |
| Burn rate (6h) | `rate(errors[6h]) / 0.001` | Detección de quema sostenida |
| Fecha de reset | `30d - elapsed_in_window` | Cuándo se resetea el presupuesto |
### Reglas de Alerta
```yaml
- alert: PaymentSLOFastBurn
expr: |
(
sum(rate(http_requests_total{service="payment",status=~"5.."}[1h]))
/
sum(rate(http_requests_total{service="payment"}[1h]))
) > 0.02
for: 5m
labels:
severity: critical
service: payment
annotations:
summary: "Payment SLO fast burn — 2% del presupuesto consumido en 1h"
runbook: "https://runbooks.example.com/payment-slo-burn"
# Quema lenta: 5% del presupuesto en 6 horas
- alert: PaymentSLOSlowBurn
expr: |
(
sum(rate(http_requests_total{service="payment",status=~"5.."}[6h]))
/
sum(rate(http_requests_total{service="payment"}[6h]))
) > 0.005
for: 30m
labels:
severity: warning
service: payment
annotations:
summary: "Payment SLO slow burn — 5% del presupuesto consumido en 6h"
runbook: "https://runbooks.example.com/payment-slo-burn"
```
## 4. Variables del Dashboard
| Variable | Tipo | Query | Default | Propósito |
|----------|------|-------|---------|-----------|
| $datasource | Data source | — | Prometheus | Cambiar entre entornos |
| $environment | Query | `label_values(up, environment)` | production | Filtrar por entorno |
| $instance | Query | `label_values(up{service="payment"}, instance)` | All | Filtrar por instancia |
| $endpoint | Query | `label_values(http_requests_total{service="payment"}, endpoint)` | All | Filtrar por endpoint |
| $timeframe | Interval | — | 1h | Cambio rápido de rango |
## 5. Capas de Anotaciones
| Anotación | Query | Propósito |
|-----------|-------|-----------|
| Deployments | `deployments{service="payment"}` | Correlacionar cambios con movimientos en las métricas |
| Incidents | `incidents{service="payment"}` | Ver el impacto de incidentes en las métricas |
| Maintenance | `maintenance{service="payment"}` | Caídas esperadas durante mantenimiento |
| Alerts | `alerts{service="payment"}` | Cuándo se dispararon alertas respecto a las métricas |
Explicación
El layout sigue un orden de lectura estricto de arriba hacia abajo. Durante un incidente, el ingeniero lee el dashboard siempre de la misma forma:
El banner de estado (Fila 1) responde “¿está todo bien?” de un vistazo. Las métricas RED (Fila 2) — Rate, Errors, Duration, del capítulo de monitoreo del libro de SRE de Google — atrapan la mayoría de los problemas de un servicio. El desglose de tráfico (Fila 3) muestra qué endpoints sufren. La salud de infraestructura (Fila 4) verifica si el servicio tiene recursos para operar. Las métricas de negocio (Fila 5) traducen la salud técnica a impacto de negocio. Los enlaces de contexto (Fila 6) llevan al ingeniero a logs, trazas y runbooks sin tener que buscarlos.
Los SLOs y los presupuestos de error son la columna cuantitativa — el capítulo de alertas del workbook de SRE es la referencia para la matemática de burn rate usada arriba. El SLO define “saludable” de forma objetiva; el presupuesto de error mide cuánto margen tiene el equipo antes de violarlo. Las alertas de burn rate atrapan tanto incidentes de quema rápida (2% del presupuesto en 1 hora) como tendencias de quema lenta (5% en 6 horas).
Las variables del dashboard dejan filtrar sin escribir queries. $endpoint es la más útil: cuando una alerta nombra un endpoint específico, filtrar todo el dashboard por él es un clic.
Las capas de anotaciones correlacionan deploys e incidentes con los cambios en las métricas. Cuando la latencia pica y hay una anotación de deploy en el mismo timestamp, ya sabés dónde mirar.
Checklist de Revisión del Dashboard
=== Revisión Trimestral del Dashboard ===
[ ] Todos los paneles tienen fuentes de datos válidas (sin paneles "No data")
[ ] Los umbrales reflejan los SLOs y baselines de rendimiento actuales
[ ] Las variables devuelven valores correctos (entornos, instancias, endpoints)
[ ] Las capas de anotaciones siguen recibiendo eventos (deploys, incidentes)
[ ] Los enlaces a runbooks, logs y trazas no están rotos
[ ] Ningún panel tiene más de 10 series (check de cardinalidad)
[ ] El código de colores es consistente (verde/amarillo/rojo en todos)
[ ] El dashboard carga en menos de 3 segundos
[ ] La vista móvil es legible (el on-call revisa desde el teléfono)
[ ] Al menos otro ingeniero puede interpretar el dashboard sin explicación
[ ] Los paneles de SLO coinciden con las definiciones vigentes
[ ] El panel de error budget es preciso y no muestra datos viejos
[ ] Los paneles de métricas de negocio reflejan los KPIs actuales
[ ] Se quitaron los paneles que nadie usa (métrica de vistas de Grafana)
[ ] El dashboard está etiquetado con nombre de servicio y equipo owner
Variantes
| Contexto | Enfoque | Notas |
|---|---|---|
| Dashboard de base de datos | Reemplazar RED con USE (Utilization, Saturation, Errors) | Foco en métricas de recursos |
| Consumidor de colas | Agregar lag, throughput y tiempo de procesamiento | Métricas específicas del consumidor |
| Vista multi-servicio | Agregar métricas RED entre servicios | Usar service map para dependencias |
| Dashboard de negocio | Foco en KPIs de negocio, no infraestructura | Ingresos, conversión, churn |
| Handoff de on-call | Agregar notas de turno, incidentes abiertos, ítems pendientes | Contexto para el on-call entrante |
Lo que Funciona
- Poné la información más importante arriba — el estado y el SLO tienen que ser visibles sin scrollear.
- Usá un código de colores consistente — verde = OK, amarillo = warning, rojo = error en todos los paneles.
- Enlazá a runbooks, logs y trazas — recortá el tiempo de navegación durante incidentes.
- Usá variables para filtrar — que el ingeniero pueda hacer drill-down sin escribir queries.
- Agregá anotaciones de deploy — correlacioná cambios con movimientos en las métricas.
- Definí umbrales realistas — basate en datos históricos, no en suposiciones.
- Revisá los dashboards cada trimestre — quitá los paneles que nadie mira, agregá las métricas que faltan.
- Que se pueda leer en un teléfono — el on-call revisa desde el móvil.
Recursos companion: el repo companion de dashboard-design-template tiene la plantilla como archivo independiente, un dashboard.json de Grafana importable que implementa este layout, y el grupo de reglas slo-alerts.yml para Prometheus.
Errores Comunes
- Demasiados paneles — un dashboard con 50 paneles es una pared de ruido. Quedate debajo de 15.
- Sin resumen de estado — obligás al ingeniero a interpretar 10 gráficos para saber si está todo bien.
- Sin umbrales — las líneas sin umbrales exigen interpretación. Marcá umbrales visuales.
- Sin enlaces de contexto — un dashboard sin enlaces a logs, trazas y runbooks es un callejón sin salida.
- Dashboards viejos — las métricas cambian, los servicios evolucionan. Revisá cada trimestre.
- Mezclar audiencias — un dashboard para ejecutivos y uno para el on-call son cosas distintas.
- Sin variables — obligás a editar queries para filtrar por endpoint o instancia.
- Cardinalidad muy alta — un panel con 100 series es ilegible. Agregá apropiadamente.
Solución de Problemas
- Los paneles muestran “No data”. Revisá primero la fuente de datos, después el rango de tiempo, después la query. Un nombre de métrica renombrado o un label que desapareció es la causa habitual — compará la query contra
label_values()en el explorador del data source. - El dashboard carga lento. Casi siempre es cardinalidad. Agregá con
sum by (...)en vez deby (pod), sacá los matchers con regex que abren a cientos de series, y subí el intervalo de scrape en los paneles pesados. La documentación de Grafana sobre dashboards tiene más detalle. - Las variables vuelven vacías. La query de
label_values()depende del data source y del rango de tiempo seleccionados — una variable sobreupno devuelve nada si cambió el nombre del job. Probá cada query de variable por separado. - Los umbrales nunca se disparan. Los valores de umbral se comparan en la unidad del panel — un umbral de 500ms en un panel que muestra segundos no se dispara jamás. Igualá la unidad del umbral a la unidad de display.
- Las anotaciones dejaron de aparecer. Las queries de anotaciones tienen su propio data source y rango de tiempo. Si los deploys dejaron de mostrarse, la métrica de anotación puede haberse movido o renombrado.
Preguntas frecuentes
¿Cuántos paneles debería tener un dashboard?
Entre 8 y 15. Más que eso y se convierte en una pared de ruido. Si necesitás más, dividilo: una vista general que responda "¿está todo bien?" en 5 segundos, más dashboards de detalle por área.
¿Usamos Grafana o armamos un dashboard propio?
Grafana para dashboards de ingeniería — se integra con Prometheus y te da variables, anotaciones y alertas gratis. Los dashboards propios solo tienen sentido para vistas de negocio donde importa el branding.
¿Cómo elegimos los objetivos de SLO?
Basalos en el rendimiento histórico, no en la aspiración. Un servicio que estuvo en 99.5% seis meses no va a sostener un SLO de 99.99%. Empezá desde el rendimiento actual y ajustá con el tiempo.
¿Qué es un presupuesto de error?
La cantidad de falta de confiabilidad que te podés permitir cumpliendo el SLO igual. Un SLO de 99.9% en 30 días son 43.2 minutos de caída permitida. Cuando el presupuesto se agota, el equipo frena los releases y se pone a trabajar en confiabilidad.
¿Qué métricas debería tener todo dashboard de servicio?
Las métricas RED — rate, error rate y latencia p95/p99 — más CPU, memoria, uso del pool de conexiones y salud de dependencias. En servicios críticos para el negocio, sumá KPIs como órdenes/min. RED cubre la mayoría de los problemas; el resto es específico del servicio.
¿Cómo diseñamos dashboards para respuesta a incidentes?
Banner de estado arriba, métricas RED justo debajo, paneles grandes con umbrales claros, y enlaces a logs, trazas y runbooks dentro del mismo dashboard. Evitá queries lentas — un dashboard que tarda 10 segundos en cargar no sirve en medio de un incidente. Después corré un ejercicio de simulacro para verificar que responde las preguntas correctas.
Recursos Relacionados
Plantilla de Evaluación de Madurez de Observabilidad
Una plantilla para evaluar la madurez de logging, métricas y tracing entre equipos con puntuación, análisis de brechas y hoja de ruta de mejora.
DocPlantilla de Runbook de Alertas
Un runbook estandarizado para responder alertas: triage, diagnosis, mitigation, resolution y post-incident steps con escalation paths.
DocPlantilla de Postmortem de Incidentes
Una plantilla de postmortem sin culpables para documentar incidentes: cronología, impacto, causa raíz, factores contribuyentes y acciones con responsables.
DocPlantilla de Runbook de Guardia
Una plantilla que documenta alertas comunes y procedimientos de respuesta paso a paso para ingenieros de guardia.
DocPlantilla de Objetivo de Nivel de Servicio (SLO)
Una plantilla para definir objetivos de confiabilidad, presupuestos de error y metodos de medicion para servicios y sistemas.
GuideLogging Estructurado: logs JSON, correlation IDs, agregación
Dominá structured logging con JSON format, correlation IDs, log levels y aggregation. Cubre Python structlog, Node.js pino, Java SLF4J, stacks ELK y Loki.