pm2-perfmonitor 2.1.3 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/app.js CHANGED
@@ -60,6 +60,12 @@ const cpuOverloadHistory = new Map()
60
60
  const cpuOverloadRestartHistory = new Map()
61
61
  const cpuOverloadRestartFailedHistory = new Map()
62
62
 
63
+ /**
64
+ * perf 样本是否采集中
65
+ * @type { Map<number,boolean> }
66
+ */
67
+ const perfSamplingStats = new Map()
68
+
63
69
  /**
64
70
  * @param {'log' | 'info' | 'error' | 'warn'} type
65
71
  *
@@ -152,11 +158,17 @@ const setCpuOverloadRestartFailedHistory = (pm_id) => {
152
158
  }
153
159
  }
154
160
 
161
+ let isProcessCheckerRunning = false
162
+
155
163
  /**
156
164
  * check process
157
165
  */
158
166
  const processChecker = async () => {
167
+ if (isProcessCheckerRunning) return
168
+
159
169
  try {
170
+ isProcessCheckerRunning = true
171
+
160
172
  const apps = await listAppsAsync()
161
173
 
162
174
  for (const app of apps) {
@@ -249,6 +261,8 @@ const processChecker = async () => {
249
261
  )
250
262
 
251
263
  if (enablePerfCollection) {
264
+ perfSamplingStats.set(pm_id, true)
265
+
252
266
  await performPerfSampling({
253
267
  pid,
254
268
  moduleName: MODULE_NAME,
@@ -257,6 +271,8 @@ const processChecker = async () => {
257
271
  sampleDuration: perfSampleDuration,
258
272
  sampleFrequency: perfSampleFrequency,
259
273
  })
274
+
275
+ perfSamplingStats.delete(pm_id)
260
276
  }
261
277
 
262
278
  try {
@@ -292,6 +308,8 @@ const processChecker = async () => {
292
308
  }
293
309
  } catch (err) {
294
310
  logger('error', err)
311
+ } finally {
312
+ isProcessCheckerRunning = false
295
313
  }
296
314
  }
297
315
 
@@ -417,6 +435,23 @@ const runModule = () => {
417
435
  return res.map((v) => `[${v[0]}]:${v[1]}`).join(' ; ')
418
436
  },
419
437
  })
438
+
439
+ Probe.metric({
440
+ name: 'Processes in Sampling (perf)',
441
+ value: () => {
442
+ const res = []
443
+
444
+ for (const [k, v] of perfSamplingStats) {
445
+ if (v === true) {
446
+ res.push(k)
447
+ }
448
+ }
449
+
450
+ if (!res.length) return 'N/A'
451
+
452
+ return res.join(', ')
453
+ },
454
+ })
420
455
  }
421
456
 
422
457
  runModule()
@@ -30,7 +30,7 @@ const execCommand = async (cmd, args, options = {}) => {
30
30
 
31
31
  return true
32
32
  } catch (err) {
33
- console.error(`Command failed: ${cmd} ${args.join(' ')}`, err.message)
33
+ console.error(`Command failed: [${cmd} ${args.join(' ')}]`, err.message)
34
34
  return false
35
35
  }
36
36
  }
@@ -186,7 +186,9 @@ const performPerfSampling = async ({
186
186
 
187
187
  // --- Step 2: perf script 导出为文本堆栈 ---
188
188
  const scriptOk = await execCommand('perf', ['script', '-i', perfDataFile], {
189
- stdout: fs.createWriteStream(perfStacksFile),
189
+ stdout: {
190
+ file: perfStacksFile,
191
+ },
190
192
  })
191
193
 
192
194
  if (!scriptOk) return
@@ -217,14 +219,18 @@ const performPerfSampling = async ({
217
219
  stackcollapsePath,
218
220
  [perfStacksFile],
219
221
  {
220
- stdout: fs.createWriteStream(perfFoldedFile),
222
+ stdout: {
223
+ file: perfFoldedFile,
224
+ },
221
225
  },
222
226
  )
223
227
  if (!collapseOk) return
224
228
 
225
229
  // --- Step 5: 生成 SVG 火焰图 ---
226
230
  const flameOk = await execCommand(flamegraphPath, [perfFoldedFile], {
227
- stdout: fs.createWriteStream(perfSvgFile),
231
+ stdout: {
232
+ file: perfSvgFile,
233
+ },
228
234
  })
229
235
  if (flameOk) {
230
236
  logger('info', `PID:${pidNum} Flame graph generated: ${perfSvgFile}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm2-perfmonitor",
3
- "version": "2.1.3",
3
+ "version": "2.1.6",
4
4
  "description": "A pm2 module for performance monitoring. Automatically detect zombie processes and restart it",
5
5
  "author": {
6
6
  "name": "elenh",