LogManagement.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. var chalk = require('chalk');
  2. var util = require('util');
  3. var fs = require('fs');
  4. var exec = require('child_process').exec;
  5. var path = require('path');
  6. var Log = require('./Log');
  7. var cst = require('../../constants.js');
  8. var Common = require('../Common.js');
  9. module.exports = function(CLI) {
  10. /**
  11. * Description
  12. * @method flush
  13. * @return
  14. */
  15. CLI.prototype.flush = function(api, cb) {
  16. var that = this;
  17. if (!api) {
  18. Common.printOut(cst.PREFIX_MSG + 'Flushing ' + cst.PM2_LOG_FILE_PATH);
  19. fs.closeSync(fs.openSync(cst.PM2_LOG_FILE_PATH, 'w'));
  20. }
  21. that.Client.executeRemote('getMonitorData', {}, function(err, list) {
  22. if (err) {
  23. Common.printError(err);
  24. return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
  25. }
  26. list.forEach(function(l) {
  27. if (typeof api == 'undefined') {
  28. Common.printOut(cst.PREFIX_MSG + 'Flushing:');
  29. Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
  30. Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
  31. if (l.pm2_env.pm_log_path) {
  32. Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_log_path);
  33. fs.closeSync(fs.openSync(l.pm2_env.pm_log_path, 'w'));
  34. }
  35. fs.closeSync(fs.openSync(l.pm2_env.pm_out_log_path, 'w'));
  36. fs.closeSync(fs.openSync(l.pm2_env.pm_err_log_path, 'w'));
  37. }
  38. else if (l.pm2_env.name === api) {
  39. Common.printOut(cst.PREFIX_MSG + 'Flushing:');
  40. Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
  41. Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
  42. if (l.pm2_env.pm_log_path &&
  43. l.pm2_env.pm_log_path.lastIndexOf('/') < l.pm2_env.pm_log_path.lastIndexOf(api)) {
  44. Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_log_path);
  45. fs.closeSync(fs.openSync(l.pm2_env.pm_log_path, 'w'));
  46. }
  47. if (l.pm2_env.pm_out_log_path.lastIndexOf('/') < l.pm2_env.pm_out_log_path.lastIndexOf(api))
  48. fs.closeSync(fs.openSync(l.pm2_env.pm_out_log_path, 'w'));
  49. if (l.pm2_env.pm_err_log_path.lastIndexOf('/') < l.pm2_env.pm_err_log_path.lastIndexOf(api))
  50. fs.closeSync(fs.openSync(l.pm2_env.pm_err_log_path, 'w'));
  51. }
  52. });
  53. Common.printOut(cst.PREFIX_MSG + 'Logs flushed');
  54. return cb ? cb(null, list) : that.exitCli(cst.SUCCESS_EXIT);
  55. });
  56. };
  57. CLI.prototype.logrotate = function(opts, cb) {
  58. var that = this;
  59. if (process.getuid() != 0) {
  60. return exec('whoami', function(err, stdout, stderr) {
  61. Common.printError(cst.PREFIX_MSG + 'You have to run this command as root. Execute the following command:');
  62. Common.printError(cst.PREFIX_MSG + chalk.grey(' sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' pm2 logrotate -u ' + stdout.trim()));
  63. cb ? cb(Common.retErr('You have to run this with elevated rights')) : that.exitCli(cst.ERROR_EXIT);
  64. });
  65. }
  66. if (!fs.existsSync('/etc/logrotate.d')) {
  67. Common.printError(cst.PREFIX_MSG + '/etc/logrotate.d does not exist we can not copy the default configuration.');
  68. return cb ? cb(Common.retErr('/etc/logrotate.d does not exist')) : that.exitCli(cst.ERROR_EXIT);
  69. }
  70. var templatePath = path.join(cst.TEMPLATE_FOLDER, cst.LOGROTATE_SCRIPT);
  71. Common.printOut(cst.PREFIX_MSG + 'Getting logrorate template ' + templatePath);
  72. var script = fs.readFileSync(templatePath, {encoding: 'utf8'});
  73. var user = opts.user || 'root';
  74. script = script.replace(/%HOME_PATH%/g, cst.PM2_ROOT_PATH)
  75. .replace(/%USER%/g, user);
  76. try {
  77. fs.writeFileSync('/etc/logrotate.d/pm2-'+user, script);
  78. } catch (e) {
  79. console.error(e.stack || e);
  80. }
  81. Common.printOut(cst.PREFIX_MSG + 'Logrotate configuration added to /etc/logrotate.d/pm2');
  82. return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
  83. };
  84. /**
  85. * Description
  86. * @method reloadLogs
  87. * @return
  88. */
  89. CLI.prototype.reloadLogs = function(cb) {
  90. var that = this;
  91. Common.printOut('Reloading all logs...');
  92. that.Client.executeRemote('reloadLogs', {}, function(err, logs) {
  93. if (err) {
  94. Common.printError(err);
  95. return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
  96. }
  97. Common.printOut('All logs reloaded');
  98. return cb ? cb(null, logs) : that.exitCli(cst.SUCCESS_EXIT);
  99. });
  100. };
  101. /**
  102. * Description
  103. * @method streamLogs
  104. * @param {String} id
  105. * @param {Number} lines
  106. * @param {Boolean} raw
  107. * @return
  108. */
  109. CLI.prototype.streamLogs = function(id, lines, raw, timestamp, exclusive, highlight) {
  110. var that = this;
  111. var files_list = [];
  112. // If no argument is given, we stream logs for all running apps
  113. id = id || 'all';
  114. lines = lines !== undefined ? lines : 20;
  115. lines = lines < 0 ? -(lines) : lines;
  116. // Avoid duplicates and check if path is different from '/dev/null'
  117. var pushIfUnique = function(entry) {
  118. var exists = false;
  119. if (entry.path.toLowerCase
  120. && entry.path.toLowerCase() !== '/dev/null') {
  121. files_list.some(function(file) {
  122. if (file.path === entry.path)
  123. exists = true;
  124. return exists;
  125. });
  126. if (exists)
  127. return;
  128. files_list.push(entry);
  129. }
  130. }
  131. // Get the list of all running apps
  132. that.Client.executeRemote('getMonitorData', {}, function(err, list) {
  133. var regexList = [];
  134. var namespaceList = [];
  135. if (err) {
  136. Common.printError(err);
  137. that.exitCli(cst.ERROR_EXIT);
  138. }
  139. if (lines === 0)
  140. return Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
  141. Common.printOut(chalk.bold.grey(util.format.call(this, '[TAILING] Tailing last %d lines for [%s] process%s (change the value with --lines option)', lines, id, id === 'all' ? 'es' : '')));
  142. // Populate the array `files_list` with the paths of all files we need to tail
  143. list.forEach(function(proc) {
  144. if (proc.pm2_env && (id === 'all' ||
  145. proc.pm2_env.name == id ||
  146. proc.pm2_env.pm_id == id)) {
  147. if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
  148. pushIfUnique({
  149. path : proc.pm2_env.pm_out_log_path,
  150. app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  151. type : 'out'});
  152. if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
  153. pushIfUnique({
  154. path : proc.pm2_env.pm_err_log_path,
  155. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  156. type : 'err'
  157. });
  158. } else if(proc.pm2_env && proc.pm2_env.namespace == id) {
  159. if(namespaceList.indexOf(proc.pm2_env.name) === -1) {
  160. namespaceList.push(proc.pm2_env.name)
  161. }
  162. if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
  163. pushIfUnique({
  164. path : proc.pm2_env.pm_out_log_path,
  165. app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  166. type : 'out'});
  167. if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
  168. pushIfUnique({
  169. path : proc.pm2_env.pm_err_log_path,
  170. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  171. type : 'err'
  172. });
  173. }
  174. // Populate the array `files_list` with the paths of all files we need to tail, when log in put is a regex
  175. else if(proc.pm2_env && (isNaN(id) && id[0] === '/' && id[id.length - 1] === '/')) {
  176. var regex = new RegExp(id.replace(/\//g, ''));
  177. if(regex.test(proc.pm2_env.name)) {
  178. if(regexList.indexOf(proc.pm2_env.name) === -1) {
  179. regexList.push(proc.pm2_env.name);
  180. }
  181. if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
  182. pushIfUnique({
  183. path : proc.pm2_env.pm_out_log_path,
  184. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  185. type : 'out'});
  186. if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
  187. pushIfUnique({
  188. path : proc.pm2_env.pm_err_log_path,
  189. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  190. type : 'err'
  191. });
  192. }
  193. }
  194. });
  195. //for fixing issue https://github.com/Unitech/pm2/issues/3506
  196. /* if (files_list && files_list.length == 0) {
  197. Common.printError(cst.PREFIX_MSG_ERR + 'No file to stream for app [%s], exiting.', id);
  198. return process.exit(cst.ERROR_EXIT);
  199. }*/
  200. if (!raw && (id === 'all' || id === 'PM2') && exclusive === false) {
  201. Log.tail([{
  202. path : cst.PM2_LOG_FILE_PATH,
  203. app_name : 'PM2',
  204. type : 'PM2'
  205. }], lines, raw, function() {
  206. Log.tail(files_list, lines, raw, function() {
  207. Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
  208. });
  209. });
  210. }
  211. else {
  212. Log.tail(files_list, lines, raw, function() {
  213. if(regexList.length > 0) {
  214. regexList.forEach(function(id) {
  215. Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
  216. })
  217. }
  218. else if(namespaceList.length > 0) {
  219. namespaceList.forEach(function(id) {
  220. Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
  221. })
  222. }
  223. else {
  224. Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
  225. }
  226. });
  227. }
  228. });
  229. };
  230. /**
  231. * Description
  232. * @method printLogs
  233. * @param {String} id
  234. * @param {Number} lines
  235. * @param {Boolean} raw
  236. * @return
  237. */
  238. CLI.prototype.printLogs = function(id, lines, raw, timestamp, exclusive) {
  239. var that = this;
  240. var files_list = [];
  241. // If no argument is given, we stream logs for all running apps
  242. id = id || 'all';
  243. lines = lines !== undefined ? lines : 20;
  244. lines = lines < 0 ? -(lines) : lines;
  245. // Avoid duplicates and check if path is different from '/dev/null'
  246. var pushIfUnique = function(entry) {
  247. var exists = false;
  248. if (entry.path.toLowerCase
  249. && entry.path.toLowerCase() !== '/dev/null') {
  250. files_list.some(function(file) {
  251. if (file.path === entry.path)
  252. exists = true;
  253. return exists;
  254. });
  255. if (exists)
  256. return;
  257. files_list.push(entry);
  258. }
  259. }
  260. // Get the list of all running apps
  261. that.Client.executeRemote('getMonitorData', {}, function(err, list) {
  262. if (err) {
  263. Common.printError(err);
  264. that.exitCli(cst.ERROR_EXIT);
  265. }
  266. if (lines <= 0) {
  267. return that.exitCli(cst.SUCCESS_EXIT)
  268. }
  269. Common.printOut(chalk.bold.grey(util.format.call(this, '[TAILING] Tailing last %d lines for [%s] process%s (change the value with --lines option)', lines, id, id === 'all' ? 'es' : '')));
  270. // Populate the array `files_list` with the paths of all files we need to tail
  271. list.forEach(function(proc) {
  272. if (proc.pm2_env && (id === 'all' ||
  273. proc.pm2_env.name == id ||
  274. proc.pm2_env.pm_id == id)) {
  275. if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
  276. pushIfUnique({
  277. path : proc.pm2_env.pm_out_log_path,
  278. app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  279. type : 'out'});
  280. if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
  281. pushIfUnique({
  282. path : proc.pm2_env.pm_err_log_path,
  283. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  284. type : 'err'
  285. });
  286. }
  287. // Populate the array `files_list` with the paths of all files we need to tail, when log in put is a regex
  288. else if(proc.pm2_env && (isNaN(id) && id[0] === '/' && id[id.length - 1] === '/')) {
  289. var regex = new RegExp(id.replace(/\//g, ''));
  290. if(regex.test(proc.pm2_env.name)) {
  291. if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
  292. pushIfUnique({
  293. path : proc.pm2_env.pm_out_log_path,
  294. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  295. type : 'out'});
  296. if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
  297. pushIfUnique({
  298. path : proc.pm2_env.pm_err_log_path,
  299. app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
  300. type : 'err'
  301. });
  302. }
  303. }
  304. });
  305. if (!raw && (id === 'all' || id === 'PM2') && exclusive === false) {
  306. Log.tail([{
  307. path : cst.PM2_LOG_FILE_PATH,
  308. app_name : 'PM2',
  309. type : 'PM2'
  310. }], lines, raw, function() {
  311. Log.tail(files_list, lines, raw, function() {
  312. that.exitCli(cst.SUCCESS_EXIT);
  313. });
  314. });
  315. }
  316. else {
  317. Log.tail(files_list, lines, raw, function() {
  318. that.exitCli(cst.SUCCESS_EXIT);
  319. });
  320. }
  321. });
  322. };
  323. };