スケジュールされた SQL レポートを Slack に送信する
スケジュールされた SQL レポートは、レビューされたクエリをチームの繰り返しの習慣に変えます。この便利なバージョンは、チャットに行を貼り付けるだけではありません。時間ウィンドウに名前を付け、分母を含め、耐久性のあるダッシュボードにリンクし、配信が成功したかどうかを記録します。
このガイドでは、Telemetry クエリ API、Slack 受信 Webhook、およびスケジュールされた GitHub アクション ワークフローを使用します。これは統合パターンであり、Telemetry にネイティブの Slack レポート ボタンがあるという主張ではありません。
何を構築するか
レポート ジョブは次のことを行います。
- に対して読み取り専用の SQL クエリを実行します。
api_request_completed; - 結果を小さな Slack Block Kit メッセージにフォーマットします。
- 受信 Webhook を通じて投稿します。
- クエリまたは配信エラーで失敗するため、スケジューラは問題を記録します。
Telemetry API キー、Slack 受信 Webhook URL、Node.js 20 以降、および暗号化されたワークフロー シークレットを構成できるリポジトリが必要です。
Slack は、受信 Webhook を、JSON メッセージ ペイロードを受け入れる一意のシークレット URL として文書化します。 URL をソース管理から外し、公開されている場合はローテーションします。参照 Slack の受信 Webhook ガイド.
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 列は、2 つのリクエストで高いエラー率を維持し、大量のインシデントのように見えないようにします。
まず 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 メッセージに生のエラー メッセージ、顧客 ID、プロンプト、またはリクエスト ペイロードを含めないでください。より詳細な調査を行うために、承認された読者をダッシュボードにリンクします。
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 以外のクエリと Webhook 応答がワークフローに失敗するようにします。
- スケジューラの失敗通知を有効にしておく。
- 記録する
report_name,window_start,window_end,row_count,delivery_status、そしてlatency_ms限定されたレポート イベント内。 - 不正な形式のペイロードまたは取り消された Webhook に対する自動再試行を回避します。
- 後でそれをサポートする API に移行する場合は、安定したべき等キーを使用してください。
Slack は、無効なペイロード、無効なフック、アーカイブされたチャネル、またはポリシー制限に対して異なる 4xx 応答を返すことがあります。 4xx ごとにやみくもに再試行しないでください。タイムアウトまたは 5xx を一時的な配信失敗の可能性があるものとして扱い、バックオフで再試行を制限します。
人々が読み続けられるレポートをデザインする
決断を第一にしましょう。有用なレポートには、何が変更されたのかが記載され、分母が示され、証拠へのリンクが示されます。通常、慎重に選択された 10 行は、チャットに貼り付けられた CSV よりも優れています。
読者が任意のフィルタリングを必要とする場合は、チャットの代わりにテーブルまたはダッシュボードを使用します。スケジュールされた時間枠まで応答を待つことができない場合は、日次レポートの代わりにアラートを使用します。を使用します。 輸出ガイド 結果がメッセージに対して大きすぎる場合。
可能性のある続報には次のものがあります。 機能ごとの LLM コスト, バックグラウンドジョブの再試行結果, Webhook の再試行リカバリ、そして インシデント時の顧客への影響.