API de análisis de resultados
Cada página de resultados de una prueba de carga se construye a partir de un único documento JSON: todas las muestras de la ejecución, agregadas en percentiles, tipos de error y resúmenes por petición, por región y por nivel de usuarios. Ese mismo documento está disponible para tus herramientas a través de la API de análisis, de modo que un panel, un generador de informes o un paso de CI lea exactamente las cifras que muestra la página de resultados.
Endpoint
GET /api/v1/{loadtests|k6tests|jmetertests}/analysis?testrunname=<name>&testrunid=<id>
Envía tu clave de API en la cabecera loadfocus-auth. Usa loadtests para pruebas cloud, k6tests para scripts k6 y jmetertests para planes JMeter. Los dos parámetros son obligatorios; testrunid es el número de ejecución que aparece en la URL de resultados (consulta ¿Qué es un ID de Ejecución de Prueba?). Las solicitudes están limitadas a 100 cada 15 minutos por clave de API.
curl -H "loadfocus-auth: $LOADFOCUS_API_KEY" \"https://loadfocus.com/api/v1/loadtests/analysis?testrunname=checkout-flow&testrunid=12"
Una ejecución terminada se calcula una vez y se guarda en caché, así que las llamadas repetidas son baratas. Una ejecución en curso devuelve sus cifras hasta el momento.
Respuestas
| Estado | Cuerpo | Significado |
|---|---|---|
200 | el documento de análisis | La ejecución existe y tiene muestras. |
404 | { "error": "no-data" } | Ejecución desconocida, de otro equipo o todavía sin muestras. |
503 | { "error": "analysis-unavailable" } | El cálculo falló o agotó el tiempo. Reintenta; no lo trates como "sin datos" en una puerta de CI. |
400 | { "error": "testrunname-and-testrunid-required" } | Falta un parámetro. |
400 | { "error": "invalid-api-key" } | La clave de API no corresponde a ningún equipo. |
429 | { "error": "Too many requests, please try again later." } | Más de 100 solicitudes en 15 minutos con esta clave de API. |
El documento
{"samples": 50312,"overall": {"mean": 212.4, "p50": 180, "p90": 410, "p95": 612, "p99": 1480,"min": 41, "max": 5120, "sd": 233.1, "latency": 198.7, "connect": 9.2,"errors": 137, "errorPct": 0.3, "rps": 83.9,"first": 1756540800000, "last": 1756541400000},"labels": [ { "label": "GET /api/products", "samples": 25100, "mean": 190.2, "p50": 160, "p90": 380, "p95": 540, "p99": 1200, "errors": 12, "errorPct": 0.1, "rps": 41.8, "min": 41, "max": 3100, "sd": 201.0, "latency": 180.1, "connect": 8.9 } ],"byThreads": [ { "vus": 50, "samples": 4210, "mean": 150.3, "max": 900, "errors": 0, "rps": 44.1, "errorPct": 0 } ],"byRegion": [ { "region": "us-east-1", "samples": 25156, "mean": 170.5, "p95": 480, "p99": 1100, "errors": 40, "errorPct": 0.2, "rps": 41.9 } ],"errorTypes": [ { "label": "POST /api/checkout", "type": "502", "count": 90, "message": "Bad Gateway", "messages": 90, "topMessages": [ { "message": "Bad Gateway", "count": 90 } ] } ],"perSecond": [ { "t": 1756540800000, "samples": 62, "errors": 0, "errorPct": 0 } ],"histogram": { "step": 50, "buckets": [ { "from": 0, "to": 50, "count": 812 } ], "over": 31 },"apdex": { "t": 500, "satisfied": 44100, "tolerating": 5200, "frustrated": 1012, "score": 0.93 },"settled": true}
sampleses el número de peticiones registradas en todos los motores y regiones. Todas las demás cifras se calculan a partir de esas muestras, no de medias por motor.overalles la ejecución completa. Los tiempos están en milisegundos;latencyes el tiempo hasta el primer byte yconnectel tiempo de conexión.rpsson las muestras divididas por los segundos activos de la ejecución.firstylastson milisegundos epoch.labelstiene una fila por petición (URL o nombre del sampler) con los mismos campos más sus propios percentiles.byThreadsagrupa las muestras por el número de usuarios virtuales activos en ese momento. Léelo como tiempo de respuesta frente a carga: el nivel en el quemeanomaxse dispara es tu capacidad.byRegiones una fila por región cloud, en ejecuciones multirregión.errorTypeses una fila por petición y tipo de fallo (typees el código de estado HTTP o el nombre de la excepción de JMeter), como máximo las 100 más frecuentes, con el mensaje de error más frecuente y hasta cincotopMessages.perSecondes la tasa de error a lo largo del tiempo; las ejecuciones largas se reducen a un máximo de 3.600 puntos.histogrames la distribución de tiempos de respuesta que dibuja la página de resultados, con el número de muestras por encima del último intervalo enover.apdexusa un objetivo de 500 ms: una muestra es satisfied hasta 500 ms, tolerating hasta 2.000 ms y frustrated por encima.scorees (satisfied + tolerating / 2) / total.settledestruecuando la ejecución ha terminado y sus números son definitivos. Una ejecución en curso devuelvefalse; espera atrueantes de decidir con los números.
Los percentiles salen de 1.000 intervalos logarítmicos, así que p99 es exacto hasta una fracción de porcentaje del valor; no coincidirá al milisegundo con una hoja de cálculo sobre el JTL en bruto.
Condicionar un pipeline
Para una decisión de aprobado o suspenso usa la API de veredicto: aplica los umbrales guardados en la prueba y devuelve un veredicto, que es lo que lee la GitHub Action. Usa la API de análisis cuando necesites las cifras en sí, por ejemplo para publicar el p95 por endpoint en un comentario de pull request o mantener tu propio histórico de tendencias.