GASのログ出力とデバッグの基本
console.logとLoggerの使い分け

GASで「思ったとおりに動かない」を解決する第一歩はログを出すことです。console.logLogger.logの違い、トリガー実行のログの見方、エラーの記録と通知までを動くコードで解説します。

|対象: console.log / Logger.log / 実行数 / try-catch

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.warnconsole.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

01
Apps Scriptエディタ左メニューの「実行数」を開く
02
関数名・開始時刻・実行タイプ(トリガー/手動)・ステータスの一覧が並ぶ
03
確認したい行をクリックして展開する
04
その実行のときの console.log 出力とエラーを確認する

「失敗(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に統一(Cloud Loggingにも残る)
warn/errorでレベルを分けて絞り込みやすくする
オブジェクトはカンマ渡しかJSON.stringifyで整形
try-catch+e.stackで失敗を記録しメール通知
トリガー実行のログは「実行数」で後から確認
節目の記録は専用ログシートに1行ずつ残す

よくある質問

新しく書くなら基本は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開発・業務自動化を
相談する。

「トリガーで動かした処理が失敗していないか不安」「ログや通知の仕組みまで含めて任せたい」といったご相談も歓迎です。 現在の業務・課題をお聞きした上でご提案します。

GAS開発の対応範囲を見る