mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
223 lines
6.6 KiB
JavaScript
223 lines
6.6 KiB
JavaScript
var _ = require('underscore');
|
|
var isopackets = require("./isopackets.js");
|
|
var Console = require('./console.js').Console;
|
|
|
|
// runLog is primarily used by the parts of the tool which run apps locally. It
|
|
// writes to standard output (and standard error, if rawLogs is set), and allows
|
|
// special output forms like "write this line, but let the next line overwrite
|
|
// it". It also makes its output available to the proxy, to be displayed to web
|
|
// browsers if the app fails to run.
|
|
//
|
|
// It's not the only mechanism used for gathering messages! buildmessage is a
|
|
// more structured way of gathering messages, but unlike log, it does not print
|
|
// messages immediately.
|
|
//
|
|
// Some other parts of the code (eg commands and warehouse) write directly to
|
|
// process.std{out,err} or to console.log; we should be careful to not do that
|
|
// anywhere that may overlap with use of runLog.
|
|
|
|
|
|
var getLoggingPackage = function () {
|
|
var Log = isopackets.load('logging').logging.Log;
|
|
|
|
// Since no other process will be listening to stdout and parsing it,
|
|
// print directly in the same format as log messages from other apps
|
|
Log.outputFormat = 'colored-text';
|
|
|
|
return Log;
|
|
};
|
|
|
|
var RunLog = function () {
|
|
var self = this;
|
|
|
|
self.rawLogs = false;
|
|
|
|
self.messages = []; // list of log objects
|
|
self.maxLength = 100;
|
|
|
|
// If non-null, the last thing logged was "server restarted"
|
|
// message, and the value will be the number of consecutive such
|
|
// messages that have been logged with no other intervening messages
|
|
self.consecutiveRestartMessages = null;
|
|
self.consecutiveClientRestartMessages = null;
|
|
|
|
// If non-null, the last thing that was logged was a temporary
|
|
// message (with a carriage return but no newline), and this is its
|
|
// length.
|
|
self.temporaryMessageLength = null;
|
|
};
|
|
|
|
_.extend(RunLog.prototype, {
|
|
_record: function (msg) {
|
|
var self = this;
|
|
|
|
self.messages.push(msg);
|
|
if (self.messages.length > self.maxLength) {
|
|
self.messages.shift();
|
|
}
|
|
},
|
|
|
|
_clearSpecial: function () {
|
|
var self = this;
|
|
|
|
if (self.consecutiveRestartMessages) {
|
|
self.consecutiveRestartMessages = null;
|
|
Console.info();
|
|
}
|
|
|
|
if (self.consecutiveClientRestartMessages) {
|
|
self.consecutiveClientRestartMessages = null;
|
|
Console.info();
|
|
}
|
|
|
|
if (self.temporaryMessageLength) {
|
|
var spaces = new Array(self.temporaryMessageLength + 1).join(' ');
|
|
process.stdout.write(spaces + '\r');
|
|
self.temporaryMessageLength = null;
|
|
}
|
|
},
|
|
|
|
setRawLogs: function (rawLogs) {
|
|
this.rawLogs = !!rawLogs;
|
|
},
|
|
|
|
logAppOutput: function (line, isStderr) {
|
|
var self = this;
|
|
|
|
var Log = getLoggingPackage();
|
|
|
|
var obj = (isStderr ?
|
|
Log.objFromText(line, { level: 'warn', stderr: true }) :
|
|
Log.parse(line) || Log.objFromText(line));
|
|
self._record(obj);
|
|
|
|
self._clearSpecial();
|
|
if (self.rawLogs)
|
|
Console[isStderr ? "rawError" : "rawInfo"](line + "\n");
|
|
else
|
|
Console.rawInfo(Log.format(obj, { color: true }) + "\n");
|
|
|
|
// XXX deal with test server logging differently?!
|
|
},
|
|
|
|
// Log the message.
|
|
// msg: message
|
|
// options:
|
|
// - arrow: if true, preface with => and wrap accordingly.
|
|
log: function (msg, options) {
|
|
var self = this;
|
|
options = options || {};
|
|
var obj = {
|
|
time: new Date,
|
|
message: msg
|
|
// in the future, might want to add something else to
|
|
// distinguish messages from runner from message from the app,
|
|
// but for now, nothing would use it, so we'll keep it simple
|
|
};
|
|
self._record(obj);
|
|
|
|
self._clearSpecial();
|
|
|
|
// Process the options. By default, we want to wordwrap the message with
|
|
// Console.info. If we ask for raw output, then we don't want to do that. If
|
|
// we ask for an arrow, we want to wrap around with => as the bulletPoint.
|
|
Console[options.arrow ? 'arrowInfo' : 'info'](msg);
|
|
},
|
|
|
|
// Write a message to the terminal that will get overwritten by the
|
|
// next message logged. (Don't put it in the log that getLog
|
|
// returns.)
|
|
// XXX Maybe this should return an object that you have to pass to the
|
|
// subsequent log call, and only such a log call will overwrite it (and an
|
|
// intervening log call will cause this to stay on the screen)?
|
|
// eg, a log call from the updater can interweave with the logTemporary
|
|
// calls in run-all.js
|
|
logTemporary: function (msg) {
|
|
var self = this;
|
|
|
|
self._clearSpecial();
|
|
process.stdout.write(msg + "\r");
|
|
self.temporaryMessageLength = msg.length;
|
|
},
|
|
|
|
logRestart: function () {
|
|
var self = this;
|
|
|
|
if (self.consecutiveRestartMessages) {
|
|
// replace old message in place. this assumes that the new restart message
|
|
// is not shorter than the old one.
|
|
process.stdout.write("\r");
|
|
self.messages.pop();
|
|
self.consecutiveRestartMessages ++;
|
|
} else {
|
|
self._clearSpecial();
|
|
self.consecutiveRestartMessages = 1;
|
|
}
|
|
|
|
var message = "=> Meteor server restarted";
|
|
if (self.consecutiveRestartMessages > 1)
|
|
message += " (x" + self.consecutiveRestartMessages + ")";
|
|
// no newline, so that we can overwrite it if we get another
|
|
// restart message right after this one
|
|
process.stdout.write(message);
|
|
|
|
self._record({
|
|
time: new Date,
|
|
message: message
|
|
});
|
|
},
|
|
|
|
logClientRestart: function () {
|
|
var self = this;
|
|
|
|
if (self.consecutiveClientRestartMessages) {
|
|
// replace old message in place. this assumes that the new restart message
|
|
// is not shorter than the old one.
|
|
process.stdout.write("\r");
|
|
self.messages.pop();
|
|
self.consecutiveClientRestartMessages ++;
|
|
} else {
|
|
self._clearSpecial();
|
|
self.consecutiveClientRestartMessages = 1;
|
|
}
|
|
|
|
var message = "=> Client modified -- refreshing";
|
|
if (self.consecutiveClientRestartMessages > 1)
|
|
message += " (x" + self.consecutiveClientRestartMessages + ")";
|
|
// no newline, so that we can overwrite it if we get another
|
|
// restart message right after this one
|
|
process.stdout.write(message);
|
|
|
|
self._record({
|
|
time: new Date,
|
|
message: message
|
|
});
|
|
},
|
|
|
|
finish: function () {
|
|
var self = this;
|
|
|
|
self._clearSpecial();
|
|
},
|
|
|
|
clearLog: function () {
|
|
var self = this;
|
|
self.messages = [];
|
|
},
|
|
|
|
getLog: function () {
|
|
var self = this;
|
|
return self.messages;
|
|
}
|
|
});
|
|
|
|
// Create a singleton instance of RunLog. Expose its public methods on the
|
|
// object you get with require('./run-log.js').
|
|
var runLogInstance = new RunLog;
|
|
_.each(
|
|
['log', 'logTemporary', 'logRestart', 'logClientRestart', 'logAppOutput',
|
|
'setRawLogs', 'finish', 'clearLog', 'getLog'],
|
|
function (method) {
|
|
exports[method] = _.bind(runLogInstance[method], runLogInstance);
|
|
});
|