Enviar informes SQL programados a Slack
Un informe SQL programado convierte una consulta revisada en un hábito recurrente del equipo. La útil versión hace más que pegar filas en el chat: nombra la ventana de tiempo, incluye el denominador, vincula al tablero duradero y registra si la entrega se realizó correctamente.
Esta guía utiliza la consulta Telemetry API, un webhook entrante de Slack y un flujo de trabajo de acciones GitHub programado. Es un patrón de integración, no una afirmación de que Telemetry tenga un botón nativo de informes de Slack.
que construiras
El trabajo de informes:
- ejecute una consulta SQL de solo lectura contra
api_request_completed; - formatee el resultado en un pequeño mensaje del Slack Block Kit;
- publicarlo a través de un webhook entrante;
- falla en consultas o errores de entrega para que el programador registre el problema.
Necesita una clave Telemetry API, una URL de webhook entrante de Slack, Node.js 20 o posterior, y un repositorio donde se puedan configurar los secretos de flujo de trabajo cifrados.
Slack documenta los webhooks entrantes como URL secretas únicas que aceptan cargas útiles de mensajes JSON. Mantenga la URL fuera del control de fuente y gírela si está expuesta. Ver Guía de webhooks entrantes de Slack.
1. Comience con el informe SQL
Mantenga el primer informe pequeño y orientado a la toma de decisiones:
SELECT
route,
COUNT(*) AS requests,
SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) AS errors,
ROUND(
100.0 * SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0),
2
) AS error_rate_pct
FROM api_request_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY route
ORDER BY error_rate_pct DESC, requests DESC
LIMIT 5;
El mensaje debe decir "últimas 24 horas", no "hoy", porque el programador y el lector pueden usar zonas horarias diferentes. La columna requests evita que una alta tasa de error en dos solicitudes parezca un incidente de gran volumen.
Primero pruebe la consulta en Telemetry. Confirme los tipos de campos y decida si los reintentos cuentan como solicitudes independientes. El Receta de tasa de error API incluye un contrato escrito, resultados sintéticos, gráficos y casos extremos operativos.
2. Consulta Telemetry y publica el resultado.
Guarde esto como scripts/post-telemetry-report.mjs en el repositorio que ejecutará el informe:
const { TELEMETRY_API_KEY, SLACK_WEBHOOK_URL, TELEMETRY_DASHBOARD_URL } =
process.env;
if (!TELEMETRY_API_KEY || !SLACK_WEBHOOK_URL) {
throw new Error(
"TELEMETRY_API_KEY and SLACK_WEBHOOK_URL are required to run this report"
);
}
const sql = `
SELECT
route,
COUNT(*) AS requests,
SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) AS errors,
ROUND(
100.0 * SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0),
2
) AS error_rate_pct
FROM api_request_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY route
ORDER BY error_rate_pct DESC, requests DESC
LIMIT 5
`;
const queryResponse = await fetch("https://api.telemetry.sh/query", {
method: "POST",
headers: {
Authorization: TELEMETRY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ query: sql, realtime: true, json: true }),
});
if (!queryResponse.ok) {
throw new Error(
`Telemetry query failed: ${queryResponse.status} ${await queryResponse.text()}`
);
}
const queryResult = await queryResponse.json();
const rows = Array.isArray(queryResult.data) ? queryResult.data : [];
const lines =
rows.length > 0
? rows.map(
(row) =>
`• \`${row.route}\` — ${row.error_rate_pct}% errors ` +
`(${row.errors}/${row.requests})`
)
: ["• No matching requests in the last 24 hours"];
const dashboardLink = TELEMETRY_DASHBOARD_URL
? `\n<${TELEMETRY_DASHBOARD_URL}|Open the Telemetry dashboard>`
: "";
const slackResponse = await fetch(SLACK_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: "Daily API reliability report",
blocks: [
{
type: "header",
text: { type: "plain_text", text: "Daily API reliability" },
},
{
type: "section",
text: {
type: "mrkdwn",
text:
"*Window:* trailing 24 hours\n" +
lines.join("\n") +
dashboardLink,
},
},
{
type: "context",
elements: [
{
type: "mrkdwn",
text: "Synthetic example format — validate thresholds and counting rules.",
},
],
},
],
}),
});
if (!slackResponse.ok) {
throw new Error(
`Slack delivery failed: ${slackResponse.status} ${await slackResponse.text()}`
);
}
console.log(`Posted ${rows.length} report rows to Slack.`);
Las comprobaciones del entorno se realizan solo cuando se ejecuta este script. No agregan un nuevo requisito a la ruta de inicio o importación de su aplicación.
Evite incluir mensajes de error sin formato, identificadores de clientes, mensajes o cargas útiles de solicitud en el mensaje de Slack. Vincule lectores autorizados al panel para una investigación más profunda.
3. Programe el informe
Crear .github/workflows/telemetry-report.yml:
name: telemetry reliability report
on:
schedule:
- cron: "15 16 * * 1-5"
timezone: "America/Los_Angeles"
workflow_dispatch:
jobs:
post-report:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: node scripts/post-telemetry-report.mjs
env:
TELEMETRY_API_KEY: ${{ secrets.TELEMETRY_API_KEY }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
TELEMETRY_DASHBOARD_URL: ${{ vars.TELEMETRY_DASHBOARD_URL }}
Los flujos de trabajo programados GitHub se ejecutan desde la rama predeterminada. La sintaxis del flujo de trabajo admite cron POSIX y una zona horaria de IANA; revise el comportamiento actual en Referencia de sintaxis del flujo de trabajo de GitHub.
Agregue TELEMETRY_API_KEY y SLACK_WEBHOOK_URL como secretos de acciones cifrados. La URL de un panel normalmente no es un secreto, por lo que puede ser una variable de repositorio si la URL en sí no revela ningún identificador confidencial.
Mantenga workflow_dispatch mientras implementa el informe. Permite al revisor ejecutar el trabajo exacto manualmente antes de esperar la primera ejecución programada.
Hacer visibles los fallos
Un trabajo programado silencioso no es un sistema operativo. Como mínimo:
- permitir que las respuestas de webhooks y consultas que no sean 2xx fallen el flujo de trabajo;
- mantener habilitadas las notificaciones de fallas del programador;
- registre
report_name,window_start,window_end,row_count,delivery_statusylatency_msen un evento de informe acotado; - evite los reintentos automáticos en caso de cargas útiles con formato incorrecto o webhooks revocados;
- use una clave de idempotencia estable si luego cambia a un API que la admita.
Slack puede devolver diferentes respuestas 4xx para cargas útiles no válidas, enlaces deshabilitados, canales archivados o restricciones de políticas. No vuelva a intentarlo cada 4xx a ciegas. Trate un tiempo de espera o 5xx como un error de entrega potencialmente transitorio y limite los reintentos con retroceso.
Diseña un informe que la gente seguirá leyendo
Pon la decisión primero. Un informe útil nombra lo que cambió, muestra el denominador y vincula a la evidencia. Diez filas cuidadosamente elegidas suelen ser mejores que un CSV pegado en el chat.
Utilice una tabla o panel en lugar de chatear cuando los lectores necesiten un filtrado arbitrario. Utilice una alerta en lugar de un informe diario cuando la respuesta no pueda esperar hasta el período programado. Utilice guía de exportación cuando el resultado sea demasiado grande para un mensaje.
Los posibles informes de seguimiento incluyen Costo de LLM por característica, resultados del reintento del trabajo en segundo plano, recuperación de reintento de webhook y Impacto en el cliente durante un incidente..