この記事では、GCPのCloud Loggingで検知したエラーログを、Pub/SubとCloud Run Functionsを経由してChatworkに自動通知するシステムの構築方法を解説します。
システム構成
前提条件
- GCPプロジェクトが作成済み
- Chatworkアカウントを持っている
- GCP Consoleへのアクセス権限がある
利用するGCPサービス
- Cloud Logging(ログ収集・フィルタリング)
- Pub/Sub(メッセージキュー)
- Cloud Run Functions(サーバーレス実行環境)
- Secret Manager(認証情報管理)
- Eventarc(イベント駆動型トリガー)
セットアップ手順
全体の流れは以下の6ステップです:
- Chatwork準備(APIトークン、Room ID取得)
- Pub/Sub Topic作成
- ログシンク作成
- Secret Manager設定
- Cloud Run Functions作成・デプロイ
- テスト・動作確認
Step 1: Chatwork準備
1-1. APIトークンの取得
- Chatworkにログイン
- 右上のアイコン → サービス連携 をクリック
- 左メニューから API Token を選択
- 新しいトークンを発行する をクリック
- 表示されたAPIトークンをコピーして保存
APIトークンは一度しか表示されません。必ず安全な場所に保存してください。
1-2. Room IDの取得
- 通知を送りたいチャットルームを開く
- ブラウザのURLを確認:
https://www.chatwork.com/#!rid123456789 -
ridの後の数字(例:123456789)がRoom ID
取得した情報をメモしておきましょう:
- APIトークン:
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 - Room ID:
123456789
Step 2: Pub/Sub Topic作成
2-1. GCP Consoleでの操作
- GCP Console にアクセス
- ナビゲーションメニュー → Pub/Sub を選択
- プロジェクト
test-loggingを選択
2-2. トピック作成
トピック作成 ボタンをクリックし、以下を設定:
| 項目 | 設定値 |
|---|---|
| トピック ID | error-log-notifications |
| デフォルトのサブスクリプションを追加 | チェックなし |
| 暗号化 | Google管理の暗号鍵(デフォルト) |
その他の設定はデフォルトのまま 作成 をクリック。
Step 3: ログシンク作成
3-1. ログルーター画面を開く
- ナビゲーションメニュー → ロギング → ログ ルーター を選択
- シンクを作成 をクリック
3-2. シンクの設定
シンクの詳細
| 項目 | 設定値 |
|---|---|
| シンク名 | error-log-sink |
| シンクの説明 | ERRORレベル以上のログをPub/Subに転送 |
シンクの送信先
| 項目 | 設定値 |
|---|---|
| シンク サービス | Cloud Pub/Sub トピック |
| トピック | projects/test-logging/topics/error-log-notifications |
ログフィルタ
severity >= ERROR
このフィルタでERROR、CRITICAL、ALERTレベルのログのみを転送します。
シンクを作成 をクリック。
3-3. 権限付与(重要)
シンク作成後、Pub/Subへの書き込み権限を付与する必要があります。
Cloud Shellを開いて以下を実行:
# ログシンクのwriterIdentityを取得
WRITER_IDENTITY=$(gcloud logging sinks describe error-log-sink \
--project=test-logging \
--format="value(writerIdentity)")
echo "Writer Identity: $WRITER_IDENTITY"
# Pub/Subトピックに権限付与
gcloud pubsub topics add-iam-policy-binding error-log-notifications \
--member="${WRITER_IDENTITY}" \
--role='roles/pubsub.publisher' \
--project=test-logging
権限付与が成功すると、Updated IAM policy for topic [error-log-notifications] と表示されます。
Step 4: Secret Manager設定
4-1. Secret Manager APIの有効化
- ナビゲーションメニュー → セキュリティ → Secret Manager を選択
- 初回の場合、APIを有効にする をクリック
4-2. シークレット作成
Chatwork APIトークン
シークレットを作成 をクリックし、以下を設定:
| 項目 | 設定値 |
|---|---|
| 名前 | chatwork-api-token |
| シークレットの値 | (Step 1で取得したAPIトークン) |
Chatwork Room ID
同様に、もう1つシークレットを作成:
| 項目 | 設定値 |
|---|---|
| 名前 | chatwork-room-id |
| シークレットの値 | (Step 1で取得したRoom ID) |
Step 5: Cloud Run Functions作成・デプロイ
5-1. Cloud Functions APIの有効化
- ナビゲーションメニュー → Cloud Run functions を選択
- 初回の場合、APIを有効にする をクリック
5-2. 関数作成
関数を作成 をクリックし、基本設定を行います。
基本設定
| 項目 | 設定値 |
|---|---|
| 関数名 | chatwork-notifier-function |
| リージョン | asia-northeast1 |
| ランタイム | Node.js 24 |
| トリガーのタイプ | Pub/Sub トリガー |
Eventarcトリガー設定
1.Eventarc APIの有効化
- ナビゲーションメニュー → Eventarc を選択
- 初回の場合、APIを有効にする をクリック
基本設定
| 項目 | 設定値 |
|---|---|
| トリガーの名前 | pubsub-to-chatwork-trigger |
| トリガーのタイプ | Google のソース |
| イベント プロバイダ | Cloud Pub/Sub |
| イベント タイプ | google.cloud.pubsub.topic.v1.messagePublished |
| Pub/Subトピック | projects/test-logging/topics/error-log-notifications |
| リージョン | asia-northeast1 |
| サービス アカウント | Default compute service account |
警告が表示された場合は 付与 ボタンをクリックして権限を自動付与してください。
トリガーを保存 をクリック。
シークレット設定
シークレットと環境変数 タブで、以下の2つを追加:
1つ目:
- 参照するシークレット:
chatwork-api-token - 参照方法: 環境変数として公開
- バージョン:
latest - 環境変数:
CHATWORK_API_TOKEN
2つ目:
- 参照するシークレット:
chatwork-room-id - 参照方法: 環境変数として公開
- バージョン:
latest - 環境変数:
CHATWORK_ROOM_ID
設定完了後、次へ をクリック。
5-3. コード入力
package.json
{
"name": "chatwork-notifier-function",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^3.3.0",
"axios": "^1.6.2"
},
"engines": {
"node": ">=18"
}
}
index.js
const functions = require('@google-cloud/functions-framework');
const axios = require('axios');
// CloudEventハンドラー
functions.cloudEvent('chatworkNotifierFunction', async (cloudEvent) => {
try {
console.log('Received CloudEvent:', JSON.stringify(cloudEvent, null, 2));
// Pub/Subメッセージのデコード
const base64Data = cloudEvent.data.message.data;
const messageData = Buffer.from(base64Data, 'base64').toString('utf-8');
const logEntry = JSON.parse(messageData);
console.log('Log entry:', JSON.stringify(logEntry, null, 2));
// ログ情報の抽出
const severity = logEntry.severity || 'UNKNOWN';
const timestamp = logEntry.timestamp || '';
const resource = logEntry.resource || {};
const textPayload = logEntry.textPayload || '';
const jsonPayload = logEntry.jsonPayload || {};
const logName = logEntry.logName || '';
// リソース情報
const resourceType = resource.type || 'unknown';
const resourceLabels = resource.labels || {};
const projectId = resourceLabels.project_id || 'unknown';
const serviceName = resourceLabels.service_name || resourceLabels.function_name || 'unknown';
// エラーメッセージの取得
const errorMessage = textPayload || jsonPayload.message || JSON.stringify(jsonPayload) || 'No message';
// Chatworkメッセージの構築
const chatworkMessage = buildChatworkMessage(
severity,
timestamp,
projectId,
serviceName,
resourceType,
errorMessage,
logName
);
// Chatworkに送信
await sendToChatwork(chatworkMessage);
console.log('Successfully sent notification to Chatwork');
} catch (error) {
console.error('Error processing CloudEvent:', error);
throw error;
}
});
/**
* Chatwork用のメッセージを構築
*/
function buildChatworkMessage(severity, timestamp, projectId, serviceName, resourceType, errorMessage, logName) {
// 絵文字を選択
const emoji = severity === 'ERROR' ? '🚨' : severity === 'CRITICAL' ? '🔥' : '⚠️';
// タイムスタンプを読みやすく整形
const displayTime = timestamp.replace('T', ' ').replace('Z', ' UTC');
// エラーメッセージを500文字に制限
const truncatedMessage = errorMessage.length > 500
? errorMessage.substring(0, 500) + '...'
: errorMessage;
const message = `[info][title]${emoji} エラー検知 - ${severity}[/title]
【プロジェクト】${projectId}
【サービス】${serviceName}
【リソースタイプ】${resourceType}
【時刻】${displayTime}
【エラー内容】
${truncatedMessage}
【ログ名】
${logName}
[/info]`;
return message;
}
/**
* Chatwork APIにメッセージを送信
*/
async function sendToChatwork(message) {
const apiToken = process.env.CHATWORK_API_TOKEN;
const roomId = process.env.CHATWORK_ROOM_ID;
if (!apiToken || !roomId) {
throw new Error('CHATWORK_API_TOKEN or CHATWORK_ROOM_ID not set');
}
const url = `https://api.chatwork.com/v2/rooms/${roomId}/messages`;
try {
const response = await axios.post(
url,
`body=${encodeURIComponent(message)}`,
{
headers: {
'X-ChatWorkToken': apiToken,
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
console.log('Chatwork API response:', response.data);
return response.data;
} catch (error) {
console.error('Chatwork API error:', error.response?.data || error.message);
throw error;
}
}
5-4. デプロイ
デプロイ ボタンをクリックし、完了を待ちます(2〜3分)。
関数一覧に chatwork-notifier-function が表示され、緑のチェックマークが付けば成功です。
Step 6: テスト・動作確認
6-1. テストログ送信
Cloud Shellで以下を実行:
# プロジェクト設定
gcloud config set project test-logging
# テストログ送信
gcloud logging write test-error \
"Test ERROR: Chatwork notification test from Cloud Shell" \
--severity=ERROR \
--project=test-logging
成功すると Created log entry. と表示されます。
6-2. ログ確認
Cloud Functionsのログ
gcloud functions logs read chatwork-notifier-function \
--gen2 \
--region=asia-northeast1 \
--limit=30 \
--test-logging
以下のようなログが表示されればOK:
LEVEL: INFO
LOG: Received CloudEvent: {...}
LEVEL: INFO
LOG: Log entry: {"severity":"ERROR",...}
LEVEL: INFO
LOG: Chatwork API response: {"message_id":"..."}
LEVEL: INFO
LOG: Successfully sent notification to Chatwork
GCP Consoleでの確認
- Cloud Run functions →
chatwork-notifier-function→ ログ タブ - 最新のログを確認
6-3. Chatwork通知確認
指定したChatworkルームを開き、以下のような通知が届いていることを確認:
トラブルシューティング
通知が届かない場合
1. Cloud Functionsのエラーログを確認
gcloud functions logs read chatwork-notifier-function \
--gen2 \
--region=asia-northeast1 \
--limit=50 \
--project=test-logging | grep -i error
よくあるエラーと対処法:
| エラーメッセージ | 原因 | 対処法 |
|---|---|---|
CHATWORK_API_TOKEN not set |
Secret Managerの設定漏れ | Step 4とStep 5-2を再確認 |
status code 401 |
APIトークンが無効 | Chatworkでトークンを再発行 |
status code 404 |
Room IDが間違っている | Room IDを再確認 |
Cloud Functionsが起動しない場合
Eventarcトリガーの状態確認
Eventarc → pubsub-to-chatwork-trigger でステータスが アクティブ になっているか確認
Pub/Subの権限確認
gcloud pubsub topics get-iam-policy error-log-notifications \
--project=test-logging
service-XXXXX@gcp-sa-pubsub.iam.gserviceaccount.com に roles/iam.serviceAccountTokenCreator があることを確認
ログがPub/Subに届かない場合
ログシンクの権限確認
# ログシンクの状態確認
gcloud logging sinks describe error-log-sink \
--project=test-logging
# Pub/Subトピックの権限確認
gcloud pubsub topics get-iam-policy error-log-notifications \
--project=test-logging
service-XXXXX@gcp-sa-logging.iam.gserviceaccount.com に roles/pubsub.publisher があることを確認
権限がない場合は、Step 3-3を再実行してください。
まとめ
本記事では、GCPのCloud LoggingからChatworkへの自動通知システムを構築しました。



