Análisis del rendimiento de la ejecución de código
Cronometrar cada etapa de una solicitud reemplaza la intuición con evidencia. Una vez que las duraciones son eventos estructurados, puede comparar funciones entre ejecuciones, lanzamientos y categorías de tamaño de entrada.
Un perfil de duración le indica qué función vale la pena optimizar primero.
Configurar el proyecto
npm init -y
npm install telemetry-sh
Instrumentar cada paso completado
Utilice un evento por paso para que las mismas columnas funcionen en todos los flujos de trabajo. Un run_id conecta pasos que pertenecen a una solicitud o trabajo.
const telemetry = require("telemetry-sh");
const { randomUUID } = require("node:crypto");
telemetry.init(process.env.TELEMETRY_API_KEY);
async function measureStep({ runId, stepName }, operation) {
const startedAt = Date.now();
try {
const result = await operation();
await telemetry.log("profile_step_completed", {
run_id: runId,
step_name: stepName,
status: "success",
duration_ms: Date.now() - startedAt,
release: process.env.APP_RELEASE ?? "unknown",
});
return result;
} catch (error) {
await telemetry.log("profile_step_completed", {
run_id: runId,
step_name: stepName,
status: "error",
duration_ms: Date.now() - startedAt,
error_type: error.constructor?.name ?? "Error",
release: process.env.APP_RELEASE ?? "unknown",
});
throw error;
}
}
async function profileRequest() {
const runId = randomUUID();
const project = await measureStep(
{ runId, stepName: "load_project" },
() => loadProject()
);
return measureStep(
{ runId, stepName: "generate_report" },
() => generateReport(project)
);
}
Evite registrar argumentos de funciones, registros de bases de datos o mensajes de excepción de forma predeterminada. Las categorías seguras como input_size_bucket, cache_status o query_name pueden explicar el rendimiento sin almacenar contenido sin formato.
Promedio de consulta y duración de cola
SELECT
step_name,
COUNT(*) AS runs,
ROUND(AVG(duration_ms), 0) AS avg_duration_ms,
ROUND(approx_percentile_cont(duration_ms, 0.95), 0) AS p95_duration_ms,
ROUND(
100.0 * SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0),
2
) AS error_rate_pct
FROM profile_step_completed
WHERE timestamp_utc >= now() - INTERVAL '7 days'
GROUP BY step_name
ORDER BY p95_duration_ms DESC;
Utilice p95 en lugar de solo el promedio para que los pasos lentos intermitentes permanezcan visibles. Divida por release después de una implementación e inspeccione los valores individuales de run_id cuando varios pasos lentos pertenezcan a la misma solicitud.
Construya la vista de rendimiento
Comience con:
- un gráfico de barras de p95 duración por paso;
- un gráfico de líneas de p95 a lo largo del tiempo para los pasos más lentos;
- una tabla de resultados dividida por versión;
- una tabla de eventos recientes filtrada por filas de error o de duración extrema.
Perfil en un límite útil. No emita un evento por cada pequeña función en un bucle activo; eso agrega gastos generales y produce un conjunto de datos que es difícil de interpretar.
Próximos pasos
Cuando el flujo de trabajo medido es una solicitud API, utilice el Receta de percentiles de latencia API para obtener una visualización completa de los resultados, un diseño del tablero y un diseño de alertas.