读取已部署的Google脚本的日志

时间:2014-05-17 13:17:09

标签: google-apps-script

有没有办法阅读已发布的google apps脚本的日志?

目前,我可以在调试模式下使用Logger.log()获取日志。

但是当我们在发布脚本时遇到某些问题时,就无法实现其原因。

2 个答案:

答案 0 :(得分:2)

这是我用于记录和错误检查的调试对象。它总是写入Logger,但也写入一个名为" log"在链接的电子表格中。我已经从我正在处理的脚本(Flubaroo)中复制了这个内容,因此可能会遗漏一些外部函数。

// debug.gas.gs
// ============
//
// Development/debug functions.

// TODO_AJR - Add function name as first parameter of logging functions

// TODO_AJR - Generally, should there be some indication to the user that,
// there has been an error when debug is turned off? Couldn't we try and 
// catch the errors further up rather than ignoring them in production and
// letting GAS catch them in debug.

// Unit Tests
// ==========

// testDebugClass()
// ----------------
//
// Unit tests for DebugClass(). Check log for results.

function testDebugClass()
{
  Debug.info("testDebugClass() - PASS - info test call");
  Debug.warning("testDebugClass() - PASS - warning test call");

  Debug.assert_w(false, "testDebugClass() - PASS - assert_w test call");  

  // This will test Debug.error().
  Debug.assert(true, "testDebugClass() - FAIL - Should not see this");

  Debug.info("testDebugClass() - All tests PASSED");

  return true;

} // testDebugClass()

// Debug Service
// =============

Debug = new DebugClass();

function DebugClass()
{
  this.debugOn = DEBUG_ON;
  this.loggingOn = LOGGING_ON;
  this.log_sheet;
  this.last_msg;

} // DebugClass()

// DebugClass.info()
// -----------------
//
// Output debug trace.

DebugClass.prototype.info = function(msg)
{
  Logger.log(msg);

  this.last_msg = msg;

  if (!this.loggingOn)
    {
      return;
    }

  if (typeof this.log_sheet === 'undefined')
    { 
      // Store log sheet name.

      this.log_sheet = SpreadsheetApp.getActiveSpreadsheet()
                                     .getSheetByName(LOG_SHEET_NAME);

      if (this.log_sheet === null)
        {
          // TODO_AJR - Could create it.
          // TODO_AJR - use langStr.

          Browser.msgBox(langstr("FLB_STR_NOTIFICATION"), 
                         "You need to create a sheet called " + 
                           LOG_SHEET_NAME + 
                           " with logging enabled", 
                         Browser.Buttons.OK);

          this.error("DebugClass.info() - no 'log' sheet");

          return;
        }
    }

  if (this.log_sheet === null)
    {
      // Attempted, but failed, to find the log sheet on a 
      // previous call to info().
      return;
    }

  // Add the trace message to the end of log sheet.

  var row = this.log_sheet.getLastRow() + 1;
  var range = this.log_sheet.getRange(row, 1, 1, 2);
  var time = new Date();

  range.setValues([[time, msg]]);

} // DebugClass.info()

// DebugClass.warning()
// --------------------
//
// Output warning.

DebugClass.prototype.warning = function(msg)
{ 
  if (typeof msg !== "string")
    {
      this.error("DebugClass.warning() - incorrect parameter type");
    }

  this.info("WARNING - " + msg);

} // DebugClass.warning()

// DebugClass.error()
// ------------------
//
// Output error trace and throw an error (only this function
// should decide whether to throw the errors).

DebugClass.prototype.error = function(msg)
{ 
  if (typeof msg !== "string")
    {
      msg = "DebugClass.error() - parameter must be a string";

      this.info(msg);

      if (this.debugOn)
        {
          throw(msg);
        }
    }

  this.info("ERROR - " + msg);

  if (this.debugOn)
  {
    throw(msg);
  }

} // DebugClass.error()

// DebugClass.assert()
// -------------------
//
// Issue error if assertion false.

DebugClass.prototype.assert = function(assertion, msg) 
{ 
  if (typeof assertion !== "boolean")
    {
      assertion = false;
      msg = "DebugClass.assert() - first parameter must be a boolean";
    }
  else if (typeof msg !== 'string')
    {
      assertion = false;
      msg = "DebugClass.assert() - second parameter must be a string";
    }

  if (!assertion)
    {
      this.error(msg);
    }

} // DebugClass.assert()

// assert_w()
// ----------
//
// Issue warning if assertion false.

DebugClass.prototype.assert_w = function(assertion, msg) 
{ 
  if (typeof assertion !== 'boolean')
    {
      assertion = false;
      msg = "DebugClass.assert_w() - first parameter must be a boolean";
    }
  else if (typeof msg !== 'string')
    {
      assertion = false;
      msg = "DebugClass.assert_w() - second parameter must be a string";
    }

  if (!assertion)
    {
      this.warning(msg);
    }

} // DebugClass.assert_w()

