GCloudのエラーログをSlackに通知する
はじめに
Google Cloud Platform(GCP)を利用していると、システムの異常やエラーを迅速に検知することが重要です。
標準のアラート通知では、エラーが発生したことは通知されますが、詳細なログ内容が表示されず、リンクをクリックして別画面でログを確認する必要があります。
緊急時の問題把握が難しいと感じたため、ログの内容をSlackチャンネルに直接送信する方法を調査&まとめてみました。
tl:dr;
以下のアーキテクチャを構築することによって、上記の問題を解決するができました。
Log Router → Pub/Sub → Cloud Function → Slack Webhook
実装手順
1. Pub/Subトピックの作成
まず、ログデータを一時的に保存するためのPub/Subトピックを作成します。
- GCPコンソールで「Pub/Sub」に移動
- 「トピックを作成」をクリック
- トピック名を入力(例:
logs-to-slack
) - デフォルト設定のまま「作成」をクリック
2. ログシンクの作成
次に、特定の条件に一致するログをPub/Subに転送するためのシンクを作成します。
- GCPコンソールで「ロギング」→「ログルーター」に移動
- 「シンクを作成」をクリック
- シンク名を設定(例:
error-logs-to-slack
) - シンクに含めるログを選択するクエリを入力:
severity>=ERROR
このクエリは重要度が「ERROR」以上のログを対象としています。
- 宛先として「Cloud Pub/Sub」を選択
- 作成したトピック(
logs-to-slack
)を選択 - 「作成」をクリック
3. 権限の設定
シンク作成後、GCPロギングサービスがPub/Subトピックに書き込めるよう権限を設定します。
- シンク作成後に表示されるサービスアカウント(
servic-123456789012@gcp-sa-logging.iam.gserviceaccount.com
のような形式)をメモ - 「IAMと管理」→「IAM」に移動
- 「アクセスを許可」をクリック
- 「プリンシパル」にサービスアカウントのメールアドレスを入力
- ロールとして「Pub/Subパブリッシャー」を選択
- 「保存」をクリック
4. Slackウェブフックの設定
次に、Slackでログを受け取るためのウェブフックを設定します。
- Slack APIにアクセス
- 「Create New App」→「From scratch」を選択
- アプリ名とワークスペースを設定
- 「Incoming Webhooks」を選択し、有効化
- 「Add New Webhook to Workspace」をクリック
- ログを送信するチャンネルを選択
- 生成されたウェブフックURLをコピー
5. Cloud Functionの作成
最後に、Pub/Subからメッセージを受け取り、Slackに送信するCloud Functionを作成します。
- GCPコンソールで「Cloud Functions」に移動
- 「関数を作成」をクリック
- 関数名を入力(例:
logs-to-slack
) - トリガーを「Cloud Pub/Sub」に設定
- 作成したトピックを選択
- 「次へ」をクリック
- ランタイムに「Node.js 20」(または最新バージョン)を選択
- エントリポイントに関数名(
processLogEntry
)を設定
package.json
package.json
{
"name": "sample-pubsub",
"version": "0.0.1",
"dependencies": {
"@google-cloud/pubsub": "^0.18.0",
"@slack/webhook": "^6.1.0"
}
}
index.js
index.js
const {IncomingWebhook} = require('@slack/webhook');
// SlackウェブフックURLを設定
const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL';
const webhook = new IncomingWebhook(SLACK_WEBHOOK_URL);
exports.processLogEntry = async (message, context) => {
try {
// Pub/Subメッセージをデコード
const logEntry = JSON.parse(Buffer.from(message.data, 'base64').toString());
console.log('ログエントリを処理中:', JSON.stringify(logEntry));
// Slack用にログエントリをフォーマット
const slackMessage = formatLogForSlack(logEntry);
// Slackに送信
await webhook.send(slackMessage);
console.log('メッセージが正常にSlackに送信されました');
} catch (error) {
console.error('ログエントリの処理中にエラーが発生しました:', error);
}
};
function formatLogForSlack(logEntry) {
// ログから必要な情報を抽出
const severity = logEntry.severity || 'INFO';
const timestamp = logEntry.timestamp || new Date().toISOString();
let message = '';
if (logEntry.textPayload) {
message = logEntry.textPayload;
} else if (logEntry.jsonPayload) {
message = JSON.stringify(logEntry.jsonPayload, null, 2);
} else {
message = 'No message';
}
const httpRequest = logEntry.httpRequest || {};
const resource = logEntry.resource || {type: 'unknown'};
// ログへのリンクを作成
const projectId = logEntry.resource?.labels?.project_id || 'unknown-project';
const logName = encodeURIComponent(logEntry.logName || '');
const logLink = `https://console.cloud.google.com/logs/query;query=${encodeURIComponent(`logName="${logEntry.logName}"`)}?project=${projectId}`;
// フォーマットされたSlackメッセージを返す
return {
blocks: [
{
type: "header",
text: {
type: "plain_text",
text: `ログエントリ [${severity}]`
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: `*メッセージ:*\n\`\`\`${message}\`\`\``
}
},
{
type: "section",
fields: [
{
type: "mrkdwn",
text: `*タイムスタンプ:* ${timestamp}`
},
{
type: "mrkdwn",
text: `*リソース:* ${resource.type || 'unknown'}`
}
]
},
{
type: "section",
text: {
type: "mrkdwn",
text: `<${logLink}|ログの詳細を表示>`
}
}
].filter(Boolean)
};
}
- SLACK_WEBHOOK_URLを先ほどコピーしたURLに置き換え
- 「デプロイ」をクリック
動作確認
設定が完了したら、実際に動作確認を行います。
- エラーを発生させるようなリクエストをGCPのサービスに送信
- Slackチャンネルを確認し、詳細なログ情報が表示されることを確認
カスタマイズ例
メッセージフォーマットのカスタマイズ
Slackに送信するメッセージの形式は、formatLogForSlack
関数で自由にカスタマイズできます。例えば、特定のフィールドのみを表示したり、色を変更したりすることが可能です。
フィルタの調整
ログシンクのクエリを変更することで、特定の条件のログのみを取得できます。例えば、特定のサービスやリソースタイプに絞り込むこともできます。
セキュリティに関する注意点
Slackウェブフックの認証情報はCloud Functionのコード内に直接記述せず、Secret Managerなどを使って安全に管理するこができます。
まとめ
この記事では、GCPのログを完全な形でSlackに送信する方法をまとめてみしました。
この仕組みにより、エラーやアラートが発生した際に、即座に詳細を確認できるようになり、対応時間の短縮につながります。
また、このアーキテクチャは他のシステムへの連携にも応用できます。例えば、Slackの代わりにDiscordやMicrosoft Teamsに送信することも可能です。
誰かの参考になれば嬉しいです。
Discussion