Ir al contenido principal
Laravel, shipping fast.
Capítulo 13 · Monitorización y observabilidad

Rastrear una petición que no puedes reproducir

Julian Beaujardin

¿Qué haces cuando el fallo ya ocurrió y no puedes hacer que ocurra otra vez? No lo reproduces. Lo reconstruyes a partir de lo que quedó registrado, que es la razón para registrar las cosas antes de necesitarlas.

Tres registros, unidos por el ID de traza del Capítulo 7, cuentan la historia de una petición:

trace_id 7c1e9a52-...
  petición  POST /api/licenses   consumidor 4   504  10.2 s
  saliente  POST statamic/sites                 timeout
  excepción ConnectionException                 warning

El log de peticiones y la excepción ya están ahí. La línea del medio es la que los equipos olvidan: un registro de cada llamada que haces a un proveedor. El cliente HTTP de Laravel dispara un evento por cada respuesta, así que un solo listener cubre todos los drivers que llegues a escribir:

// app/Providers/AppServiceProvider.php, en boot()
Event::listen(function (ResponseReceived $event): void {
    $request = $event->request;

    Log::info('provider.response', [
        'method' => $request->method(),
        'host' => parse_url($request->url(), PHP_URL_HOST),
        'status' => $event->response->status(),
    ]);
});

Como el ID de traza está en Context, queda adjunto a esta línea de log sin que el listener sepa que existe. Un evento ConnectionFailed cubre las llamadas que nunca recibieron respuesta. Si usas Nightwatch, ya registra las llamadas salientes y puedes saltarte el listener.

Registra el host y el estado, no la URL y el cuerpo. Una URL de proveedor puede contener un identificador que no deberías conservar, y el cuerpo de la respuesta de un proveedor son datos ajenos.

Los jobs reciben el mismo trato gratis. Context viaja con un job despachado, así que las líneas de log que escribe DeleteLicense diez minutos después llevan el ID de traza de la petición que lo encoló. Cuando un consumidor cita un ID de la cabecera X-Trace-Id, una búsqueda devuelve la petición, el job, cada llamada al proveedor que hizo cualquiera de los dos y la excepción.

Objetivos

Cuatro señales te dicen lo que está pasando. No te dicen si es aceptable. ¿Es bueno un percentil 95 de 800 ms? ¿Lo es una petición fallida de cada quinientas?

Sin una respuesta acordada de antemano, cada gráfica es una discusión. Una persona ve una anomalía pasajera, otra ve un incidente, y la decisión queda en manos de quien esté más preocupado ese día.

Un objetivo de nivel de servicio es esa respuesta, puesta por escrito. Tiene tres partes: una medida, una meta y una ventana.

  • Disponibilidad: el 99,5 % de las peticiones, a lo largo de 30 días, responden sin un 5xx que sea culpa de esta API.
  • Latencia: el 95 % de las peticiones GET /api/licenses responden en menos de 500 ms.
  • Trabajo en segundo plano: el 99 % de los borrados de licencias se completan en los cinco minutos siguientes a la petición.

Tres decisiones se esconden en esas frases, y cada una merece pensarse un momento.

Qué cuenta como fallo. Un 422 es el error del consumidor y no cuenta. Un 504 porque el proveedor estaba caído es más difícil. No es culpa de tu código, y a tu consumidor no le importa de quién es la culpa. Yo lo cuento, porque un objetivo que disculpa a tus dependencias mide tu comodidad y no la experiencia de tus consumidores.

Cuál es la meta. No el 100 %. Una meta del 100 % no puede cumplirse, así que no puede orientar nada. El 99,5 % en treinta días permite unas tres horas y media de fallo, y ese margen es la parte útil.

Qué haces con el margen. El hueco entre la meta y la perfección es un presupuesto de error. Mientras quede presupuesto, entrega: despliega el viernes, prueba la migración arriesgada. Cuando se gaste, deja de entregar funcionalidades y dedica el tiempo a la fiabilidad hasta que se recupere. Eso hace que «¿deberíamos ir más despacio?» deje de ser un debate y pase a ser una lectura.

Y cambia aquello por lo que alertas. No despiertes a nadie cuando falla una petición. Hazlo cuando el presupuesto se esté quemando lo bastante rápido para agotarse, que es la definición de un síntoma que importa.

No necesitas herramientas nuevas para esto. El log de peticiones ya contiene cada estado y cada duración. Un objetivo es una consulta sobre él, ejecutada de forma programada, con un número que va al panel junto a las cuatro señales.

No se pudo cargar el audio. Inténtalo de nuevo en un momento.