// Event Handlers
// ==============

function debugMenu(menuEntries)
{
  if (Debug.debugOn)
    {
      // Line break.
      menuEntries.push(null);

      menuEntries.push({name: "Debug: Reset", functionName: "resetFlubaroo"});

      menuEntries.push({name: "Debug: Reinitialize", functionName: "reinitialize"});

      if (UI.isOn())
        {
          menuEntries.push({name: "Debug: Skip UI", functionName: "skipUIMenu"});
        }
      else
        {
          menuEntries.push({name: "Debug: Display UI", functionName: "displayUIMenu"});
        }

      menuEntries.push({name: "Debug: Clear Log", functionName: "logClear"});

      menuEntries.push({name: "Debug: Dump Config", functionName: "dumpConfig"});

      menuEntries.push({name: "Debug: Trigger Autograde", functionName: "onAutogradeSubmission"});

      menuEntries.push({name: "Debug: Run Tests", functionName: "runTests"});

      menuEntries.push({name: "Debug: Delete Grades", functionName: "deleteGradesSheet"});

      if (ScriptProperties.getProperty(SCRIPT_PROP_SKIP_EMAIL))
        {
          menuEntries.push({name: "Debug: Send Emails", functionName: "toggleEmailSending"});
        }
      else
        {
          menuEntries.push({name: "Debug: Skip Emailing", functionName: "toggleEmailSending"});
        }
    }

} // debugMenu()

// dumpConfig()
// ------------

function dumpConfig()
{  
  Debug.info("dumpConfig() - SCRIPT_PROP_NUM_GRADED_SUBM: " + 
             Number(ScriptProperties.getProperty(SCRIPT_PROP_NUM_GRADED_SUBM)));

  Debug.info("dumpConfig() - SCRIPT_PROP_EMPTY_SUBM_ROW_PTR: " + 
             Number(ScriptProperties.getProperty(SCRIPT_PROP_EMPTY_SUBM_ROW_PTR)));

} // dumpConfig()

// logClear()
// ----------

function logClear()
{
  Debug.info("logClear()");

  var log_sheet = SpreadsheetApp.getActiveSpreadsheet()
                                .getSheetByName(LOG_SHEET_NAME);

  if (log_sheet)
    {
      log_sheet.deleteRows(1, log_sheet.getMaxRows() - 1);
      log_sheet.insertRowsAfter(1, 5);
    }

} // logClear()

// reinitialize()
// --------------

function reinitialize()
{
  Debug.info("reinitialize()");

  ScriptProperties.deleteAllProperties();

  // Clear the triggers.  
  var triggers = ScriptApp.getProjectTriggers();

  for (var i = 0; i < triggers.length; i++)
    {
      ScriptApp.deleteTrigger(triggers[i]);
    }

  // Simulate a re-installation.
  onInstall();

} // reinitialize()

// resetFlubaroo()
// ---------------

function resetFlubaroo()
{
  logClear();
  reinitialize();
  deleteGradesSheet();

} // resetFlubaroo()

// deleteGradesSheet()
// -------------------

function deleteGradesSheet()
{  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = getSheetWithGrades(ss);

  if (sheet)
    {
      ss.setActiveSheet(sheet);
      ss.deleteActiveSheet();

      // To avoid a bug in which 'Grades' get deleted, but appears to
      // stick around, switch to another sheet after deleting it.
      // TODO_AJR: bug still exists sometimes.

      var switch_to_sheet = getSheetWithSubmissions(ss);
      ss.setActiveSheet(switch_to_sheet);
    }

} // deleteGradesSheet()

// toggleEmailSending()
// --------------------

function toggleEmailSending()
{
  if (ScriptProperties.getProperty(SCRIPT_PROP_SKIP_EMAIL))
    {
      ScriptProperties.deleteProperty(SCRIPT_PROP_SKIP_EMAIL);
    }
  else
    {
      ScriptProperties.setProperty(SCRIPT_PROP_SKIP_EMAIL, 'true');
    }

} // toggleEmailSending()

更新(2015年3月11日):我已经转移到使用BetterLog和我的own wrapper library for BetterLog自动将函数名称添加到调试跟踪(MqTFuiXcPtS5rVUZ_jC9Z4tnfWGfgtIUb)。

答案 1 :(得分:1)

不可能。根据它的执行方式,您最多可以访问上一次运行日志,它会在下一个脚本运行日志中丢失。 制作自己的记录器功能,例如在电子表格上执行appendRow。我做过一个甚至记录每个日志的完整堆栈跟踪,这比本机记录器更好。 这当然会让您记录罕见的事件,因为它会消耗更多的配额。 有关记录stacktrace等的示例代码,请参见此处(滚动到中间): http://plusfortrello.blogspot.com/2013/08/spent-for-trello-google-apps.html