Monit.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /**
  2. * Copyright 2013-2022 the PM2 project authors. All rights reserved.
  3. * Use of this source code is governed by a license that
  4. * can be found in the LICENSE file.
  5. */
  6. // pm2-htop
  7. // Library who interacts with PM2 to display processes resources in htop way
  8. // by Strzelewicz Alexandre
  9. var multimeter = require('pm2-multimeter');
  10. var os = require('os');
  11. var p = require('path');
  12. var chalk = require('chalk');
  13. var UX = require('./UX');
  14. var debug = require('debug')('pm2:monit');
  15. // Cst for light programs
  16. const RATIO_T1 = Math.floor(os.totalmem() / 500);
  17. // Cst for medium programs
  18. const RATIO_T2 = Math.floor(os.totalmem() / 50);
  19. // Cst for heavy programs
  20. const RATIO_T3 = Math.floor(os.totalmem() / 5);
  21. // Cst for heavy programs
  22. const RATIO_T4 = Math.floor(os.totalmem());
  23. var Monit = {};
  24. //helper to get bars.length (num bars printed)
  25. Object.size = function(obj) {
  26. var size = 0, key;
  27. for (key in obj) {
  28. if (obj.hasOwnProperty(key)) size++;
  29. }
  30. return size;
  31. };
  32. /**
  33. * Reset the monitor through charm, basically \033c
  34. * @param String msg optional message to show
  35. * @return Monit
  36. */
  37. Monit.reset = function(msg) {
  38. this.multi.charm.reset();
  39. this.multi.write('\x1B[32m⌬ PM2 \x1B[39mmonitoring\x1B[96m (To go further check out https://app.pm2.io) \x1B[39m\n\n');
  40. if(msg) {
  41. this.multi.write(msg);
  42. }
  43. this.bars = {};
  44. return this;
  45. }
  46. /**
  47. * Synchronous Monitor init method
  48. * @method init
  49. * @return Monit
  50. */
  51. Monit.init = function() {
  52. this.multi = multimeter(process);
  53. this.multi.on('^C', this.stop);
  54. this.reset();
  55. return this;
  56. }
  57. /**
  58. * Stops monitor
  59. * @method stop
  60. */
  61. Monit.stop = function() {
  62. this.multi.charm.destroy();
  63. process.exit(0);
  64. }
  65. /**
  66. * Refresh monitor
  67. * @method refresh
  68. * @param {} processes
  69. * @return this
  70. */
  71. Monit.refresh = function(processes) {
  72. debug('Monit refresh');
  73. if(!processes) {
  74. processes = [];
  75. }
  76. var num = processes.length;
  77. this.num_bars = Object.size(this.bars);
  78. if(num !== this.num_bars) {
  79. debug('Monit addProcesses - actual: %s, new: %s', this.num_bars, num);
  80. return this.addProcesses(processes);
  81. } else {
  82. if(num === 0) {
  83. return;
  84. }
  85. debug('Monit refresh');
  86. var proc;
  87. for(var i = 0; i < num; i++) {
  88. proc = processes[i];
  89. //this is to avoid a print issue when the process is restarted for example
  90. //we might also check for the pid but restarted|restarting will be rendered bad
  91. if(this.bars[proc.pm_id] && proc.pm2_env.status !== this.bars[proc.pm_id].status) {
  92. debug('bars for %s does not exist', proc.pm_id);
  93. this.addProcesses(processes);
  94. break;
  95. }
  96. this.updateBars(proc);
  97. }
  98. }
  99. return this;
  100. }
  101. Monit.addProcess = function(proc, i) {
  102. if(proc.pm_id in this.bars) {
  103. return ;
  104. }
  105. if (proc.monit.error)
  106. throw new Error(JSON.stringify(proc.monit.error));
  107. var process_name = proc.pm2_env.name || p.basename(proc.pm2_env.pm_exec_path);
  108. var status = proc.pm2_env.status == 'online' ? chalk.green.bold('●') : chalk.red.bold('●');
  109. this.multi.write(' ' + status + ' ' + chalk.green.bold(process_name));
  110. this.multi.write('\n');
  111. this.multi.write('[' + proc.pm2_env.pm_id + '] [' + proc.pm2_env.exec_mode + ']\n');
  112. var bar_cpu = this.multi(40, (i * 2) + 3 + i, {
  113. width: 30,
  114. solid: {
  115. text: '|',
  116. foreground: 'white',
  117. background: 'blue'
  118. },
  119. empty: {
  120. text: ' '
  121. }
  122. });
  123. var bar_memory = this.multi(40, (i * 2) + 4 + i, {
  124. width: 30,
  125. solid: {
  126. text: '|',
  127. foreground: 'white',
  128. background: 'red'
  129. },
  130. empty: {
  131. text: ' '
  132. }
  133. });
  134. this.bars[proc.pm_id] = {
  135. memory: bar_memory,
  136. cpu: bar_cpu,
  137. status: proc.pm2_env.status
  138. };
  139. this.updateBars(proc);
  140. this.multi.write('\n');
  141. return this;
  142. }
  143. Monit.addProcesses = function(processes) {
  144. if(!processes) {
  145. processes = [];
  146. }
  147. this.reset();
  148. var num = processes.length;
  149. if(num > 0) {
  150. for(var i = 0; i < num; i++) {
  151. this.addProcess(processes[i], i);
  152. }
  153. } else {
  154. this.reset('No processes to monit');
  155. }
  156. }
  157. // Draw memory bars
  158. /**
  159. * Description
  160. * @method drawRatio
  161. * @param {} bar_memory
  162. * @param {} memory
  163. * @return
  164. */
  165. Monit.drawRatio = function(bar_memory, memory) {
  166. var scale = 0;
  167. if (memory < RATIO_T1) scale = RATIO_T1;
  168. else if (memory < RATIO_T2) scale = RATIO_T2;
  169. else if (memory < RATIO_T3) scale = RATIO_T3;
  170. else scale = RATIO_T4;
  171. bar_memory.ratio(memory,
  172. scale,
  173. UX.helpers.bytesToSize(memory, 3));
  174. };
  175. /**
  176. * Updates bars informations
  177. * @param {} proc proc object
  178. * @return this
  179. */
  180. Monit.updateBars = function(proc) {
  181. if (this.bars[proc.pm_id]) {
  182. if (proc.pm2_env.status !== 'online' || proc.pm2_env.status !== this.bars[proc.pm_id].status) {
  183. this.bars[proc.pm_id].cpu.percent(0, chalk.red(proc.pm2_env.status));
  184. this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red(proc.pm2_env.status));
  185. } else if (!proc.monit) {
  186. this.bars[proc.pm_id].cpu.percent(0, chalk.red('No data'));
  187. this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red('No data'));
  188. } else {
  189. this.bars[proc.pm_id].cpu.percent(proc.monit.cpu);
  190. this.drawRatio(this.bars[proc.pm_id].memory, proc.monit.memory);
  191. }
  192. }
  193. return this;
  194. }
  195. module.exports = Monit;