)]}'
{"version":3,"sources":["logging/logging.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mB;AACA,yC;AACA,E;;AAEA,e;AACA,kB;AACA,0B;AACA,iB;;AAEA,iE;AACA,kE;AACA,sB;AACA,mC;AACA,qB;AACA,E;;AAEA,sE;AACA,mE;AACA,kC;AACA,kC;AACA,oB;AACA,E;;AAEA,8D;AACA,gC;AACA,+B;AACA,wB;AACA,gB;AACA,e;AACA,E;;AAEA,mC;AACA,E;AACA,8E;AACA,wE;AACA,gC;AACA,E;AACA,yE;AACA,2E;AACA,0D;AACA,0B;;AAEA,oB;AACA,iB;AACA,oC;AACA,kB;AACA,c;AACA,E;;AAEA,wB;;AAEA,c;AACA,sE;AACA,uE;;AAEA,gE;;AAEA,mC;AACA,4B;;AAEA,6D;AACA,wB;;AAEA,2D;AACA,wB;AACA,U;AACA,4E;AACA,yE;AACA,kC;AACA,uB;AACA,G;AACA,E;;AAEA,oD;AACA,qC;AACA,8B;AACA,gF;AACA,4E;AACA,kE;AACA,wB;AACA,0B;AACA,iB;AACA,I;;AAEA,yB;;AAEA,wB;;AAEA,gC;;AAEA,kE;AACA,gC;AACA,W;AACA,0C;AACA,oB;AACA,2C;AACA,4B;AACA,K;;AAEA,oE;AACA,Y;AACA,G;;AAEA,mB;;AAEA,4D;AACA,4E;AACA,0D;AACA,mE;AACA,a;AACA,mB;AACA,kD;AACA,wC;;AAEA,uE;AACA,oE;AACA,2B;AACA,gE;;AAEA,iB;AACA,E;;AAEA,6D;AACA,+B;AACA,+B;AACA,mB;AACA,iB;AACA,a;AACA,K;;AAEA,4B;AACA,oB;AACA,kB;AACA,yB;AACA,K;;AAEA,wE;AACA,2D;;AAEA,4C;AACA,mB;AACA,kE;AACA,O;;AAEA,0D;AACA,6E;AACA,+B;AACA,mD;AACA,0B;AACA,sB;;AAEA,4D;AACA,0B;AACA,a;;AAEA,sB;AACA,kD;AACA,iC;AACA,gD;AACA,oD;AACA,+C;AACA,0C;AACA,c;AACA,8E;AACA,O;AACA,Y;AACA,wB;AACA,K;AACA,I;AACA,G;;AAEA,sF;AACA,6B;AACA,iB;AACA,qF;AACA,iD;AACA,G;;AAEA,uD;AACA,oD;AACA,e;AACA,M;AACA,gB;AACA,E;;AAEA,oE;AACA,sC;AACA,sD;AACA,0B;;AAEA,sB;AACA,8B;AACA,oD;AACA,oC;;AAEA,gE;AACA,kC;AACA,sB;AACA,4B;AACA,8B;AACA,gC;AACA,kC;AACA,kC;AACA,gC;AACA,gC;;AAEA,wC;AACA,oB;AACA,K;;AAEA,wB;AACA,gC;AACA,oC;AACA,G;;AAEA,qE;AACA,4E;;AAEA,iD;AACA,2C;AACA,yB;AACA,yC;AACA,a;AACA,iC;AACA,a;AACA,iC;AACA,a;AACA,qC;;AAEA,oD;AACA,0E;;AAEA,mB;AACA,kC;AACA,yE;AACA,8C;;AAEA,2B;AACA,6C;AACA,uC;AACA,mD;AACA,+C;AACA,gD;;AAEA,gB;AACA,iD;;AAEA,kD;;AAEA,oB;AACA,kC;AACA,c;AACA,Q;AACA,c;AACA,iB;AACA,6B;AACA,Y;AACA,e;AACA,8B;;AAEA,yC;AACA,wD;AACA,mD;AACA,I;;AAEA,gE;AACA,2C;AACA,E;;AAEA,8C;AACA,uB;AACA,2B;AACA,6C;AACA,gF;AACA,iC;AACA,E","file":"/packages/logging.js","sourcesContent":["Log = function () {\n  return Log.info.apply(this, arguments);\n};\n\n/// FOR TESTING\nvar intercept = 0;\nvar interceptedLines = [];\nvar suppress = 0;\n\n// Intercept the next 'count' calls to a Log function. The actual\n// lines printed to the console can be cleared and read by calling\n// Log._intercepted().\nLog._intercept = function (count) {\n  intercept += count;\n};\n\n// Suppress the next 'count' calls to a Log function. Use this to stop\n// tests from spamming the console, especially with red errors that\n// might look like a failing test.\nLog._suppress = function (count) {\n  suppress += count;\n};\n\n// Returns intercepted lines and resets the intercept counter.\nLog._intercepted = function () {\n  var lines = interceptedLines;\n  interceptedLines = [];\n  intercept = 0;\n  return lines;\n};\n\n// Either 'json' or 'colored-text'.\n//\n// When this is set to 'json', print JSON documents that are parsed by another\n// process ('satellite' or 'meteor run'). This other process should call\n// 'Log.format' for nice output.\n//\n// When this is set to 'colored-text', call 'Log.format' before printing.\n// This should be used for logging from within satellite, since there is no\n// other process that will be reading its standard output.\nLog.outputFormat = 'json';\n\nvar LEVEL_COLORS = {\n  debug: 'green',\n  // leave info as the default color\n  warn: 'magenta',\n  error: 'red'\n};\n\nvar META_COLOR = 'blue';\n\n// XXX package\nvar RESTRICTED_KEYS = ['time', 'timeInexact', 'level', 'file', 'line',\n                        'program', 'originApp', 'satellite', 'stderr'];\n\nvar FORMATTED_KEYS = RESTRICTED_KEYS.concat(['app', 'message']);\n\nvar logInBrowser = function (obj) {\n  var str = Log.format(obj);\n\n  // XXX Some levels should be probably be sent to the server\n  var level = obj.level;\n\n  if ((typeof console !== 'undefined') && console[level]) {\n    console[level](str);\n  } else {\n    // XXX Uses of Meteor._debug should probably be replaced by Log.debug or\n    //     Log.info, and we should have another name for \"do your best to\n    //     call call console.log\".\n    Meteor._debug(str);\n  }\n};\n\n// @returns {Object: { line: Number, file: String }}\nLog._getCallerDetails = function () {\n  var getStack = function () {\n    // We do NOT use Error.prepareStackTrace here (a V8 extension that gets us a\n    // pre-parsed stack) since it's impossible to compose it with the use of\n    // Error.prepareStackTrace used on the server for source maps.\n    var err = new Error;\n    var stack = err.stack;\n    return stack;\n  };\n\n  var stack = getStack();\n\n  if (!stack) return {};\n\n  var lines = stack.split('\\n');\n\n  // looking for the first line outside the logging package (or an\n  // eval if we find that first)\n  var line;\n  for (var i = 1; i < lines.length; ++i) {\n    line = lines[i];\n    if (line.match(/^\\s*at eval \\(eval/)) {\n      return {file: \"eval\"};\n    }\n\n    if (!line.match(/packages\\/(?:local-test:)?logging(?:\\/|\\.js)/))\n      break;\n  }\n\n  var details = {};\n\n  // The format for FF is 'functionName@filePath:lineNumber'\n  // The format for V8 is 'functionName (packages/logging/logging.js:81)' or\n  //                      'packages/logging/logging.js:81'\n  var match = /(?:[@(]| at )([^(]+?):([0-9:]+)(?:\\)|$)/.exec(line);\n  if (!match)\n    return details;\n  // in case the matched block here is line:column\n  details.line = match[2].split(':')[0];\n\n  // Possible format: https://foo.bar.com/scripts/file.js?random=foobar\n  // XXX: if you can write the following in better way, please do it\n  // XXX: what about evals?\n  details.file = match[1].split('/').slice(-1)[0].split('?')[0];\n\n  return details;\n};\n\n_.each(['debug', 'info', 'warn', 'error'], function (level) {\n  // @param arg {String|Object}\n  Log[level] = function (arg) {\n    if (suppress) {\n      suppress--;\n      return;\n    }\n\n    var intercepted = false;\n    if (intercept) {\n      intercept--;\n      intercepted = true;\n    }\n\n    var obj = (_.isObject(arg) && !_.isRegExp(arg) && !_.isDate(arg) ) ?\n              arg : {message: new String(arg).toString() };\n\n    _.each(RESTRICTED_KEYS, function (key) {\n      if (obj[key])\n        throw new Error(\"Can't set '\" + key + \"' in log message\");\n    });\n\n    if (_.has(obj, 'message') && !_.isString(obj.message))\n      throw new Error(\"The 'message' field in log objects must be a string\");\n    if (!obj.omitCallerDetails)\n      obj = _.extend(Log._getCallerDetails(), obj);\n    obj.time = new Date();\n    obj.level = level;\n\n    // XXX allow you to enable 'debug', probably per-package\n    if (level === 'debug')\n      return;\n\n    if (intercepted) {\n      interceptedLines.push(EJSON.stringify(obj));\n    } else if (Meteor.isServer) {\n      if (Log.outputFormat === 'colored-text') {\n        console.log(Log.format(obj, {color: true}));\n      } else if (Log.outputFormat === 'json') {\n        console.log(EJSON.stringify(obj));\n      } else {\n        throw new Error(\"Unknown logging output format: \" + Log.outputFormat);\n      }\n    } else {\n      logInBrowser(obj);\n    }\n  };\n});\n\n// tries to parse line as EJSON. returns object if parse is successful, or null if not\nLog.parse = function (line) {\n  var obj = null;\n  if (line && line.charAt(0) === '{') { // might be json generated from calling 'Log'\n    try { obj = EJSON.parse(line); } catch (e) {}\n  }\n\n  // XXX should probably check fields other than 'time'\n  if (obj && obj.time && (obj.time instanceof Date))\n    return obj;\n  else\n    return null;\n};\n\n// formats a log object into colored human and machine-readable text\nLog.format = function (obj, options) {\n  obj = EJSON.clone(obj); // don't mutate the argument\n  options = options || {};\n\n  var time = obj.time;\n  if (!(time instanceof Date))\n    throw new Error(\"'time' must be a Date object\");\n  var timeInexact = obj.timeInexact;\n\n  // store fields that are in FORMATTED_KEYS since we strip them\n  var level = obj.level || 'info';\n  var file = obj.file;\n  var lineNumber = obj.line;\n  var appName = obj.app || '';\n  var originApp = obj.originApp;\n  var message = obj.message || '';\n  var program = obj.program || '';\n  var satellite = obj.satellite;\n  var stderr = obj.stderr || '';\n\n  _.each(FORMATTED_KEYS, function(key) {\n    delete obj[key];\n  });\n\n  if (!_.isEmpty(obj)) {\n    if (message) message += \" \";\n    message += EJSON.stringify(obj);\n  }\n\n  var pad2 = function(n) { return n < 10 ? '0' + n : n.toString(); };\n  var pad3 = function(n) { return n < 100 ? '0' + pad2(n) : n.toString(); };\n\n  var dateStamp = time.getFullYear().toString() +\n    pad2(time.getMonth() + 1 /*0-based*/) +\n    pad2(time.getDate());\n  var timeStamp = pad2(time.getHours()) +\n        ':' +\n        pad2(time.getMinutes()) +\n        ':' +\n        pad2(time.getSeconds()) +\n        '.' +\n        pad3(time.getMilliseconds());\n\n  // eg in San Francisco in June this will be '(-7)'\n  var utcOffsetStr = '(' + (-(new Date().getTimezoneOffset() / 60)) + ')';\n\n  var appInfo = '';\n  if (appName) appInfo += appName;\n  if (originApp && originApp !== appName) appInfo += ' via ' + originApp;\n  if (appInfo) appInfo = '[' + appInfo + '] ';\n\n  var sourceInfoParts = [];\n  if (program) sourceInfoParts.push(program);\n  if (file) sourceInfoParts.push(file);\n  if (lineNumber) sourceInfoParts.push(lineNumber);\n  var sourceInfo = _.isEmpty(sourceInfoParts) ?\n    '' : '(' + sourceInfoParts.join(':') + ') ';\n\n  if (satellite)\n    sourceInfo += ['[', satellite, ']'].join('');\n\n  var stderrIndicator = stderr ? '(STDERR) ' : '';\n\n  var metaPrefix = [\n    level.charAt(0).toUpperCase(),\n    dateStamp,\n    '-',\n    timeStamp,\n    utcOffsetStr,\n    timeInexact ? '? ' : ' ',\n    appInfo,\n    sourceInfo,\n    stderrIndicator].join('');\n\n  var prettify = function (line, color) {\n    return (options.color && Meteor.isServer && color) ?\n      Npm.require('cli-color')[color](line) : line;\n  };\n\n  return prettify(metaPrefix, options.metaColor || META_COLOR) +\n    prettify(message, LEVEL_COLORS[level]);\n};\n\n// Turn a line of text into a loggable object.\n// @param line {String}\n// @param override {Object}\nLog.objFromText = function (line, override) {\n  var obj = {message: line, level: \"info\", time: new Date(), timeInexact: true};\n  return _.extend(obj, override);\n};\n"]}