mirror of
https://github.com/Unitech/pm2.git
synced 2025-12-08 20:35:53 +00:00
feature: merge std(out && err)
This commit is contained in:
parent
aae6ffe938
commit
0c6c089f4f
@ -83,6 +83,8 @@ CLI.start = function(script, opts, cb) {
|
||||
appConf.max_memory_restart = opts.maxMemoryRestart;
|
||||
if (opts.instances)
|
||||
appConf['instances'] = opts.instances;
|
||||
if (opts.log)
|
||||
appConf['log_file'] = opts.log;
|
||||
if (opts.error)
|
||||
appConf['error_file'] = opts.error;
|
||||
if (opts.output)
|
||||
|
||||
@ -79,6 +79,9 @@ UX.describeTable = function(process) {
|
||||
{ 'uptime' : (pm2_env.pm_uptime && pm2_env.status == 'online') ? timeSince(pm2_env.pm_uptime) : 0 },
|
||||
{ 'created at' : created_at }
|
||||
);
|
||||
if('pm_log_path' in pm2_env){
|
||||
table.splice(6, 0, {'entire log path': pm2_env.pm_log_path});
|
||||
}
|
||||
console.log(table.toString());
|
||||
|
||||
if (pm2_env.versioning) {
|
||||
|
||||
@ -103,12 +103,17 @@ Common.resolveAppPaths = function(app, cwd, outputter) {
|
||||
if (fs.existsSync(app.pm_exec_path) == false) {
|
||||
return new Error('script not found : ' + app.pm_exec_path);
|
||||
}
|
||||
if (app.log_file){
|
||||
app["pm_log_path"] = typeof app.log_file == 'boolean' ?
|
||||
path.resolve(cst.DEFAULT_LOG_PATH, [formated_app_name, '.log'].join(''))
|
||||
: path.resolve(cwd, app.log_file);
|
||||
}
|
||||
delete app.log_file;
|
||||
|
||||
if (app.out_file)
|
||||
app["pm_out_log_path"] = path.resolve(cwd, app.out_file);
|
||||
else {
|
||||
app["pm_out_log_path"] = path.resolve(cst.DEFAULT_LOG_PATH, [formated_app_name, '-out.log'].join(''));
|
||||
app.out_file = app["pm_out_log_path"];
|
||||
}
|
||||
delete app.out_file;
|
||||
|
||||
@ -116,7 +121,6 @@ Common.resolveAppPaths = function(app, cwd, outputter) {
|
||||
app["pm_err_log_path"] = path.resolve(cwd, app.error_file);
|
||||
else {
|
||||
app["pm_err_log_path"] = path.resolve(cst.DEFAULT_LOG_PATH, [formated_app_name, '-err.log'].join(''));
|
||||
app.error_file = app["pm_err_log_path"];
|
||||
}
|
||||
delete app.error_file;
|
||||
|
||||
|
||||
@ -121,8 +121,10 @@ God.executeApp = function executeApp(env, cb) {
|
||||
|
||||
// If merge option, dont separate the logs
|
||||
if (!env_copy['merge_logs']) {
|
||||
env_copy.pm_out_log_path = env_copy.pm_out_log_path.replace(/-[0-9]+\.log$|\.log$/g, '-' + env_copy['pm_id'] + '.log');
|
||||
env_copy.pm_err_log_path = env_copy.pm_err_log_path.replace(/-[0-9]+\.log$|\.log$/g, '-' + env_copy['pm_id'] + '.log');
|
||||
['', '_out', '_err'].forEach(function(k){
|
||||
var key = 'pm' + k + '_log_path';
|
||||
env_copy[key] && (env_copy[key] = env_copy[key].replace(/-[0-9]+\.log$|\.log$/g, '-' + env_copy['pm_id'] + '.log'));
|
||||
})
|
||||
}
|
||||
|
||||
// Initiate watch file
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
var log = require('debug')('pm2:god');
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
var cst = require('../../constants.js');
|
||||
var moment = require('moment');
|
||||
var Common = require('../Common');
|
||||
@ -63,10 +64,15 @@ module.exports = function ForkMode(God) {
|
||||
args = args.concat(eval((pm2_env.args)));
|
||||
}
|
||||
|
||||
|
||||
var stdout, stderr;
|
||||
var outFile = pm2_env.pm_out_log_path;
|
||||
var errFile = pm2_env.pm_err_log_path;
|
||||
// piping stream o file
|
||||
var stds = {
|
||||
out: pm2_env.pm_out_log_path,
|
||||
err: pm2_env.pm_err_log_path
|
||||
};
|
||||
// entire log std if necessary.
|
||||
if('pm_log_path' in pm2_env){
|
||||
stds.std = pm2_env.pm_log_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
@ -75,24 +81,44 @@ module.exports = function ForkMode(God) {
|
||||
* @return
|
||||
*/
|
||||
function startLogging(cb) {
|
||||
stdout = fs.createWriteStream(outFile, { flags : 'a' });
|
||||
|
||||
stdout.on('error', function(e) {
|
||||
God.logAndGenerateError(e);
|
||||
return cb(e);
|
||||
// waterfall.
|
||||
var flows = [];
|
||||
// types of stdio, should be sorted as `std(entire log)`, `out`, `err`.
|
||||
var types = Object.keys(stds).sort(function(x, y){
|
||||
return -x.charCodeAt(0) + y.charCodeAt(0);
|
||||
});
|
||||
|
||||
stdout.on('open', function() {
|
||||
stderr = fs.createWriteStream(errFile, { flags : 'a' });
|
||||
// Create write streams.
|
||||
(function createWS(io){
|
||||
if(io.length != 1){
|
||||
return;
|
||||
}
|
||||
io = io[0];
|
||||
|
||||
stderr.on('error', function(e) {
|
||||
God.logAndGenerateError(e);
|
||||
return cb(e);
|
||||
});
|
||||
// If `std` is a Stream type, try next `std`.
|
||||
// compatible with `pm2 reloadLogs`
|
||||
if(typeof stds[io] == 'object' && !isNaN(stds[io].fd)){
|
||||
return createWS(types.splice(0, 1));
|
||||
}
|
||||
|
||||
stderr.on('open', function() {
|
||||
return cb(null);
|
||||
flows.push(function(next){
|
||||
var file = stds[io];
|
||||
stds[io] = fs.createWriteStream(file, {flags: 'a'})
|
||||
.on('error', function(e){
|
||||
next(e);
|
||||
}).on('open', function(){
|
||||
next();
|
||||
});
|
||||
stds[io]._file = file;
|
||||
});
|
||||
createWS(types.splice(0, 1));
|
||||
})(types.splice(0, 1));
|
||||
|
||||
async.waterfall(flows, function(err, result){
|
||||
if(err){
|
||||
God.logAndGenerateError(err);
|
||||
}
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
|
||||
@ -125,7 +151,8 @@ module.exports = function ForkMode(God) {
|
||||
if (pm2_env.log_date_format)
|
||||
log_data = moment().format(pm2_env.log_date_format) + ': ' + log_data;
|
||||
|
||||
stderr.write(log_data);
|
||||
stds.err.write(log_data);
|
||||
stds.std && stds.std.write(log_data);
|
||||
|
||||
God.bus.emit('log:err', {
|
||||
process : Common.formatCLU(cspr),
|
||||
@ -142,7 +169,8 @@ module.exports = function ForkMode(God) {
|
||||
if (pm2_env.log_date_format)
|
||||
log_data = moment().format(pm2_env.log_date_format) + ': ' + log_data;
|
||||
|
||||
stdout.write(log_data);
|
||||
stds.out.write(log_data);
|
||||
stds.std && stds.std.write(log_data);
|
||||
|
||||
God.bus.emit('log:out', {
|
||||
process : Common.formatCLU(cspr),
|
||||
@ -177,14 +205,18 @@ module.exports = function ForkMode(God) {
|
||||
|
||||
cspr.once('close', function forkClose(status) {
|
||||
try {
|
||||
stderr.close();
|
||||
stdout.close();
|
||||
for(var k in stds){
|
||||
stds[k].close();
|
||||
stds[k] = stds[k]._file;
|
||||
}
|
||||
} catch(e) { God.logAndGenerateError(e);}
|
||||
});
|
||||
|
||||
cspr._reloadLogs = function(cb) {
|
||||
stdout.close();
|
||||
stderr.close();
|
||||
for(var k in stds){
|
||||
stds[k].close();
|
||||
stds[k] = stds[k]._file;
|
||||
}
|
||||
startLogging(cb);
|
||||
};
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ if (process.env.name != null)
|
||||
|
||||
var fs = require('fs');
|
||||
var p = require('path');
|
||||
var async = require('async');
|
||||
var cst = require('../constants');
|
||||
var axm = require('axm');
|
||||
/**
|
||||
@ -18,6 +19,7 @@ var axm = require('axm');
|
||||
var fs = require('fs');
|
||||
var worker = require('cluster').worker;
|
||||
|
||||
var stdFile = process.env.pm_log_path;
|
||||
var outFile = process.env.pm_out_log_path;
|
||||
var errFile = process.env.pm_err_log_path;
|
||||
var pmId = process.env.pm_id;
|
||||
@ -41,8 +43,13 @@ var axm = require('axm');
|
||||
if (process.env.args != null)
|
||||
process.argv = process.argv.concat(eval(process.env.args));
|
||||
|
||||
|
||||
exec(script, outFile, errFile);
|
||||
// stdio, including: out, err and entire (both out and err if necessary).
|
||||
var stds = {
|
||||
out: outFile,
|
||||
err: errFile
|
||||
};
|
||||
stdFile && (stds.std = stdFile);
|
||||
exec(script, stds);
|
||||
|
||||
if (cronRestart)
|
||||
cronize(cronRestart);
|
||||
@ -78,21 +85,20 @@ function cronize(cron_pattern) {
|
||||
* Description
|
||||
* @method exec
|
||||
* @param {} script
|
||||
* @param {} outFile
|
||||
* @param {} errFile
|
||||
* @param {} stds
|
||||
* @return
|
||||
*/
|
||||
function exec(script, outFile, errFile) {
|
||||
var stderr, stdout;
|
||||
|
||||
function exec(script, stds) {
|
||||
if (p.extname(script) == '.coffee') {
|
||||
require('coffee-script/register');
|
||||
}
|
||||
|
||||
process.on('message', function (msg) {
|
||||
if (msg.type === 'log:reload') {
|
||||
stdout.end();
|
||||
stderr.end();
|
||||
for(var k in stds){
|
||||
stds[k].close();
|
||||
stds[k] = stds[k]._file;
|
||||
}
|
||||
startLogging(function () {
|
||||
console.log('Reloading log...');
|
||||
});
|
||||
@ -112,53 +118,91 @@ function exec(script, outFile, errFile) {
|
||||
* @return
|
||||
*/
|
||||
function startLogging(callback) {
|
||||
stdout = fs.createWriteStream(outFile, { flags : 'a' });
|
||||
|
||||
stdout.on('open', function() {
|
||||
stderr = fs.createWriteStream(errFile, { flags : 'a' });
|
||||
stderr.on('open', function() {
|
||||
|
||||
process.stderr.write = (function(write) {
|
||||
return function(string, encoding, fd) {
|
||||
var log_data = string.toString();
|
||||
if (process.env.log_date_format && moment)
|
||||
log_data = moment().format(process.env.log_date_format) + ': ' + log_data;
|
||||
stderr.write(log_data);
|
||||
process.send({
|
||||
type : 'log:err',
|
||||
data : string
|
||||
});
|
||||
};
|
||||
}
|
||||
)(process.stderr.write);
|
||||
|
||||
process.stdout.write = (function(write) {
|
||||
return function(string, encoding, fd) {
|
||||
var log_data = string.toString();
|
||||
if (process.env.log_date_format && moment)
|
||||
log_data = moment().format(process.env.log_date_format) + ': ' + log_data;
|
||||
stdout.write(log_data);
|
||||
process.send({
|
||||
type : 'log:out',
|
||||
data : string
|
||||
});
|
||||
};
|
||||
})(process.stdout.write);
|
||||
return callback();
|
||||
});
|
||||
// waterfall.
|
||||
var flows = [];
|
||||
// types of stdio, should be sorted as `std(entire log)`, `out`, `err`.
|
||||
var types = Object.keys(stds).sort(function(x, y){
|
||||
return -x.charCodeAt(0) + y.charCodeAt(0);
|
||||
});
|
||||
|
||||
// Create write streams.
|
||||
(function createWS(io){
|
||||
if(io.length != 1){
|
||||
return;
|
||||
}
|
||||
io = io[0];
|
||||
|
||||
// If `std` is a Stream type, try next `std`.
|
||||
// compatible with `pm2 reloadLogs`
|
||||
if(typeof stds[io] == 'object' && !isNaN(stds[io].fd)){
|
||||
return createWS(types.splice(0, 1));
|
||||
}
|
||||
|
||||
flows.push(function(next){
|
||||
var file = stds[io];
|
||||
stds[io] = fs.createWriteStream(file, {flags: 'a'})
|
||||
.on('error', function(e){
|
||||
next(e);
|
||||
}).on('open', function(){
|
||||
next();
|
||||
});
|
||||
stds[io]._file = file;
|
||||
});
|
||||
createWS(types.splice(0, 1));
|
||||
})(types.splice(0, 1));
|
||||
|
||||
async.waterfall(flows, callback);
|
||||
}
|
||||
|
||||
startLogging(function () {
|
||||
startLogging(function (err) {
|
||||
if(err){
|
||||
process.send({
|
||||
type : 'process:exception',
|
||||
data : {
|
||||
message: err.message,
|
||||
syscall: 'ProcessContainer.startLogging'
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
process.stderr.write = (function(write) {
|
||||
return function(string, encoding, fd) {
|
||||
var log_data = string.toString();
|
||||
if (process.env.log_date_format && moment)
|
||||
log_data = moment().format(process.env.log_date_format) + ': ' + log_data;
|
||||
stds.err.write(log_data);
|
||||
stds.std && stds.std.write(log_data);
|
||||
process.send({
|
||||
type : 'log:err',
|
||||
data : string
|
||||
});
|
||||
};
|
||||
}
|
||||
)(process.stderr.write);
|
||||
|
||||
process.stdout.write = (function(write) {
|
||||
return function(string, encoding, fd) {
|
||||
var log_data = string.toString();
|
||||
if (process.env.log_date_format && moment)
|
||||
log_data = moment().format(process.env.log_date_format) + ': ' + log_data;
|
||||
stds.out.write(log_data);
|
||||
stds.std && stds.std.write(log_data);
|
||||
process.send({
|
||||
type : 'log:out',
|
||||
data : string
|
||||
});
|
||||
};
|
||||
})(process.stdout.write);
|
||||
|
||||
process.on('uncaughtException', function uncaughtListener(err) {
|
||||
try {
|
||||
stderr.write(err.stack);
|
||||
} catch(e) {
|
||||
function logError(types, error){
|
||||
try {
|
||||
stderr.write(err.toString());
|
||||
} catch(e) {}
|
||||
types.forEach(function(type){
|
||||
stds[type].write(error + '\n');
|
||||
});
|
||||
} catch(e) { }
|
||||
}
|
||||
logError(['std', 'err'], err.stack);
|
||||
|
||||
// Notify master that an uncaughtException has been catched
|
||||
try {
|
||||
@ -174,9 +218,7 @@ function exec(script, outFile, errFile) {
|
||||
data : errObj
|
||||
});
|
||||
} catch(e) {
|
||||
try {
|
||||
stderr.write('Channel is already closed can\'t broadcast error', err);
|
||||
} catch(e) {}
|
||||
logError(['std', 'err'], 'Channel is already closed can\'t broadcast error:\n' + e.stack);
|
||||
}
|
||||
|
||||
if (!process.listeners('uncaughtException').filter(function (listener) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user