CLI.js 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. 'use strict';
  2. process.env.PM2_USAGE = 'CLI';
  3. var cst = require('../../constants.js');
  4. var commander = require('commander');
  5. var chalk = require('chalk');
  6. var forEachLimit = require('async/forEachLimit');
  7. var debug = require('debug')('pm2:cli');
  8. var PM2 = require('../API.js');
  9. var pkg = require('../../package.json');
  10. var tabtab = require('../completion.js');
  11. var Common = require('../Common.js');
  12. var PM2ioHandler = require('../API/pm2-plus/PM2IO');
  13. Common.determineSilentCLI();
  14. Common.printVersion();
  15. var pm2 = new PM2();
  16. PM2ioHandler.usePM2Client(pm2)
  17. commander.version(pkg.version)
  18. .option('-v --version', 'print pm2 version')
  19. .option('-s --silent', 'hide all messages', false)
  20. .option('--ext <extensions>', 'watch only this file extensions')
  21. .option('-n --name <name>', 'set a name for the process in the process list')
  22. .option('-m --mini-list', 'display a compacted list without formatting')
  23. .option('--interpreter <interpreter>', 'set a specific interpreter to use for executing app, default: node')
  24. .option('--interpreter-args <arguments>', 'set arguments to pass to the interpreter (alias of --node-args)')
  25. .option('--node-args <node_args>', 'space delimited arguments to pass to node')
  26. .option('-o --output <path>', 'specify log file for stdout')
  27. .option('-e --error <path>', 'specify log file for stderr')
  28. .option('-l --log [path]', 'specify log file which gathers both stdout and stderr')
  29. .option('--filter-env [envs]', 'filter out outgoing global values that contain provided strings', function(v, m) { m.push(v); return m;}, [])
  30. .option('--log-type <type>', 'specify log output style (raw by default, json optional)')
  31. .option('--log-date-format <date format>', 'add custom prefix timestamp to logs')
  32. .option('--time', 'enable time logging')
  33. .option('--disable-logs', 'disable all logs storage')
  34. .option('--env <environment_name>', 'specify which set of environment variables from ecosystem file must be injected')
  35. .option('-a --update-env', 'force an update of the environment with restart/reload (-a <=> apply)')
  36. .option('-f --force', 'force actions')
  37. .option('-i --instances <number>', 'launch [number] instances (for networked app)(load balanced)')
  38. .option('--parallel <number>', 'number of parallel actions (for restart/reload)')
  39. .option('--shutdown-with-message', 'shutdown an application with process.send(\'shutdown\') instead of process.kill(pid, SIGINT)')
  40. .option('-p --pid <pid>', 'specify pid file')
  41. .option('-k --kill-timeout <delay>', 'delay before sending final SIGKILL signal to process')
  42. .option('--listen-timeout <delay>', 'listen timeout on application reload')
  43. .option('--max-memory-restart <memory>', 'Restart the app if an amount of memory is exceeded (in bytes)')
  44. .option('--restart-delay <delay>', 'specify a delay between restarts (in milliseconds)')
  45. .option('--exp-backoff-restart-delay <delay>', 'specify a delay between restarts (in milliseconds)')
  46. .option('-x --execute-command', 'execute a program using fork system')
  47. .option('--max-restarts [count]', 'only restart the script COUNT times')
  48. .option('-u --user <username>', 'define user when generating startup script')
  49. .option('--uid <uid>', 'run target script with <uid> rights')
  50. .option('--gid <gid>', 'run target script with <gid> rights')
  51. .option('--namespace <ns>', 'start application within specified namespace')
  52. .option('--cwd <path>', 'run target script from path <cwd>')
  53. .option('--hp <home path>', 'define home path when generating startup script')
  54. .option('--wait-ip', 'override systemd script to wait for full internet connectivity to launch pm2')
  55. .option('--service-name <name>', 'define service name when generating startup script')
  56. .option('-c --cron <cron_pattern>', 'restart a running process based on a cron pattern')
  57. .option('-c --cron-restart <cron_pattern>', '(alias) restart a running process based on a cron pattern')
  58. .option('-w --write', 'write configuration in local folder')
  59. .option('--no-daemon', 'run pm2 daemon in the foreground if it doesn\'t exist already')
  60. .option('--source-map-support', 'force source map support')
  61. .option('--only <application-name>', 'with json declaration, allow to only act on one application')
  62. .option('--disable-source-map-support', 'force source map support')
  63. .option('--wait-ready', 'ask pm2 to wait for ready event from your app')
  64. .option('--merge-logs', 'merge logs from different instances but keep error and out separated')
  65. .option('--watch [paths]', 'watch application folder for changes', function(v, m) { m.push(v); return m;}, [])
  66. .option('--ignore-watch <folders|files>', 'List of paths to ignore (name or regex)')
  67. .option('--watch-delay <delay>', 'specify a restart delay after changing files (--watch-delay 4 (in sec) or 4000ms)')
  68. .option('--no-color', 'skip colors')
  69. .option('--no-vizion', 'start an app without vizion feature (versioning control)')
  70. .option('--no-autorestart', 'start an app without automatic restart')
  71. .option('--no-treekill', 'Only kill the main process, not detached children')
  72. .option('--no-pmx', 'start an app without pmx')
  73. .option('--no-automation', 'start an app without pmx')
  74. .option('--trace', 'enable transaction tracing with km')
  75. .option('--disable-trace', 'disable transaction tracing with km')
  76. .option('--sort <field_name:sort>', 'sort process according to field\'s name')
  77. .option('--attach', 'attach logging after your start/restart/stop/reload')
  78. .option('--v8', 'enable v8 data collecting')
  79. .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx')
  80. .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)')
  81. .usage('[cmd] app');
  82. function displayUsage() {
  83. console.log('usage: pm2 [options] <command>')
  84. console.log('');
  85. console.log('pm2 -h, --help all available commands and options');
  86. console.log('pm2 examples display pm2 usage examples');
  87. console.log('pm2 <command> -h help on a specific command');
  88. console.log('');
  89. console.log('Access pm2 files in ~/.pm2');
  90. }
  91. function displayExamples() {
  92. console.log('- Start and add a process to the pm2 process list:')
  93. console.log('');
  94. console.log(chalk.cyan(' $ pm2 start app.js --name app'));
  95. console.log('');
  96. console.log('- Show the process list:');
  97. console.log('');
  98. console.log(chalk.cyan(' $ pm2 ls'));
  99. console.log('');
  100. console.log('- Stop and delete a process from the pm2 process list:');
  101. console.log('');
  102. console.log(chalk.cyan(' $ pm2 delete app'));
  103. console.log('');
  104. console.log('- Stop, start and restart a process from the process list:');
  105. console.log('');
  106. console.log(chalk.cyan(' $ pm2 stop app'));
  107. console.log(chalk.cyan(' $ pm2 start app'));
  108. console.log(chalk.cyan(' $ pm2 restart app'));
  109. console.log('');
  110. console.log('- Clusterize an app to all CPU cores available:');
  111. console.log('');
  112. console.log(chalk.cyan(' $ pm2 start -i max'));
  113. console.log('');
  114. console.log('- Update pm2 :');
  115. console.log('');
  116. console.log(chalk.cyan(' $ npm install pm2 -g && pm2 update'));
  117. console.log('');
  118. console.log('- Install pm2 auto completion:')
  119. console.log('');
  120. console.log(chalk.cyan(' $ pm2 completion install'))
  121. console.log('');
  122. console.log('Check the full documentation on https://pm2.keymetrics.io/');
  123. console.log('');
  124. }
  125. function beginCommandProcessing() {
  126. pm2.getVersion(function(err, remote_version) {
  127. if (!err && (pkg.version != remote_version)) {
  128. console.log('');
  129. console.log(chalk.red.bold('>>>> In-memory PM2 is out-of-date, do:\n>>>> $ pm2 update'));
  130. console.log('In memory PM2 version:', chalk.blue.bold(remote_version));
  131. console.log('Local PM2 version:', chalk.blue.bold(pkg.version));
  132. console.log('');
  133. }
  134. });
  135. commander.parse(process.argv);
  136. }
  137. function checkCompletion(){
  138. return tabtab.complete('pm2', function(err, data) {
  139. if(err || !data) return;
  140. if(/^--\w?/.test(data.last)) return tabtab.log(commander.options.map(function (data) {
  141. return data.long;
  142. }), data);
  143. if(/^-\w?/.test(data.last)) return tabtab.log(commander.options.map(function (data) {
  144. return data.short;
  145. }), data);
  146. // array containing commands after which process name should be listed
  147. var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show'];
  148. if (cmdProcess.indexOf(data.prev) > -1) {
  149. pm2.list(function(err, list){
  150. tabtab.log(list.map(function(el){ return el.name }), data);
  151. pm2.disconnect();
  152. });
  153. }
  154. else if (data.prev == 'pm2') {
  155. tabtab.log(commander.commands.map(function (data) {
  156. return data._name;
  157. }), data);
  158. pm2.disconnect();
  159. }
  160. else
  161. pm2.disconnect();
  162. });
  163. };
  164. var _arr = process.argv.indexOf('--') > -1 ? process.argv.slice(0, process.argv.indexOf('--')) : process.argv;
  165. if (_arr.indexOf('log') > -1) {
  166. process.argv[_arr.indexOf('log')] = 'logs';
  167. }
  168. if (_arr.indexOf('--no-daemon') > -1) {
  169. //
  170. // Start daemon if it does not exist
  171. //
  172. // Function checks if --no-daemon option is present,
  173. // and starts daemon in the same process if it does not exist
  174. //
  175. console.log('pm2 launched in no-daemon mode (you can add DEBUG="*" env variable to get more messages)');
  176. var pm2NoDaeamon = new PM2({
  177. daemon_mode : false
  178. });
  179. pm2NoDaeamon.connect(function() {
  180. pm2 = pm2NoDaeamon;
  181. beginCommandProcessing();
  182. });
  183. }
  184. else if (_arr.indexOf('startup') > -1 || _arr.indexOf('unstartup') > -1) {
  185. setTimeout(function() {
  186. commander.parse(process.argv);
  187. }, 100);
  188. }
  189. else {
  190. // HERE we instanciate the Client object
  191. pm2.connect(function() {
  192. debug('Now connected to daemon');
  193. if (process.argv.slice(2)[0] === 'completion') {
  194. checkCompletion();
  195. //Close client if completion related installation
  196. var third = process.argv.slice(3)[0];
  197. if ( third == null || third === 'install' || third === 'uninstall')
  198. pm2.disconnect();
  199. }
  200. else {
  201. beginCommandProcessing();
  202. }
  203. });
  204. }
  205. //
  206. // Helper function to fail when unknown command arguments are passed
  207. //
  208. function failOnUnknown(fn) {
  209. return function(arg) {
  210. if (arguments.length > 1) {
  211. console.log(cst.PREFIX_MSG + '\nUnknown command argument: ' + arg);
  212. commander.outputHelp();
  213. process.exit(cst.ERROR_EXIT);
  214. }
  215. return fn.apply(this, arguments);
  216. };
  217. }
  218. /**
  219. * @todo to remove at some point once it's fixed in official commander.js
  220. * https://github.com/tj/commander.js/issues/475
  221. *
  222. * Patch Commander.js Variadic feature
  223. */
  224. function patchCommanderArg(cmd) {
  225. var argsIndex;
  226. if ((argsIndex = commander.rawArgs.indexOf('--')) >= 0) {
  227. var optargs = commander.rawArgs.slice(argsIndex + 1);
  228. cmd = cmd.slice(0, cmd.indexOf(optargs[0]));
  229. }
  230. return cmd;
  231. }
  232. //
  233. // Start command
  234. //
  235. commander.command('start [name|namespace|file|ecosystem|id...]')
  236. .option('--watch', 'Watch folder for changes')
  237. .option('--fresh', 'Rebuild Dockerfile')
  238. .option('--daemon', 'Run container in Daemon mode (debug purposes)')
  239. .option('--container', 'Start application in container mode')
  240. .option('--dist', 'with --container; change local Dockerfile to containerize all files in current directory')
  241. .option('--image-name [name]', 'with --dist; set the exported image name')
  242. .option('--node-version [major]', 'with --container, set a specific major Node.js version')
  243. .option('--dockerdaemon', 'for debugging purpose')
  244. .description('start and daemonize an app')
  245. .action(function(cmd, opts) {
  246. if (opts.container == true && opts.dist == true)
  247. return pm2.dockerMode(cmd, opts, 'distribution');
  248. else if (opts.container == true)
  249. return pm2.dockerMode(cmd, opts, 'development');
  250. if (cmd == "-") {
  251. process.stdin.resume();
  252. process.stdin.setEncoding('utf8');
  253. process.stdin.on('data', function (cmd) {
  254. process.stdin.pause();
  255. pm2._startJson(cmd, commander, 'restartProcessId', 'pipe');
  256. });
  257. }
  258. else {
  259. // Commander.js patch
  260. cmd = patchCommanderArg(cmd);
  261. if (cmd.length === 0) {
  262. cmd = [cst.APP_CONF_DEFAULT_FILE];
  263. }
  264. let acc = []
  265. forEachLimit(cmd, 1, function(script, next) {
  266. pm2.start(script, commander, (err, apps) => {
  267. acc = acc.concat(apps)
  268. next(err)
  269. });
  270. }, function(err, dt) {
  271. if (err && err.message &&
  272. (err.message.includes('Script not found') === true ||
  273. err.message.includes('NOT AVAILABLE IN PATH') === true)) {
  274. pm2.exitCli(1)
  275. }
  276. else
  277. pm2.speedList(err ? 1 : 0, acc);
  278. });
  279. }
  280. });
  281. commander.command('trigger <id|proc_name|namespace|all> <action_name> [params]')
  282. .description('trigger process action')
  283. .action(function(pm_id, action_name, params) {
  284. pm2.trigger(pm_id, action_name, params);
  285. });
  286. commander.command('deploy <file|environment>')
  287. .description('deploy your json')
  288. .action(function(cmd) {
  289. pm2.deploy(cmd, commander);
  290. });
  291. commander.command('startOrRestart <json>')
  292. .description('start or restart JSON file')
  293. .action(function(file) {
  294. pm2._startJson(file, commander, 'restartProcessId');
  295. });
  296. commander.command('startOrReload <json>')
  297. .description('start or gracefully reload JSON file')
  298. .action(function(file) {
  299. pm2._startJson(file, commander, 'reloadProcessId');
  300. });
  301. commander.command('pid [app_name]')
  302. .description('return pid of [app_name] or all')
  303. .action(function(app) {
  304. pm2.getPID(app);
  305. });
  306. commander.command('create')
  307. .description('return pid of [app_name] or all')
  308. .action(function() {
  309. pm2.boilerplate()
  310. });
  311. commander.command('startOrGracefulReload <json>')
  312. .description('start or gracefully reload JSON file')
  313. .action(function(file) {
  314. pm2._startJson(file, commander, 'reloadProcessId');
  315. });
  316. //
  317. // Stop specific id
  318. //
  319. commander.command('stop <id|name|namespace|all|json|stdin...>')
  320. .option('--watch', 'Stop watching folder for changes')
  321. .description('stop a process')
  322. .action(function(param) {
  323. forEachLimit(param, 1, function(script, next) {
  324. pm2.stop(script, next);
  325. }, function(err) {
  326. pm2.speedList(err ? 1 : 0);
  327. });
  328. });
  329. //
  330. // Stop All processes
  331. //
  332. commander.command('restart <id|name|namespace|all|json|stdin...>')
  333. .option('--watch', 'Toggle watching folder for changes')
  334. .description('restart a process')
  335. .action(function(param) {
  336. // Commander.js patch
  337. param = patchCommanderArg(param);
  338. let acc = []
  339. forEachLimit(param, 1, function(script, next) {
  340. pm2.restart(script, commander, (err, apps) => {
  341. acc = acc.concat(apps)
  342. next(err)
  343. });
  344. }, function(err) {
  345. pm2.speedList(err ? 1 : 0, acc);
  346. });
  347. });
  348. //
  349. // Scale up/down a process in cluster mode
  350. //
  351. commander.command('scale <app_name> <number>')
  352. .description('scale up/down a process in cluster mode depending on total_number param')
  353. .action(function(app_name, number) {
  354. pm2.scale(app_name, number);
  355. });
  356. //
  357. // snapshot PM2
  358. //
  359. commander.command('profile:mem [time]')
  360. .description('Sample PM2 heap memory')
  361. .action(function(time) {
  362. pm2.profile('mem', time);
  363. });
  364. //
  365. // snapshot PM2
  366. //
  367. commander.command('profile:cpu [time]')
  368. .description('Profile PM2 cpu')
  369. .action(function(time) {
  370. pm2.profile('cpu', time);
  371. });
  372. //
  373. // Reload process(es)
  374. //
  375. commander.command('reload <id|name|namespace|all>')
  376. .description('reload processes (note that its for app using HTTP/HTTPS)')
  377. .action(function(pm2_id) {
  378. pm2.reload(pm2_id, commander);
  379. });
  380. commander.command('id <name>')
  381. .description('get process id by name')
  382. .action(function(name) {
  383. pm2.getProcessIdByName(name);
  384. });
  385. // Inspect a process
  386. commander.command('inspect <name>')
  387. .description('inspect a process')
  388. .action(function(cmd) {
  389. pm2.inspect(cmd, commander);
  390. });
  391. //
  392. // Stop and delete a process by name from database
  393. //
  394. commander.command('delete <name|id|namespace|script|all|json|stdin...>')
  395. .alias('del')
  396. .description('stop and delete a process from pm2 process list')
  397. .action(function(name) {
  398. if (name == "-") {
  399. process.stdin.resume();
  400. process.stdin.setEncoding('utf8');
  401. process.stdin.on('data', function (param) {
  402. process.stdin.pause();
  403. pm2.delete(param, 'pipe');
  404. });
  405. } else
  406. forEachLimit(name, 1, function(script, next) {
  407. pm2.delete(script,'', next);
  408. }, function(err) {
  409. pm2.speedList(err ? 1 : 0);
  410. });
  411. });
  412. //
  413. // Send system signal to process
  414. //
  415. commander.command('sendSignal <signal> <pm2_id|name>')
  416. .description('send a system signal to the target process')
  417. .action(function(signal, pm2_id) {
  418. if (isNaN(parseInt(pm2_id))) {
  419. console.log(cst.PREFIX_MSG + 'Sending signal to process name ' + pm2_id);
  420. pm2.sendSignalToProcessName(signal, pm2_id);
  421. } else {
  422. console.log(cst.PREFIX_MSG + 'Sending signal to process id ' + pm2_id);
  423. pm2.sendSignalToProcessId(signal, pm2_id);
  424. }
  425. });
  426. //
  427. // Stop and delete a process by name from database
  428. //
  429. commander.command('ping')
  430. .description('ping pm2 daemon - if not up it will launch it')
  431. .action(function() {
  432. pm2.ping();
  433. });
  434. commander.command('updatePM2')
  435. .description('update in-memory PM2 with local PM2')
  436. .action(function() {
  437. pm2.update();
  438. });
  439. commander.command('update')
  440. .description('(alias) update in-memory PM2 with local PM2')
  441. .action(function() {
  442. pm2.update();
  443. });
  444. /**
  445. * Module specifics
  446. */
  447. commander.command('install <module|git:// url>')
  448. .alias('module:install')
  449. .option('--tarball', 'is local tarball')
  450. .option('--install', 'run yarn install before starting module')
  451. .option('--docker', 'is docker container')
  452. .option('--v1', 'install module in v1 manner (do not use it)')
  453. .option('--safe [time]', 'keep module backup, if new module fail = restore with previous')
  454. .description('install or update a module and run it forever')
  455. .action(function(plugin_name, opts) {
  456. require('util')._extend(commander, opts);
  457. pm2.install(plugin_name, commander);
  458. });
  459. commander.command('module:update <module|git:// url>')
  460. .description('update a module and run it forever')
  461. .action(function(plugin_name) {
  462. pm2.install(plugin_name);
  463. });
  464. commander.command('module:generate [app_name]')
  465. .description('Generate a sample module in current folder')
  466. .action(function(app_name) {
  467. pm2.generateModuleSample(app_name);
  468. });
  469. commander.command('uninstall <module>')
  470. .alias('module:uninstall')
  471. .description('stop and uninstall a module')
  472. .action(function(plugin_name) {
  473. pm2.uninstall(plugin_name);
  474. });
  475. commander.command('package [target]')
  476. .description('Check & Package TAR type module')
  477. .action(function(target) {
  478. pm2.package(target);
  479. });
  480. commander.command('publish [folder]')
  481. .option('--npm', 'publish on npm')
  482. .alias('module:publish')
  483. .description('Publish the module you are currently on')
  484. .action(function(folder, opts) {
  485. pm2.publish(folder, opts);
  486. });
  487. commander.command('set [key] [value]')
  488. .description('sets the specified config <key> <value>')
  489. .action(function(key, value) {
  490. pm2.set(key, value);
  491. });
  492. commander.command('multiset <value>')
  493. .description('multiset eg "key1 val1 key2 val2')
  494. .action(function(str) {
  495. pm2.multiset(str);
  496. });
  497. commander.command('get [key]')
  498. .description('get value for <key>')
  499. .action(function(key) {
  500. pm2.get(key);
  501. });
  502. commander.command('conf [key] [value]')
  503. .description('get / set module config values')
  504. .action(function(key, value) {
  505. pm2.get()
  506. });
  507. commander.command('config <key> [value]')
  508. .description('get / set module config values')
  509. .action(function(key, value) {
  510. pm2.conf(key, value);
  511. });
  512. commander.command('unset <key>')
  513. .description('clears the specified config <key>')
  514. .action(function(key) {
  515. pm2.unset(key);
  516. });
  517. commander.command('report')
  518. .description('give a full pm2 report for https://github.com/Unitech/pm2/issues')
  519. .action(function(key) {
  520. pm2.report();
  521. });
  522. //
  523. // PM2 I/O
  524. //
  525. commander.command('link [secret] [public] [name]')
  526. .option('--info-node [url]', 'set url info node')
  527. .description('link with the pm2 monitoring dashboard')
  528. .action(pm2.linkManagement.bind(pm2));
  529. commander.command('unlink')
  530. .description('unlink with the pm2 monitoring dashboard')
  531. .action(function() {
  532. pm2.unlink();
  533. });
  534. commander.command('monitor [name]')
  535. .description('monitor target process')
  536. .action(function(name) {
  537. if (name === undefined) {
  538. return plusHandler()
  539. }
  540. pm2.monitorState('monitor', name);
  541. });
  542. commander.command('unmonitor [name]')
  543. .description('unmonitor target process')
  544. .action(function(name) {
  545. pm2.monitorState('unmonitor', name);
  546. });
  547. commander.command('open')
  548. .description('open the pm2 monitoring dashboard')
  549. .action(function(name) {
  550. pm2.openDashboard();
  551. });
  552. function plusHandler (command, opts) {
  553. if (opts && opts.infoNode) {
  554. process.env.KEYMETRICS_NODE = opts.infoNode
  555. }
  556. return PM2ioHandler.launch(command, opts)
  557. }
  558. commander.command('plus [command] [option]')
  559. .alias('register')
  560. .option('--info-node [url]', 'set url info node for on-premise pm2 plus')
  561. .option('-d --discrete', 'silent mode')
  562. .option('-a --install-all', 'install all modules (force yes)')
  563. .description('enable pm2 plus')
  564. .action(plusHandler);
  565. commander.command('login')
  566. .description('Login to pm2 plus')
  567. .action(function() {
  568. return plusHandler('login')
  569. });
  570. commander.command('logout')
  571. .description('Logout from pm2 plus')
  572. .action(function() {
  573. return plusHandler('logout')
  574. });
  575. //
  576. // Save processes to file
  577. //
  578. commander.command('dump')
  579. .alias('save')
  580. .option('--force', 'force deletion of dump file, even if empty')
  581. .description('dump all processes for resurrecting them later')
  582. .action(failOnUnknown(function(opts) {
  583. pm2.dump(commander.force)
  584. }));
  585. //
  586. // Delete dump file
  587. //
  588. commander.command('cleardump')
  589. .description('Create empty dump file')
  590. .action(failOnUnknown(function() {
  591. pm2.clearDump();
  592. }));
  593. //
  594. // Save processes to file
  595. //
  596. commander.command('send <pm_id> <line>')
  597. .description('send stdin to <pm_id>')
  598. .action(function(pm_id, line) {
  599. pm2.sendLineToStdin(pm_id, line);
  600. });
  601. //
  602. // Attach to stdin/stdout
  603. // Not TTY ready
  604. //
  605. commander.command('attach <pm_id> [command separator]')
  606. .description('attach stdin/stdout to application identified by <pm_id>')
  607. .action(function(pm_id, separator) {
  608. pm2.attach(pm_id, separator);
  609. });
  610. //
  611. // Resurrect
  612. //
  613. commander.command('resurrect')
  614. .description('resurrect previously dumped processes')
  615. .action(failOnUnknown(function() {
  616. console.log(cst.PREFIX_MSG + 'Resurrecting');
  617. pm2.resurrect();
  618. }));
  619. //
  620. // Set pm2 to startup
  621. //
  622. commander.command('unstartup [platform]')
  623. .description('disable the pm2 startup hook')
  624. .action(function(platform) {
  625. pm2.uninstallStartup(platform, commander);
  626. });
  627. //
  628. // Set pm2 to startup
  629. //
  630. commander.command('startup [platform]')
  631. .description('enable the pm2 startup hook')
  632. .action(function(platform) {
  633. pm2.startup(platform, commander);
  634. });
  635. //
  636. // Logrotate
  637. //
  638. commander.command('logrotate')
  639. .description('copy default logrotate configuration')
  640. .action(function(cmd) {
  641. pm2.logrotate(commander);
  642. });
  643. //
  644. // Sample generate
  645. //
  646. commander.command('ecosystem [mode]')
  647. .alias('init')
  648. .description('generate a process conf file. (mode = null or simple)')
  649. .action(function(mode) {
  650. pm2.generateSample(mode);
  651. });
  652. commander.command('reset <name|id|all>')
  653. .description('reset counters for process')
  654. .action(function(proc_id) {
  655. pm2.reset(proc_id);
  656. });
  657. commander.command('describe <name|id>')
  658. .description('describe all parameters of a process')
  659. .action(function(proc_id) {
  660. pm2.describe(proc_id);
  661. });
  662. commander.command('desc <name|id>')
  663. .description('(alias) describe all parameters of a process')
  664. .action(function(proc_id) {
  665. pm2.describe(proc_id);
  666. });
  667. commander.command('info <name|id>')
  668. .description('(alias) describe all parameters of a process')
  669. .action(function(proc_id) {
  670. pm2.describe(proc_id);
  671. });
  672. commander.command('show <name|id>')
  673. .description('(alias) describe all parameters of a process')
  674. .action(function(proc_id) {
  675. pm2.describe(proc_id);
  676. });
  677. commander.command('env <id>')
  678. .description('list all environment variables of a process id')
  679. .action(function(proc_id) {
  680. pm2.env(proc_id);
  681. });
  682. //
  683. // List command
  684. //
  685. commander
  686. .command('list')
  687. .alias('ls')
  688. .description('list all processes')
  689. .action(function() {
  690. pm2.list(commander)
  691. });
  692. commander.command('l')
  693. .description('(alias) list all processes')
  694. .action(function() {
  695. pm2.list()
  696. });
  697. commander.command('ps')
  698. .description('(alias) list all processes')
  699. .action(function() {
  700. pm2.list()
  701. });
  702. commander.command('status')
  703. .description('(alias) list all processes')
  704. .action(function() {
  705. pm2.list()
  706. });
  707. // List in raw json
  708. commander.command('jlist')
  709. .description('list all processes in JSON format')
  710. .action(function() {
  711. pm2.jlist()
  712. });
  713. commander.command('sysmonit')
  714. .description('start system monitoring daemon')
  715. .action(function() {
  716. pm2.launchSysMonitoring()
  717. })
  718. commander.command('slist')
  719. .alias('sysinfos')
  720. .option('-t --tree', 'show as tree')
  721. .description('list system infos in JSON')
  722. .action(function(opts) {
  723. pm2.slist(opts.tree)
  724. })
  725. // List in prettified Json
  726. commander.command('prettylist')
  727. .description('print json in a prettified JSON')
  728. .action(failOnUnknown(function() {
  729. pm2.jlist(true);
  730. }));
  731. //
  732. // Dashboard command
  733. //
  734. commander.command('monit')
  735. .description('launch termcaps monitoring')
  736. .action(function() {
  737. pm2.dashboard();
  738. });
  739. commander.command('imonit')
  740. .description('launch legacy termcaps monitoring')
  741. .action(function() {
  742. pm2.monit();
  743. });
  744. commander.command('dashboard')
  745. .alias('dash')
  746. .description('launch dashboard with monitoring and logs')
  747. .action(function() {
  748. pm2.dashboard();
  749. });
  750. //
  751. // Flushing command
  752. //
  753. commander.command('flush [api]')
  754. .description('flush logs')
  755. .action(function(api) {
  756. pm2.flush(api);
  757. });
  758. /* old version
  759. commander.command('flush')
  760. .description('flush logs')
  761. .action(failOnUnknown(function() {
  762. pm2.flush();
  763. }));
  764. */
  765. //
  766. // Reload all logs
  767. //
  768. commander.command('reloadLogs')
  769. .description('reload all logs')
  770. .action(function() {
  771. pm2.reloadLogs();
  772. });
  773. //
  774. // Log streaming
  775. //
  776. commander.command('logs [id|name|namespace]')
  777. .option('--json', 'json log output')
  778. .option('--format', 'formated log output')
  779. .option('--raw', 'raw output')
  780. .option('--err', 'only shows error output')
  781. .option('--out', 'only shows standard output')
  782. .option('--lines <n>', 'output the last N lines, instead of the last 15 by default')
  783. .option('--timestamp [format]', 'add timestamps (default format YYYY-MM-DD-HH:mm:ss)')
  784. .option('--nostream', 'print logs without lauching the log stream')
  785. .option('--highlight [value]', 'highlights the given value')
  786. .description('stream logs file. Default stream all logs')
  787. .action(function(id, cmd) {
  788. var Logs = require('../API/Log.js');
  789. if (!id) id = 'all';
  790. var line = 15;
  791. var raw = false;
  792. var exclusive = false;
  793. var timestamp = false;
  794. var highlight = false;
  795. if(!isNaN(parseInt(cmd.lines))) {
  796. line = parseInt(cmd.lines);
  797. }
  798. if (cmd.parent.rawArgs.indexOf('--raw') !== -1)
  799. raw = true;
  800. if (cmd.timestamp)
  801. timestamp = typeof cmd.timestamp === 'string' ? cmd.timestamp : 'YYYY-MM-DD-HH:mm:ss';
  802. if (cmd.highlight)
  803. highlight = typeof cmd.highlight === 'string' ? cmd.highlight : false;
  804. if (cmd.out === true)
  805. exclusive = 'out';
  806. if (cmd.err === true)
  807. exclusive = 'err';
  808. if (cmd.nostream === true)
  809. pm2.printLogs(id, line, raw, timestamp, exclusive);
  810. else if (cmd.json === true)
  811. Logs.jsonStream(pm2.Client, id);
  812. else if (cmd.format === true)
  813. Logs.formatStream(pm2.Client, id, false, 'YYYY-MM-DD-HH:mm:ssZZ', exclusive, highlight);
  814. else
  815. pm2.streamLogs(id, line, raw, timestamp, exclusive, highlight);
  816. });
  817. //
  818. // Kill
  819. //
  820. commander.command('kill')
  821. .description('kill daemon')
  822. .action(failOnUnknown(function(arg) {
  823. pm2.killDaemon(function() {
  824. process.exit(cst.SUCCESS_EXIT);
  825. });
  826. }));
  827. //
  828. // Update repository for a given app
  829. //
  830. commander.command('pull <name> [commit_id]')
  831. .description('updates repository for a given app')
  832. .action(function(pm2_name, commit_id) {
  833. if (commit_id !== undefined) {
  834. pm2._pullCommitId({
  835. pm2_name: pm2_name,
  836. commit_id: commit_id
  837. });
  838. }
  839. else
  840. pm2.pullAndRestart(pm2_name);
  841. });
  842. //
  843. // Update repository to the next commit for a given app
  844. //
  845. commander.command('forward <name>')
  846. .description('updates repository to the next commit for a given app')
  847. .action(function(pm2_name) {
  848. pm2.forward(pm2_name);
  849. });
  850. //
  851. // Downgrade repository to the previous commit for a given app
  852. //
  853. commander.command('backward <name>')
  854. .description('downgrades repository to the previous commit for a given app')
  855. .action(function(pm2_name) {
  856. pm2.backward(pm2_name);
  857. });
  858. //
  859. // Perform a deep update of PM2
  860. //
  861. commander.command('deepUpdate')
  862. .description('performs a deep update of PM2')
  863. .action(function() {
  864. pm2.deepUpdate();
  865. });
  866. //
  867. // Launch a http server that expose a given path on given port
  868. //
  869. commander.command('serve [path] [port]')
  870. .alias('expose')
  871. .option('--port [port]', 'specify port to listen to')
  872. .option('--spa', 'always serving index.html on inexistant sub path')
  873. .option('--basic-auth-username [username]', 'set basic auth username')
  874. .option('--basic-auth-password [password]', 'set basic auth password')
  875. .option('--monitor [frontend-app]', 'frontend app monitoring (auto integrate snippet on html files)')
  876. .description('serve a directory over http via port')
  877. .action(function (path, port, cmd) {
  878. pm2.serve(path, port || cmd.port, cmd, commander);
  879. });
  880. commander.command('autoinstall')
  881. .action(function() {
  882. pm2.autoinstall()
  883. })
  884. commander.command('examples')
  885. .description('display pm2 usage examples')
  886. .action(() => {
  887. console.log(cst.PREFIX_MSG + chalk.grey('pm2 usage examples:\n'));
  888. displayExamples();
  889. process.exit(cst.SUCCESS_EXIT);
  890. })
  891. //
  892. // Catch all
  893. //
  894. commander.command('*')
  895. .action(function() {
  896. console.log(cst.PREFIX_MSG_ERR + chalk.bold('Command not found\n'));
  897. displayUsage();
  898. // Check if it does not forget to close fds from RPC
  899. process.exit(cst.ERROR_EXIT);
  900. });
  901. //
  902. // Display help if 0 arguments passed to pm2
  903. //
  904. if (process.argv.length == 2) {
  905. commander.parse(process.argv);
  906. displayUsage();
  907. // Check if it does not forget to close fds from RPC
  908. process.exit(cst.ERROR_EXIT);
  909. }