예약된 SQL 보고서를 Slack으로 보내기
예약된 SQL 보고서는 검토된 쿼리를 반복적인 팀 습관으로 전환합니다. 유용한 버전은 채팅에 행을 붙여넣는 것 이상의 기능을 수행합니다. 기간 이름을 지정하고, 분모를 포함하고, 지속 가능한 대시보드로 다시 연결하고, 전달 성공 여부를 기록합니다.
이 가이드에서는 Telemetry 쿼리 API, Slack 수신 웹훅 및 예약된 GitHub 작업 워크플로를 사용합니다. 이는 Telemetry에 기본 Slack 보고 버튼이 있다는 주장이 아니라 통합 패턴입니다.
무엇을 구축할 것인가
보고 작업은 다음을 수행합니다.
api_request_completed에 대해 읽기 전용 SQL 쿼리를 실행합니다.- 결과를 작은 Slack Block Kit 메시지로 형식화합니다.
- 들어오는 웹훅을 통해 게시합니다.
- 쿼리 또는 배달 오류가 발생하면 스케줄러가 문제를 기록합니다.
Telemetry API 키, Slack 수신 웹훅 URL, Node.js 20 이상, 암호화된 워크플로 비밀을 구성할 수 있는 저장소가 필요합니다.
Slack은 수신 웹후크를 JSON 메시지 페이로드를 허용하는 고유한 비밀 URL로 문서화합니다. URL을 소스 제어에서 제외하고 노출되는 경우 회전하세요. Slack의 수신 웹훅 가이드를 참조하세요.
1. 보고서 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;
스케줄러와 리더가 서로 다른 시간대를 사용할 수 있으므로 메시지에는 "오늘"이 아닌 "지난 24시간"이라고 표시되어야 합니다. requests 열은 두 요청에 대해 높은 오류율을 유지하여 대용량 사고처럼 보이지 않게 합니다.
먼저 Telemetry에서 쿼리를 테스트합니다. 필드 유형을 확인하고 재시도가 별도의 요청으로 간주되는지 여부를 결정하세요. API 오류율 레시피에는 형식화된 계약, 합성 출력, 차트 및 운영 엣지 케이스가 포함되어 있습니다.
2. Telemetry를 쿼리하고 결과를 게시합니다.
보고서를 실행할 저장소에 이를 scripts/post-telemetry-report.mjs로 저장합니다.
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.`);
환경 검사는 이 스크립트가 실행될 때만 발생합니다. 애플리케이션의 가져오기 또는 시작 경로에 새로운 요구 사항을 추가하지 않습니다.
Slack 메시지에 원시 오류 메시지, 고객 식별자, 프롬프트 또는 요청 페이로드를 포함하지 마세요. 더 심층적인 조사를 위해 승인된 독자를 대시보드에 연결하세요.
3. 보고서 예약
.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 }}
GitHub 예약된 워크플로는 기본 분기에서 실행됩니다. 워크플로 구문은 POSIX cron 및 IANA 시간대를 지원합니다. GitHub의 워크플로 구문 참조에서 현재 동작을 검토하세요.
TELEMETRY_API_KEY 및 SLACK_WEBHOOK_URL를 암호화된 작업 비밀로 추가합니다. 대시보드 URL은 일반적으로 비밀이 아니므로 URL 자체에 민감한 식별자가 표시되지 않는 경우 저장소 변수가 될 수 있습니다.
보고서를 출시하는 동안 workflow_dispatch를 유지하세요. 이를 통해 검토자는 예약된 첫 번째 실행을 기다리기 전에 정확한 작업을 수동으로 실행할 수 있습니다.
실패를 가시화하라
자동 예약 작업은 운영 체제가 아닙니다. 최소한:
- 2xx가 아닌 쿼리 및 웹훅 응답이 워크플로에 실패하도록 합니다.
- 스케줄러의 실패 알림을 활성화된 상태로 유지합니다.
- 제한된 보고 이벤트에
report_name,window_start,window_end,row_count,delivery_status및latency_ms를 기록합니다. - 잘못된 페이로드 또는 취소된 웹후크에 대한 자동 재시도를 방지합니다.
- 나중에 이를 지원하는 API로 이동하는 경우 안정적인 멱등성 키를 사용하세요.
Slack은 유효하지 않은 페이로드, 비활성화된 후크, 보관된 채널 또는 정책 제한에 대해 다양한 4xx 응답을 반환할 수 있습니다. 맹목적으로 4xx마다 재시도하지 마세요. 시간 초과 또는 5xx를 잠재적으로 일시적인 전달 실패로 처리하고 백오프를 통한 한도 재시도를 수행합니다.
사람들이 계속 읽을 보고서를 디자인하세요
결정을 먼저 하세요. 유용한 보고서는 변경된 내용을 나열하고 분모를 표시하며 증거에 대한 링크를 제공합니다. 신중하게 선택한 10개의 행은 일반적으로 채팅에 CSV를 붙여넣는 것보다 낫습니다.
독자에게 임의 필터링이 필요한 경우 채팅 대신 테이블이나 대시보드를 사용하세요. 응답이 예약된 창까지 기다릴 수 없는 경우 일일 보고서 대신 알림을 사용합니다. 결과가 메시지에 비해 너무 큰 경우 내보내기 가이드를 사용하세요.
가능한 후속 보고서에는 기능별 LLM 비용, 백그라운드 작업 재시도 결과, 웹훅 재시도 복구 및 사고 중 고객 영향이 포함됩니다.