GASのログ出力とデバッグの基本
console.logとLoggerの使い分け
GASで「思ったとおりに動かない」を解決する第一歩はログを出すことです。console.logとLogger.logの違い、トリガー実行のログの見方、エラーの記録と通知までを動くコードで解説します。
Table of Contents
GASのログは主に3か所に残る
GAS(Google Apps Script。Googleサービスを自動化するスクリプト)でデバッグ(不具合の原因調べ)をするとき、出力したログの行き先を知っておくと迷いません。ログの出力先は主に3か所です。
実行ログ
エディタで関数を実行した直後に下部へ表示される。手元での確認に最適。
実行数(Executions)
手動・トリガーを問わず過去の実行が一覧に残る。後から追える。
Cloud Logging
console.logの出力が溜まるGoogle Cloud側のログ。検索やアラートに使える。
ポイントは、console.logの出力はエディタを閉じた後でも「実行数」やCloud Loggingに残る点です。トリガーで夜間に動く処理でも、後からログを追えます。
console.log と Logger.log の違いと使い分け
結論から言うと、新しく書くならconsole.logで問題ありません。Logger.logはGAS独自の古いロガーで、consoleの方が複数の値をそのまま渡せて扱いやすいためです。
function logBasics() {
const value = 42;
// 推奨: console.log。複数の値はカンマで並べて渡せる
console.log('計算結果は', value, 'です');
// GAS独自の古いロガー。こちらも実行ログに残る
Logger.log('計算結果は %s です', value);
}使い分けの目安
現在のV8ランタイム(GASの標準実行環境)では、どちらの出力も実行ログに表示されます。加えてconsole.logはCloud Loggingにも残るため、検索・アラート・長期保管まで見据えるならconsoleに統一するのが無難です。
ログレベル(info / warn / error)を使い分ける
すべてconsole.logで出すと、大量のログの中から本当に見たいエラーを探すのが大変になります。レベルを分けておくと、Cloud Loggingで「エラーだけ」に絞り込めます。
function logLevels() {
console.log('通常の処理ログ'); // info相当。普段づかい
console.info('補足情報'); // 補足メッセージ
console.warn('件数が想定より多い'); // 警告(黄色で強調)
console.error('APIの呼び出しに失敗'); // エラー(赤色で強調)
}console.warnとconsole.errorは実行ログ上でも色付きで強調され、目で追うときにも見つけやすくなります。「正常だが注意したいこと」はwarn、「処理が失敗したこと」はerrorと決めておくと運用が楽です。
オブジェクトを見やすくログに出す
よくあるつまずきが、オブジェクトをログに出したら[object Object]になってしまう問題です。原因は文字列と+で結合していることです。
function logObject() {
const row = { name: '田中', age: 30, tags: ['GAS', 'AI'] };
// NG: 文字列と結合すると [object Object] になる
console.log('data: ' + row);
// → data: [object Object]
// OK: カンマで渡すとオブジェクトのまま展開される
console.log('data:', row);
// OK: 見やすく整形したい場合は JSON.stringify
console.log(JSON.stringify(row, null, 2));
// {
// "name": "田中",
// "age": 30,
// "tags": ["GAS", "AI"]
// }
}値をカンマで渡せばオブジェクトのまま展開されます。ネストが深い構造や、後で貼り付けて確認したいときはJSON.stringify(obj, null, 2)で整形するのがおすすめです。第3引数の2はインデントの空白数です。
try-catch でエラーを記録して通知する
トリガーで自動実行する処理が静かに失敗し続けるのは、実務でいちばん怖いパターンです。重要な処理はtry-catchで囲み、失敗をconsole.errorに残したうえでメール通知しましょう。
function importWithLogging() {
try {
console.log('処理を開始します');
const sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('データ');
const values = sheet.getDataRange().getValues();
console.log('読み込み件数:', values.length - 1);
// ... ここで本処理 ...
console.log('処理が正常に完了しました');
} catch (e) {
// スタックトレース付きでエラーを記録する
console.error('処理に失敗しました:', e.stack);
// 管理者にメールで通知する(静かな失敗を防ぐ)
MailApp.sendEmail(
'admin@example.com',
'[GAS] バッチ処理でエラー',
'エラー内容:\n' + e.stack
);
}
}e.stack を使う理由
e.messageだけだと「どの行で落ちたか」が分かりません。e.stackを記録すると、エラーの内容と発生箇所(スタックトレース)まで残せて、原因調査が一気に楽になります。
通知先はメールに限りません。Slackへの通知に置き換える方法はGASからSlackに自動通知する方法を参考にしてください。
トリガー実行のログを後から確認する
時間主導トリガーやonEditなどで自動実行された処理のログは、エディタを開いていなくても残ります。Apps Scriptエディタの左メニューにある「実行数(Executions)」を開くと確認できます。
Steps
「失敗(Failed)」ステータスの行は、トリガー処理がエラーで止まった実行です。ここを定期的に見るだけでも、気づかないうちに壊れている自動処理を早めに発見できます。
スプレッドシートに独自の実行ログを残す
「いつ・何件処理したか」を業務担当者にも見える形で残したいときは、専用のログシートに1行ずつ追記するのが手軽です。エンジニアでなくても中身を確認でき、後からの証跡(あとで振り返れる記録)にもなります。
// 専用の「ログ」シートに実行記録を1行ずつ追記する
function writeLog(level, message) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName('ログ');
// シートが無ければ作ってヘッダーを付ける
if (!sheet) {
sheet = ss.insertSheet('ログ');
sheet.appendRow(['日時', 'レベル', 'メッセージ']);
}
const now = Utilities.formatDate(
new Date(),
'Asia/Tokyo',
'yyyy/MM/dd HH:mm:ss'
);
sheet.appendRow([now, level, message]);
}
function useWriteLog() {
writeLog('INFO', 'バッチ処理を開始');
// ... 処理 ...
writeLog('INFO', '3件を更新しました');
}処理時間を測りたいときはDate.now()の差分をログに出すのが簡単です。V8ランタイムならconsole.time()とconsole.timeEnd()も使えます。
function measureTime() {
const start = Date.now();
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
const values = sheet.getDataRange().getValues(); // 重い可能性のある処理
const elapsed = Date.now() - start;
console.log('読み込みにかかった時間:', elapsed, 'ms');
// V8ランタイムなら console.time / timeEnd も使える
console.time('集計');
const total = values.reduce((sum, row) => sum + (Number(row[2]) || 0), 0);
console.timeEnd('集計'); // → 集計: 12 ms のように出力
console.log('合計:', total);
}ログシートを使うときの注意
大量ループの中で毎回appendRowを呼ぶと処理が遅くなります。細かいデバッグ用ログはconsole.logに任せ、ログシートには「開始・完了・件数・エラー」など節目の記録だけを残すのがおすすめです。
まとめ
GASのデバッグは、まず正しくログを出すことから始まります。普段づかいはconsole.logに統一し、レベル分けとオブジェクトの整形、そしてtry-catchでの記録・通知を押さえておけば、トリガーで動く自動処理も安心して運用できます。
この記事のポイント
よくある質問
新しく書くなら基本はconsole.logで問題ありません。V8ランタイムではconsole.logの出力がエディタの実行ログにもGoogle CloudのCloud Loggingにも残り、複数の値をカンマで並べて渡せます。Logger.logはGAS独自の古いロガーで、こちらも実行ログに残りますが、機能面ではconsoleに一本化して使い分けを減らす方がシンプルです。
Apps Scriptエディタ左メニューの「実行数(Executions)」画面で見られます。手動実行だけでなく、時間主導トリガーやonEditなどのトリガー実行も一覧に並び、各行を開くとそのときのconsole.log出力を確認できます。エディタを閉じていた間のトリガー実行のログも後から追えます。
文字列と結合するとそうなります。console.log('data: ' + obj)ではなく、console.log('data:', obj)のようにカンマで渡すか、console.log(JSON.stringify(obj, null, 2))で整形した文字列にして出力してください。後者はネストした中身まで見やすく展開されます。
重要な処理をtry-catchで囲み、catchの中でconsole.error()にエラーを記録したうえで、MailAppやSlackで管理者に通知するのが定番です。Cloud Loggingにはアラート機能もありますが、まずはcatchでメール通知を入れておくと、トリガー実行が静かに失敗し続ける事故を防げます。
処理の前後でDate.now()を取り、差分をconsole.logに出すのが手軽です。区間ごとにミリ秒を出せば、どのステップが重いか切り分けられます。V8ランタイムではconsole.time()とconsole.timeEnd()も使えるので、区間名を付けて計測することもできます。
GAS開発・業務自動化を
相談する。
「トリガーで動かした処理が失敗していないか不安」「ログや通知の仕組みまで含めて任せたい」といったご相談も歓迎です。 現在の業務・課題をお聞きした上でご提案します。