Observabilidad desde los logs: como construir SLIs sin esperar a que alguien instrumente el codigo
Leiste los 5 blogs anteriores. Sabes cual estadistica usar, que rompe un SLO, como computar el SLI, como visualizarlo, y que hacer cuando la alarma suena. Pero cuando abres Amazon CloudWatch, tu servicio solo tiene las metricas que AWS publica por defecto. El dato que realmente necesitas esta en los logs.
El equipo que tiene logs pero no metricas
Conoces este equipo. Llevan meses con una aplicacion en produccion. Tienen logs estructurados en JSON: cada request deja un registro con timestamp, status code, duracion en milisegundos, endpoint, y user ID. CloudWatch Logs tiene todo. Pero cuando alguien pregunta "cual es nuestro p99 de latencia esta semana?" la respuesta es: "no sabemos, no tenemos esa metrica."
La ironia: el dato esta ahi. Cada request registro su duracion. Pero nadie conecto ese dato con una metrica de CloudWatch, lo cual significa que no hay SLI, no hay SLO, no hay presupuesto de error, no hay alarma. Toda la cadena que construimos en los blogs anteriores no existe porque falta el primer eslabon: convertir un log en una metrica.
Este post cubre tres formas de hacerlo, cada una con sus ventajas y trampas.
Los cinco blogs anteriores:
- Blog 1: Como leer una estadistica de CloudWatch sin retos -- cual estadistica usar
- Blog 2: Por que tu SLO te miente -- que errores rompen la cadena
- Blog 3: 5 formulas de Metric Math que convierten metricas crudas en SLIs -- como computar el SLI
- Blog 4: Tu dashboard miente si esta organizado por servicio -- como visualizarlo
Camino 1: Metric Filters -- extraer metricas de patrones en logs
Un metric filter observa un log group, busca patrones que coincidan con tu filtro, y publica un data point en CloudWatch cada vez que encuentra uno. Desde ese momento, la metrica existe como cualquier otra metrica de CloudWatch: puedes graficarla, alarmarla, y usarla en Metric Math.
Ejemplo: tasa de errores 5xx desde access logs
Tus logs tienen lineas como:
JSON
{"timestamp": "2026-09-01T12:00:00Z", "status": 503, "duration_ms": 1200, "endpoint": "/api/orders"}
Creas un metric filter en el log group de tu aplicacion:
Plain text
Filter pattern: { $.status >= 500 }Metric name: 5xxErrorsMetric value: 1Default value: 0
Cada vez que un log con status >= 500 llega, CloudWatch publica un data point de valor 1 en la metrica
5xxErrors . La Sum de esa metrica en un periodo de 5 minutos te da el conteo total de errores 5xx.Para la tasa de errores necesitas dos metricas: errores y total de requests. Crea un segundo metric filter:
Plain text
Filter pattern: { $.status = * }Metric name: TotalRequestsMetric value: 1Default value: 0
Ahora puedes usar la Formula 1 del Blog 3:
Plain text
m1 = 5xxErrors [Sum]m2 = TotalRequests [Sum]e1 = (m1 / m2) * 100
Tasa de errores. SLI de disponibilidad. La cadena empieza a existir.
Ejemplo: latencia p99 desde logs estructurados
Pero metric filters tambien pueden extraer valores numericos de los logs, no solo contar ocurrencias:
Plain text
Filter pattern: { $.duration_ms = * }Metric name: RequestDurationMetric value: $.duration_msDefault value: (dejar vacio)
Cada log event publica su valor de
duration_ms como un data point individual. Esto es clave: al publicar data points individuales (no agregados), tienes acceso a las 12 estadisticas del Blog 1, incluyendo percentiles y TrimmedMean."You can use any type of CloudWatch statistic, including percentile statistics, when viewing these metrics or setting alarms." - Creating metrics from log events using filters
La unica restriccion: si los valores pueden ser negativos, las percentile statistics no estan disponibles para esa metrica.
Ahora puedes construir la Formula 3 del Blog 3 (cumplimiento de latencia) directamente sobre esta metrica:
Plain text
m1 = RequestDuration [p99]e1 = IF(m1 <= 500, 1, 0)e2 = RUNNING_SUM(e1)e3 = TIME_SERIES(DATAPOINT_COUNT(m1))e4 = (e2 / e3) * 100
SLI de latencia p99. Desde logs. Sin tocar el codigo de la aplicacion.
Cuando metric filters no alcanzan
- Solo Standard log class. Metric filters no funcionan con log groups en la clase Infrequent Access. Si tus logs usan esa clase para reducir costos, necesitas EMF o Logs Insights.
- No son retroactivos. Solo procesan logs que llegan despues de crear el filtro. Si necesitas analizar datos historicos, usa Logs Insights (Camino 3).
- Un filtro, una metrica. No puedes extraer latencia Y status code del mismo log con un solo filtro. Necesitas filtros separados.
- Hasta 3 dimensiones. Puedes extraer valores de campos del log como dimensiones para JSON y logs delimitados por espacios. Pero el limite es 3 dimensiones por metric filter, y cuando usas dimensiones no puedes asignar un default value a la metrica. Si necesitas mas de 3 dimensiones o combinaciones de alta cardinalidad, EMF (Camino 2) escala mejor.
Camino 2: Embedded Metric Format -- metricas dentro de tus logs
El Embedded Metric Format (EMF) es un esquema JSON que le dice a CloudWatch Logs: "este log contiene metricas, extrae las y publicalas automaticamente." No haces llamadas a PutMetricData. No pagas por API calls adicionales. Simplemente escribes un JSON estructurado a stdout y CloudWatch hace el resto.
"The CloudWatch embedded metric format allows you to generate custom metrics asynchronously in the form of logs written to CloudWatch Logs." - Embedding metrics within logs
Ejemplo: latencia y errores por endpoint
JSON
{"_aws": {"Timestamp": 1725192000000,"CloudWatchMetrics": [{"Namespace": "MyApp/SLIs","Dimensions": [["Endpoint"]],"Metrics": [{ "Name": "Duration", "Unit": "Milliseconds" },{ "Name": "ErrorCount", "Unit": "Count" }]}]},"Endpoint": "/api/orders","Duration": 245,"ErrorCount": 0,"requestId": "abc-123","userId": "usr-456"}
CloudWatch Logs recibe este log, reconoce el bloque
_aws , y publica dos metricas: Duration y ErrorCount bajo el namespace MyApp/SLIs con la dimension Endpoint=/api/orders . Los campos requestId y userId se quedan en el log para busquedas futuras pero no generan metricas ni dimensiones.Cada valor se publica como un data point individual. Igual que con metric filters, esto te da acceso a las 12 estadisticas del Blog 1. Puedes pedir p99 de
Duration filtrado por Endpoint=/api/orders .Donde EMF gana sobre metric filters
Mas dimensiones, mas flexible. Metric filters soportan hasta 3 dimensiones. EMF soporta hasta 30 por DimensionSet. Si necesitas filtrar por endpoint, region, stage, y version simultaneamente, EMF no tiene el limite de 3.
Multiples metricas en un log. Un solo log event publica
Duration y ErrorCount . Con metric filters necesitarias dos filtros separados.Arrays de valores. Si un log agrupa multiples mediciones (por ejemplo, un batch de 50 requests), puedes publicar un array:
JSON
{"Duration": [120, 340, 89, 450, 210, 95, 780, 110, 200, 315]}
Cada valor del array se publica como un data point individual. 10 data points de una sola linea de log.
La trampa de EMF: explosion de cardinalidad
Cada combinacion unica de dimensiones crea una metrica nueva en CloudWatch. Si usas
userId como dimension y tienes 100,000 usuarios, creas 100,000 metricas. El costo se dispara."If you unintentionally create metrics based on high-cardinality dimensions (such as requestId), the embedded metric format will by design create a custom metric corresponding to each unique dimension combination." - Embedded metric format specification
La regla: usa como dimensiones solo los campos que quieres como ejes de filtrado en tu SLI. Endpoint, region, stage, service name. No uses request ID, user ID, transaction ID, o cualquier campo que sea unico por request.
Lo que EMF requiere
EMF necesita cambios en el codigo de tu aplicacion. Tu aplicacion tiene que emitir el JSON con el bloque
_aws . Existen librerias oficiales para varios lenguajes (Python, Node.js, Java, .NET) que simplifican esto, pero la instrumentacion no es transparente como un metric filter. Si no puedes modificar el codigo (vendor, legacy, imagen de contenedor que no controlas), EMF no es una opcion.Camino 3: CloudWatch Logs Insights -- SLIs ad-hoc sin crear metricas
A veces no necesitas una metrica persistente. Necesitas una respuesta ahora: "cual fue el p99 de latencia del endpoint /api/orders en las ultimas 2 horas?" Logs Insights te da eso con una consulta.
Ejemplo: p99 de latencia por endpoint
Plain text
fields @timestamp, duration_ms, endpoint| filter endpoint like /api/| stats pct(duration_ms, 99) as p99,pct(duration_ms, 50) as p50,avg(duration_ms) as promedio,count(*) as totalby bin(5m)
Esta consulta te da una serie de tiempo con p99, p50, promedio y conteo total por ventanas de 5 minutos. Puedes visualizarla directamente en la consola.
Ejemplo: disponibilidad por hora
Plain text
fields @timestamp, status, status >= 500 as is_5xx| stats count(*) as total,sum(is_5xx) as errores_5xxby bin(1h)| display total, errores_5xx,((total - errores_5xx) / total) * 100 as disponibilidad
Disponibilidad por hora. La misma Formula 2 del Blog 3, pero calculada directamente sobre los logs sin crear metricas intermedias.
Cuando Logs Insights es la herramienta correcta
Investigacion durante incidentes. Cuando la alarma de burn rate suena (Blog 5) y necesitas entender que paso en los ultimos 30 minutos, una consulta de Logs Insights te da respuestas sin esperar a que una metrica acumule suficientes data points.
Validar antes de instrumentar. Antes de crear un metric filter o agregar EMF, usa Logs Insights para confirmar que el dato existe en tus logs y que el SLI que quieres construir tiene sentido con tus datos reales.
Analisis historico. Logs Insights consulta datos historicos. Metric filters no son retroactivos. Si necesitas saber "cual fue nuestro p99 el mes pasado" y no tenias una metrica publicada, Logs Insights es tu unica opcion.
Cuando Logs Insights no alcanza
No genera alarmas. No puedes crear una alarma de CloudWatch directamente sobre una consulta de Logs Insights. Si necesitas alarmar, necesitas una metrica persistente (metric filter o EMF).
Costo por consulta. Logs Insights cobra por la cantidad de datos escaneados. Una consulta sobre 30 dias de logs de alta volumetria puede ser costosa. Las metricas publicadas (metric filter o EMF) se consultan sin costo adicional despues de la publicacion.
No alimenta dashboards automaticamente. Puedes agregar una consulta de Logs Insights a un dashboard de CloudWatch, pero se ejecuta cada vez que abres el dashboard. Para un dashboard que alguien mira 20 veces al dia (la Fila 1 del Blog 4), eso suma en costo y latencia.
Matriz de decision: cual camino usar
| Metric filter | EMF | Logs Insights |
|---|---|---|---|
Requiere cambiar codigo? | No | Si | No |
Retroactivo? | No | No | Si |
Genera metrica persistente? | Si | Si | No |
Soporta percentiles (p99, TM)? | Si | Si | Si (en query) |
Soporta las 12 estadisticas del Blog 1? | Si (valores no negativos) | Si | Parcial (depende de funciones disponibles) |
Dimensiones desde log fields? | Si (hasta 3) | Si (hasta 30) | Si (por campo de log) |
Alimenta alarmas? | Si | Si | No |
Alimenta Fila 1 del dashboard (Blog 4)? | Si | Si | Con limitaciones |
Costo incremental | Bajo (metrica custom) | Bajo (metrica custom) | Por consulta |
Mejor para... | Patrones simples, sin tocar codigo | Metricas de aplicacion con dimensiones | Investigacion, validacion, historico |
El camino mas comun
La mayoria de los equipos empieza con metric filters porque no requieren cambios en codigo. Creas dos filtros (errores y total), construyes el SLI de disponibilidad con Metric Math (Blog 3, Formula 1), lo agregas al dashboard (Blog 4, Fila 1), y configuras la alarma de burn rate (Blog 5).
Cuando necesitan mas de 3 dimensiones o metricas de negocio con combinaciones complejas, migran a EMF. Cuando necesitan investigar un incidente o validar una hipotesis, usan Logs Insights.
No son mutuamente excluyentes. Un equipo maduro usa los tres.
La trampa silenciosa: PutMetricData con StatisticValues
Hay un cuarto camino que algunos equipos toman y que este blog deliberadamente no recomienda: llamar a PutMetricData con el parametro
StatisticValues en vez de Value .StatisticValues permite publicar datos pre-agregados: Sum, SampleCount, Minimum, Maximum. Es tentador porque reduces el numero de API calls (un solo call en vez de uno por request). Pero al publicar datos pre-agregados pierdes acceso a las extended statistics del Blog 1: percentiles (p99, p50), TrimmedMean (TM), Winsorized Mean (WM), Percentile Rank (PR), Trimmed Count (TC), Trimmed Sum (TS)."If you published your data using a statistic set instead, you can retrieve only these statistics (Average, Sum, Minimum, Maximum, SampleCount). You cannot retrieve percentile statistics for this data because CloudWatch needs the raw data points in order to calculate percentiles." - CloudWatch statistics definitions
Si tu SLI usa p99 (que deberia, si leiste el Blog 1), publicar con
StatisticValues lo destruye desde la raiz. Toda la cadena SLO del Blog 2 se construye sobre una estadistica que ya no existe.Tanto metric filters como EMF publican data points individuales. Ese es el camino correcto.
Lo que este blog no cubre (limitaciones honestas)
No cubre el diseno de logs. Asume que tus logs ya tienen los campos que necesitas (status, duration, endpoint). Si tus logs son texto plano sin estructura, el primer paso es migrar a logs estructurados en JSON. Eso es un proyecto separado.
No cubre costos en detalle. Metric filters y EMF crean metricas custom que tienen un costo por metrica por mes. El calculo depende de cuantas metricas, cuantas dimensiones, y cual resolucion. La pagina de precios de Amazon CloudWatch tiene las tarifas actuales.
No cubre OpenTelemetry. Si tu aplicacion ya esta instrumentada con OpenTelemetry y usas CloudWatch Application Signals, las metricas de SLI se generan automaticamente. EMF y metric filters son para equipos que aun no han llegado a esa etapa.
Conclusion
Los cinco blogs anteriores construyeron una cadena: estadistica (Blog 1) que alimenta un SLI (Blog 2) calculado con Metric Math (Blog 3), visualizado en un dashboard SLO-first (Blog 4), con un runbook para cuando la alarma suena (Blog 5). Este blog es el paso cero: como crear la metrica que alimenta esa cadena a partir de los datos que ya tienes en tus logs.
Tres caminos: metric filters para lo simple e inmediato, EMF para cuando necesitas dimensiones y control, Logs Insights para investigar y validar. Los tres publican data points individuales (o los consultan directamente), lo cual preserva las 12 estadisticas que la cadena necesita.
Si tu equipo tiene logs pero no tiene SLIs, ya no hay excusa. El dato esta ahi. Solo falta conectarlo.
Recursos
- Creating metrics from log events using filters - Como crear metric filters y publicar metricas desde logs
- Embedding metrics within logs - Guia de Embedded Metric Format (EMF)
- Embedded metric format specification - Esquema JSON y limites de EMF
- Filter pattern syntax for metric filters - Sintaxis de patrones, dimensiones, y valores de metrica
- CloudWatch Statistics Definitions - Referencia oficial de las 12 estadisticas
- CloudWatch Logs Insights query syntax - Funciones de agregacion en Logs Insights (pct, sum, avg, count)
- Publish custom metrics (PutMetricData / EMF) - Comparacion de metodos para publicar metricas custom
- Amazon CloudWatch pricing - Costos de metricas custom, logs, y consultas
- Como leer una estadistica de CloudWatch sin retos - Blog 1: las 12 estadisticas (AWS Builder Center)
- Por que tu SLO te miente - Blog 2: errores que rompen SLOs (AWS Builder Center)
- 5 formulas de Metric Math que convierten metricas crudas en SLIs - Blog 3: las formulas de Metric Math (AWS Builder Center)
- Tu dashboard miente si esta organizado por servicio - Blog 4: dashboard SLO-first con 4 filas (AWS Builder Center)
- La alarma sono. Y ahora que? - Blog 5: runbook guiado por SLOs (enlace pendiente de publicacion)
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article