Saturday, May 19, 2012

Logger and Log Level in Google Apps Script

If you have become used to some finer control for logging, you may not be very satisfied with the one in Apps Script.

To fix it, you only need a few lines of code:

this.log = function(/*level, args*/) {
    var args = Array.prototype.slice.call(arguments),
    level = args.shift();
    if (this.level >= level) {
      this.logger.log([new Date(), level].concat(args.map(function(o, i, a) {
         return Utilities.jsonStringify(o); })).join(this.delimiter));
    }
    return this;
};

For convenience, we may add some additional functions:

  var levels = ['', 'fatal', 'error', 'warn', 'info', 'debug', 'trace'];
  for (var i = 1; i < levels.length; i++) {
    this[levels[i]] = (function() {
      var args = Array.prototype.slice.call(arguments);
      return function() {
        return this.log.apply(this, args.concat(Array.prototype.slice.call(arguments)));
      };
    }(i));
  }

Here is the complete sample.

Sunday, May 13, 2012

Cache 101 with Google Apps Script

If you have used the cache service long enough in your Google Apps Script, you probably have known you could not cache anything larger than 100KB.

If you are absolutely certain the values you are going to cache will not hit that magic number, you will be fine; but what if there is a chance your value could be 100 + 1? You can always check the size before you put, but that would be cumbersome and your code would be messy.

Here is a simple ready-to-use wrapper which hides the complexity and still performs equally well for size under 100KB.

It uses the first byte as an indicator: 'v' or 'k'. If the size is less than (100KB -1), it stores the data value; otherwise it chunks the data and stores the auto assigned keys as the value for the given key. The generated keys consist of the given key appended with a running number.

In addition, the wrapper automatically does the conversion between JSON object and string text, so you may store object instead.

To simplify the interface, you specify a creator function in place of a value. i.e.

cache.get(key, creator);

If the value exists in cache, it returns immediately; otherwise the creator function will be called.

Sample