GAS×エラー通知|Slack・メールで自動アラートを実現する方法
GASで自動化したスクリプトは、動いている間は快適だが、エラーで止まっていても気づきにくい。日次バッチが3日前から止まっていた、という事態は珍しくない。
エラー発生時にSlackやメールへ自動通知する仕組みを組み込んでおけば、そうした見落としを防げる。ここではコピペで使えるコード付きで、実装手順を説明していく。
目次
エラー通知を入れる理由
自動化が抱える落とし穴
GASによる自動化は便利だが、以下のような問題がつきまとう。
| 問題 | 具体例 | 影響 |
|---|---|---|
| サイレントエラー | APIの仕様変更で処理が失敗 | データ欠損に気づかない |
| タイムアウト | 大量データ処理で6分超過 | 途中で処理が止まる |
| 権限エラー | 共有設定の変更でアクセス不可 | 他メンバーの作業に影響 |
| API制限 | 短時間に大量リクエスト | 一定期間使用不可 |
問題の核心は、エラーの発見が遅れることにある。通知の仕組みを入れておけば、発生から数秒で把握できるし、Slack通知ならチーム全体で共有もできる。
try-catchでエラーを捕捉する
基本構文
GASでエラーを捕捉するにはJavaScriptのtry-catch構文を使う。
function basicErrorHandling() {
try {
// エラーが発生する可能性のある処理
const result = riskyOperation();
console.log('処理成功:', result);
} catch (error) {
// エラーが発生したときの処理
console.error('エラー発生:', error.message);
} finally {
// エラーの有無に関わらず実行される処理
console.log('処理終了');
}
}
エラー情報の取得
errorオブジェクトからは以下の情報を取り出せる。
function getErrorDetails(error) {
return {
message: error.message, // エラーメッセージ
name: error.name, // エラーの種類
stack: error.stack, // スタックトレース
fileName: error.fileName, // ファイル名(あれば)
lineNumber: error.lineNumber // 行番号(あれば)
};
}
メールでエラー通知を送る
【コード①】シンプルなメール通知
まずは最小限の構成から。
/**
* エラー発生時にメールで通知する
* @param {Error} error - 発生したエラー
* @param {string} scriptName - スクリプト名
*/
function sendErrorEmail(error, scriptName) {
const recipient = 'your-email@example.com'; // 通知先メールアドレス
const subject = `【エラー通知】${scriptName}でエラーが発生しました`;
const body = `
以下のエラーが発生しました。
■ スクリプト名
${scriptName}
■ 発生日時
${Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss')}
■ エラーメッセージ
${error.message}
■ スタックトレース
${error.stack || 'なし'}
■ 対応
スクリプトエディタを確認し、エラーの原因を調査してください。
`;
MailApp.sendEmail(recipient, subject, body);
}
// 使用例
function mainProcess() {
const SCRIPT_NAME = '日次データ集計';
try {
// メイン処理
processData();
} catch (error) {
sendErrorEmail(error, SCRIPT_NAME);
throw error; // 必要に応じて再スロー
}
}
メール通知で押さえる点
- 件名に【エラー通知】を付けておくとフィルタ設定しやすい
- 発生日時は必ず記載する。いつ起きたか一目で分かる
- スタックトレースを含めるとデバッグが捗る
Slack Webhookでエラー通知を送る
Slack Webhook URLの取得
- Slack APIにアクセス
- 「Create New App」→「From scratch」
- 「Incoming Webhooks」を有効化
- 「Add New Webhook to Workspace」でチャンネル選択
- 生成されたWebhook URLをコピー
【コード②】Slack通知(基本版)
/**
* Slackにエラー通知を送信する
* @param {Error} error - 発生したエラー
* @param {string} scriptName - スクリプト名
*/
function sendSlackErrorNotification(error, scriptName) {
const WEBHOOK_URL = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL';
const payload = {
username: 'GAS Error Bot',
icon_emoji: ':warning:',
attachments: [{
color: 'danger',
title: `🚨 ${scriptName} でエラーが発生`,
fields: [
{
title: '発生日時',
value: Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss'),
short: true
},
{
title: 'エラー種別',
value: error.name || 'Error',
short: true
},
{
title: 'エラーメッセージ',
value: error.message,
short: false
},
{
title: 'スタックトレース',
value: '```' + (error.stack || 'なし') + '```',
short: false
}
],
footer: 'GAS Error Notification',
ts: Math.floor(Date.now() / 1000)
}]
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
UrlFetchApp.fetch(WEBHOOK_URL, options);
}
エラーレベル別の通知設計
すべてのエラーを同列に扱うと、通知が来ても緊急度が分からない。レベルを分けて対応を変える。
/**
* エラーレベルの定義
*/
const ERROR_LEVELS = {
CRITICAL: {
color: '#FF0000',
emoji: ':rotating_light:',
mention: '<!channel>', // チャンネル全員に通知
description: '即時対応が必要'
},
WARNING: {
color: '#FFA500',
emoji: ':warning:',
mention: '',
description: '確認が必要'
},
INFO: {
color: '#0000FF',
emoji: ':information_source:',
mention: '',
description: '参考情報'
}
};
/**
* エラーレベルに応じたSlack通知
*/
function sendLeveledSlackNotification(error, scriptName, level = 'WARNING') {
const WEBHOOK_URL = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL';
const config = ERROR_LEVELS[level];
const payload = {
text: config.mention,
username: 'GAS Alert System',
icon_emoji: config.emoji,
attachments: [{
color: config.color,
title: `${config.emoji} [${level}] ${scriptName}`,
text: config.description,
fields: [
{
title: '発生日時',
value: Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss'),
short: true
},
{
title: 'エラーメッセージ',
value: error.message,
short: false
}
]
}]
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
};
UrlFetchApp.fetch(WEBHOOK_URL, options);
}
// 使用例
try {
criticalProcess();
} catch (error) {
sendLeveledSlackNotification(error, 'データ同期処理', 'CRITICAL');
}
実践例① 日次バッチのエラー監視
日次で走るバッチ処理に、エラー監視を組み込む例。
【コード③】日次バッチ監視システム
/**
* 日次バッチ処理のラッパー
* エラー発生時に自動通知 + ログ記録
*/
function dailyBatchWithMonitoring() {
const SCRIPT_NAME = '日次売上集計バッチ';
const startTime = new Date();
let status = 'SUCCESS';
let errorInfo = null;
try {
console.log(`[${SCRIPT_NAME}] 処理開始: ${startTime}`);
// ===== メイン処理 =====
step1_fetchData();
step2_processData();
step3_updateSheet();
step4_generateReport();
// =====================
console.log(`[${SCRIPT_NAME}] 処理完了`);
} catch (error) {
status = 'FAILED';
errorInfo = error;
// エラー通知(Slack + メール)
sendSlackErrorNotification(error, SCRIPT_NAME);
sendErrorEmail(error, SCRIPT_NAME);
console.error(`[${SCRIPT_NAME}] エラー発生: ${error.message}`);
} finally {
// 実行ログを記録
logExecutionResult(SCRIPT_NAME, startTime, status, errorInfo);
}
}
/**
* 実行結果をスプレッドシートに記録
*/
function logExecutionResult(scriptName, startTime, status, error) {
const LOG_SHEET_ID = 'YOUR_LOG_SHEET_ID';
const sheet = SpreadsheetApp.openById(LOG_SHEET_ID).getSheetByName('実行ログ');
const endTime = new Date();
const duration = (endTime - startTime) / 1000; // 秒
sheet.appendRow([
Utilities.formatDate(startTime, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss'),
scriptName,
status,
duration + '秒',
error ? error.message : '-'
]);
}
実践例② トリガー実行のエラーログ
トリガーで実行されるスクリプトは、エラーが起きても画面に表示されない。すべてのトリガー実行をログに残す仕組みを作っておくと安心できる。
/**
* トリガー実行用のエラーハンドリングラッパー
* @param {Function} mainFunction - メイン処理関数
* @param {string} functionName - 関数名(ログ用)
*/
function triggerWrapper(mainFunction, functionName) {
const executionId = Utilities.getUuid();
try {
console.log(`[${executionId}] ${functionName} 開始`);
mainFunction();
console.log(`[${executionId}] ${functionName} 正常終了`);
// 成功時もログに記録(オプション)
logToSheet(executionId, functionName, 'SUCCESS', null);
} catch (error) {
console.error(`[${executionId}] ${functionName} エラー: ${error.message}`);
// エラーログ記録
logToSheet(executionId, functionName, 'ERROR', error);
// 通知送信
sendSlackErrorNotification(error, functionName);
// エラーを再スローしない(トリガーの連続失敗を防ぐ)
}
}
/**
* スプレッドシートにログを記録
*/
function logToSheet(executionId, functionName, status, error) {
const props = PropertiesService.getScriptProperties();
const LOG_SHEET_ID = props.getProperty('LOG_SHEET_ID');
if (!LOG_SHEET_ID) return;
const sheet = SpreadsheetApp.openById(LOG_SHEET_ID).getSheetByName('トリガーログ');
sheet.appendRow([
new Date(),
executionId,
functionName,
status,
error ? error.message : '-',
error ? error.stack : '-'
]);
}
// トリガーに設定する関数
function scheduledTask() {
triggerWrapper(actualTask, 'scheduledTask');
}
function actualTask() {
// 実際の処理をここに書く
const data = fetchExternalData();
processAndSave(data);
}
エラー通知のベストプラクティス
1. 通知先の使い分け
| 状況 | 推奨通知先 | 理由 |
|---|---|---|
| 即時対応が必要 | Slack(チャンネルメンション) | すぐに気づける |
| 日次確認で十分 | メール or Slack(通常) | 通知疲れを防ぐ |
| ログとして残したい | スプレッドシート | 後から検索・分析可能 |
| 複数人で対応 | Slack + メンション | チームで共有 |
2. 通知内容に含めるべき情報
✅ 必須項目
- スクリプト名
- 発生日時
- エラーメッセージ
- エラーの種類
✅ あると便利
- スタックトレース
- 実行ID(複数ログの紐付け用)
- 影響範囲
- 復旧手順へのリンク
3. 通知疲れを防ぐ
同じエラーが連続発生すると、通知が大量に飛ぶ。スロットリングを入れて抑制する。
/**
* 同一エラーの連続通知を抑制
*/
function sendNotificationWithThrottle(error, scriptName) {
const cache = CacheService.getScriptCache();
const cacheKey = `error_${scriptName}_${error.message}`.slice(0, 250);
// 過去5分以内に同じエラーを通知済みかチェック
if (cache.get(cacheKey)) {
console.log('同一エラーの通知を抑制');
return;
}
// 通知送信
sendSlackErrorNotification(error, scriptName);
// 5分間キャッシュ(同じエラーの再通知を防ぐ)
cache.put(cacheKey, 'sent', 300);
}
4. 復旧手順を用意しておく
エラーが起きたときにパニックにならないよう、主要なエラーへの対応手順をドキュメント化しておくとよい。
// エラー別の対応手順リンクを通知に含める
const ERROR_RECOVERY_DOCS = {
'Exceeded maximum execution time': 'https://your-docs/timeout-recovery',
'Service invoked too many times': 'https://your-docs/quota-recovery',
'Access denied': 'https://your-docs/permission-recovery'
};
function getRecoveryDoc(errorMessage) {
for (const [pattern, url] of Object.entries(ERROR_RECOVERY_DOCS)) {
if (errorMessage.includes(pattern)) {
return url;
}
}
return 'https://your-docs/general-troubleshooting';
}
まとめ
導入のステップ
Step 1: 既存スクリプトにtry-catchを追加
Step 2: sendErrorEmail関数を追加してテスト
Step 3: Slack Webhookを設定
Step 4: エラーレベル別の通知を実装
Step 5: 通知スロットリングで最適化
try-catchで捕捉し、メールかSlackで飛ばし、スプレッドシートにログを残す。この3段構えでGASの自動化は格段に安定する。エラー通知の有無が、運用の信頼性を分ける。
※ この記事のコードはそのままコピペで動作しますが、WEBHOOK_URLやメールアドレスは必ずご自身のものに変更してください。
コメント