From b1cf02f29cb1d21d1389c714f7d026223dfb07b9 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Tue, 12 Mar 2024 08:29:33 -0300 Subject: [PATCH 01/18] feat: free memory module --- lib/models/system.js | 48 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/models/system.js b/lib/models/system.js index c421a5b2..2c5c84b3 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -8,6 +8,7 @@ import { KadiraModel } from './0model'; import { EventLoopMonitor } from '../event_loop_monitor.js'; import { Ntp } from '../ntp'; import os from 'os'; +import { execSync } from 'child_process'; export const MEMORY_ROUNDING_FACTOR = 100 * 1024; // 100kb const EVENT_LOOP_ROUNDING_FACTOR = 500; // microseconds @@ -47,6 +48,50 @@ export function SystemModel () { _.extend(SystemModel.prototype, KadiraModel.prototype); +function meminfo() { + var info = {}; + var data = fs.readFileSync('/proc/meminfo').toString(); + data.split(/\n/g).forEach(function(line){ + line = line.split(':'); + + // Ignore invalid lines, if any + if (line.length < 2) { + return; + } + + // Remove parseInt call to make all values strings + info[line[0]] = parseInt(line[1].trim(), 10); + }); + + return info; +} + +function getFreeMemory(){ + const isLinux = process.platform === "linux"; + const isMac = process.platform === "darwin"; + + try { + if(isLinux){ + const info = meminfo(); + return info.MemFree + info.Buffers + info.Cached; + } + if(isMac){ + const output = execSync('vm_stat').toString(); + const pageSizeArray = [...output.matchAll(/page size of (\d*)/g)]; + const pageSize = parseInt(pageSizeArray[0][1], 10) + const freePagesMatches = [...output.matchAll(/Pages free:\s*(\d*)/g)]; + const freePages = parseInt(freePagesMatches[0][1], 10) + const inactivePagesMatches = [...output.matchAll(/Pages inactive:\s*(\d*)/g)]; + const inactivePages = parseInt(inactivePagesMatches[0][1],10) + return pageSize * (freePages + inactivePages) + } + }catch(e){ + console.error('failed to get native memory info, falling back to default option', e); + } + + return os.freemem(); +} + SystemModel.prototype.buildPayload = function () { let metrics = {}; let now = Ntp._now(); @@ -60,7 +105,8 @@ SystemModel.prototype.buildPayload = function () { metrics.memoryExternal = roundUsingFactor(memoryUsage.external, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.memoryHeapUsed = roundUsingFactor(memoryUsage.heapUsed, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.memoryHeapTotal = roundUsingFactor(memoryUsage.heapTotal, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); - metrics.freeMemory = roundUsingFactor(os.freemem(), MEMORY_ROUNDING_FACTOR) / (1024 * 1024); + const freeMemory = getFreeMemory(); + metrics.freeMemory = roundUsingFactor(freeMemory, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.totalMemory = roundUsingFactor(os.totalmem(), MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.newSessions = this.newSessions; From 466e33417cd46692443a72e61707bb6303608731 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Tue, 12 Mar 2024 08:32:55 -0300 Subject: [PATCH 02/18] fix: eslint --- lib/models/system.js | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 2c5c84b3..de62d3ce 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -8,6 +8,7 @@ import { KadiraModel } from './0model'; import { EventLoopMonitor } from '../event_loop_monitor.js'; import { Ntp } from '../ntp'; import os from 'os'; +import fs from 'fs'; import { execSync } from 'child_process'; export const MEMORY_ROUNDING_FACTOR = 100 * 1024; // 100kb @@ -48,44 +49,44 @@ export function SystemModel () { _.extend(SystemModel.prototype, KadiraModel.prototype); -function meminfo() { - var info = {}; - var data = fs.readFileSync('/proc/meminfo').toString(); - data.split(/\n/g).forEach(function(line){ - line = line.split(':'); +function meminfo () { + let info = {}; + let data = fs.readFileSync('/proc/meminfo').toString(); + data.split(/\n/g).forEach(function (line) { + line = line.split(':'); - // Ignore invalid lines, if any - if (line.length < 2) { - return; - } + // Ignore invalid lines, if any + if (line.length < 2) { + return; + } - // Remove parseInt call to make all values strings - info[line[0]] = parseInt(line[1].trim(), 10); + // Remove parseInt call to make all values strings + info[line[0]] = parseInt(line[1].trim(), 10); }); return info; } -function getFreeMemory(){ - const isLinux = process.platform === "linux"; - const isMac = process.platform === "darwin"; +function getFreeMemory () { + const isLinux = process.platform === 'linux'; + const isMac = process.platform === 'darwin'; try { - if(isLinux){ + if (isLinux) { const info = meminfo(); return info.MemFree + info.Buffers + info.Cached; } - if(isMac){ + if (isMac) { const output = execSync('vm_stat').toString(); const pageSizeArray = [...output.matchAll(/page size of (\d*)/g)]; - const pageSize = parseInt(pageSizeArray[0][1], 10) + const pageSize = parseInt(pageSizeArray[0][1], 10); const freePagesMatches = [...output.matchAll(/Pages free:\s*(\d*)/g)]; - const freePages = parseInt(freePagesMatches[0][1], 10) + const freePages = parseInt(freePagesMatches[0][1], 10); const inactivePagesMatches = [...output.matchAll(/Pages inactive:\s*(\d*)/g)]; - const inactivePages = parseInt(inactivePagesMatches[0][1],10) - return pageSize * (freePages + inactivePages) + const inactivePages = parseInt(inactivePagesMatches[0][1],10); + return pageSize * (freePages + inactivePages); } - }catch(e){ + } catch (e) { console.error('failed to get native memory info, falling back to default option', e); } From 4657801502020040f5e1d065790fb8ab87d8e0cf Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Tue, 12 Mar 2024 19:13:36 -0300 Subject: [PATCH 03/18] Update lib/models/system.js Co-authored-by: zodern --- lib/models/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/system.js b/lib/models/system.js index de62d3ce..1c451372 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -87,7 +87,7 @@ function getFreeMemory () { return pageSize * (freePages + inactivePages); } } catch (e) { - console.error('failed to get native memory info, falling back to default option', e); + console.error('Monti APM: failed to get native memory info, falling back to default option', e); } return os.freemem(); From 4d456552bf2f7d34fc015c7600f71a5ad12d379c Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Tue, 12 Mar 2024 20:13:52 -0300 Subject: [PATCH 04/18] fix: addressing code review comments --- lib/models/system.js | 48 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 1c451372..0efa6947 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -9,7 +9,7 @@ import { EventLoopMonitor } from '../event_loop_monitor.js'; import { Ntp } from '../ntp'; import os from 'os'; import fs from 'fs'; -import { execSync } from 'child_process'; +import { exec } from 'child_process'; export const MEMORY_ROUNDING_FACTOR = 100 * 1024; // 100kb const EVENT_LOOP_ROUNDING_FACTOR = 500; // microseconds @@ -41,17 +41,23 @@ export function SystemModel () { this.previousCpuUsage = process.cpuUsage(); this.cpuHistory = []; this.currentCpuUsage = 0; + this.freeMemory = os.freemem(); setInterval(() => { this.cpuUsage(); }, 2000); + + setInterval(async () => { + await this.getFreeMemory(); + }, 2000); } _.extend(SystemModel.prototype, KadiraModel.prototype); -function meminfo () { +async function meminfo () { let info = {}; - let data = fs.readFileSync('/proc/meminfo').toString(); + const content = await fs.promises.readFile('/proc/meminfo'); + let data = content.toString(); data.split(/\n/g).forEach(function (line) { line = line.split(':'); @@ -67,31 +73,50 @@ function meminfo () { return info; } -function getFreeMemory () { +SystemModel.prototype.getFreeMemory = async function () { const isLinux = process.platform === 'linux'; const isMac = process.platform === 'darwin'; try { if (isLinux) { - const info = meminfo(); - return info.MemFree + info.Buffers + info.Cached; + const info = await meminfo(); + // in kb to bytes + this.freeMemory = 1024 * (info.MemFree + info.Buffers + info.Cached); + return; } if (isMac) { - const output = execSync('vm_stat').toString(); + const output = await new Promise((resolve, reject) => { + exec( + 'vm_stat', + (error, stdout) => { + if (error) { + reject(error); + } else { + resolve(stdout); + } + }); + }); const pageSizeArray = [...output.matchAll(/page size of (\d*)/g)]; const pageSize = parseInt(pageSizeArray[0][1], 10); const freePagesMatches = [...output.matchAll(/Pages free:\s*(\d*)/g)]; const freePages = parseInt(freePagesMatches[0][1], 10); const inactivePagesMatches = [...output.matchAll(/Pages inactive:\s*(\d*)/g)]; const inactivePages = parseInt(inactivePagesMatches[0][1],10); - return pageSize * (freePages + inactivePages); + [pageSize, freePages, inactivePages].forEach(o => { + if (Number.isNaN(o)) { + throw new Error('Monti APM: failed to parse vm_stat'); + } + }); + const totalFreeMemory = pageSize * (freePages + inactivePages); + this.freeMemory = totalFreeMemory; + return; } } catch (e) { console.error('Monti APM: failed to get native memory info, falling back to default option', e); } - return os.freemem(); -} + this.freeMemory = os.freemem(); +}; SystemModel.prototype.buildPayload = function () { let metrics = {}; @@ -106,7 +131,8 @@ SystemModel.prototype.buildPayload = function () { metrics.memoryExternal = roundUsingFactor(memoryUsage.external, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.memoryHeapUsed = roundUsingFactor(memoryUsage.heapUsed, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.memoryHeapTotal = roundUsingFactor(memoryUsage.heapTotal, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); - const freeMemory = getFreeMemory(); + + const freeMemory = this.freeMemory; metrics.freeMemory = roundUsingFactor(freeMemory, MEMORY_ROUNDING_FACTOR) / (1024 * 1024); metrics.totalMemory = roundUsingFactor(os.totalmem(), MEMORY_ROUNDING_FACTOR) / (1024 * 1024); From bfd8a264f3e7e30b584a8f8323877d494582f26d Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Tue, 12 Mar 2024 22:48:06 -0300 Subject: [PATCH 05/18] feat: add sinon and tests --- lib/models/system.js | 17 +++-- package.js | 3 +- tests/models/system.js | 143 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 7 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 0efa6947..dbc0c7e8 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -9,7 +9,7 @@ import { EventLoopMonitor } from '../event_loop_monitor.js'; import { Ntp } from '../ntp'; import os from 'os'; import fs from 'fs'; -import { exec } from 'child_process'; +import cp from 'child_process'; export const MEMORY_ROUNDING_FACTOR = 100 * 1024; // 100kb const EVENT_LOOP_ROUNDING_FACTOR = 500; // microseconds @@ -56,7 +56,15 @@ _.extend(SystemModel.prototype, KadiraModel.prototype); async function meminfo () { let info = {}; - const content = await fs.promises.readFile('/proc/meminfo'); + const content = await new Promise((resolve, reject) => { + fs.readFile('/proc/meminfo', (error, data) => { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + }); let data = content.toString(); data.split(/\n/g).forEach(function (line) { line = line.split(':'); @@ -67,7 +75,7 @@ async function meminfo () { } // Remove parseInt call to make all values strings - info[line[0]] = parseInt(line[1].trim(), 10); + info[line[0].trim()] = parseInt(line[1].trim(), 10); }); return info; @@ -76,7 +84,6 @@ async function meminfo () { SystemModel.prototype.getFreeMemory = async function () { const isLinux = process.platform === 'linux'; const isMac = process.platform === 'darwin'; - try { if (isLinux) { const info = await meminfo(); @@ -86,7 +93,7 @@ SystemModel.prototype.getFreeMemory = async function () { } if (isMac) { const output = await new Promise((resolve, reject) => { - exec( + cp.exec( 'vm_stat', (error, stdout) => { if (error) { diff --git a/package.js b/package.js index 2106362a..b00d2537 100644 --- a/package.js +++ b/package.js @@ -22,14 +22,15 @@ let npmModules = { parseurl: '1.3.3', }; -Npm.depends(npmModules); Package.onUse(function (api) { + Npm.depends(npmModules); configurePackage(api, false); api.export(['Kadira', 'Monti']); }); Package.onTest(function (api) { + Npm.depends({...npmModules, sinon: '17.0.1'}); configurePackage(api, true); api.use([ 'peerlibrary:reactive-publish', diff --git a/tests/models/system.js b/tests/models/system.js index 5fecb6e4..1dbf3461 100644 --- a/tests/models/system.js +++ b/tests/models/system.js @@ -1,7 +1,9 @@ +import child_process from 'child_process'; +import fs from 'fs'; import { Meteor } from 'meteor/meteor'; +import sinon from 'sinon'; import { MEMORY_ROUNDING_FACTOR, SystemModel } from '../../lib/models/system'; import { Wait } from '../_helpers/helpers'; - /** * @flaky */ @@ -15,12 +17,151 @@ Tinytest.add( let payload = model.buildPayload().systemMetrics[0]; test.isTrue(payload.memory > 0, `memory: ${payload.memory}`); test.isTrue((payload.memory * 1024 * 1024 /* in bytes */) % MEMORY_ROUNDING_FACTOR === 0, 'memory is rounded'); + test.isTrue((payload.freeMemory * 1024 * 1024 /* in bytes */) % MEMORY_ROUNDING_FACTOR === 0, 'memory is rounded'); + test.isTrue(payload.freeMemory > 0, 'free memory is > 0'); + test.isTrue(payload.freeMemory > 0, 'free memory is > 0'); test.isTrue(payload.pcpu >= 0, `pcpu: ${payload.pcpu}`); test.isTrue(payload.sessions >= 0, `sessions: ${payload.sessions}`); test.isTrue(payload.endTime >= payload.startTime + 500, `time: ${payload.endTime} - ${payload.startTime}`); } ); +Tinytest.addAsync( + 'Models - System - freeMemory', + async function (test) { + let model = new SystemModel(); + /** + * MAC OS + */ + sinon.stub(process, 'platform').value('darwin'); + + sinon.replace(child_process, 'exec', (a, callback) => { + callback(null, + `Mach Virtual Memory Statistics: (page size of 16384 bytes) + Pages free: 3293. + Pages active: 231224. + Pages inactive: 238682. + Pages speculative: 534. + Pages throttled: 0. + Pages wired down: 212821. + Pages purgeable: 15075. + "Translation faults": 3619403884. + Pages copy-on-write: 205742534. + Pages zero filled: 1133125308. + Pages reactivated: 862283057. + Pages purged: 221979774. + File-backed pages: 115729. + Anonymous pages: 354711. + Pages stored in compressor: 2284038. + Pages occupied by compressor: 452497. + Decompressions: 992611451. + Compressions: 1067810568. + Pageins: 58750181. + Pageouts: 2172799. + Swapins: 6971267. + Swapouts: 8892364.`); + }); + await model.getFreeMemory(); + test.isTrue(model.freeMemory === 3964518400, 'should use the file format on mac'); + sinon.restore(); + + /** + * LINUX + */ + sinon.stub(process, 'platform').value('linux'); + model = new SystemModel(); + sinon.replace(fs, 'readFile', (_,callback) => { + callback(null, + { toString: () => `MemTotal: 2097152 kB + MemFree: 2085696 kB + MemAvailable: 2085828 kB + Buffers: 0 kB + Cached: 132 kB + SwapCached: 0 kB + Active: 0 kB + Inactive: 4116 kB + Active(anon): 0 kB + Inactive(anon): 4116 kB + Active(file): 0 kB + Inactive(file): 0 kB + Unevictable: 0 kB + Mlocked: 0 kB + SwapTotal: 0 kB + SwapFree: 0 kB + Dirty: 0 kB + Writeback: 0 kB + AnonPages: 4116 kB + Mapped: 0 kB + Shmem: 0 kB + KReclaimable: 6807616 kB + Slab: 0 kB + SReclaimable: 0 kB + SUnreclaim: 0 kB + KernelStack: 36496 kB + PageTables: 48024 kB + NFS_Unstable: 0 kB + Bounce: 0 kB + WritebackTmp: 0 kB + CommitLimit: 325948112 kB + Committed_AS: 18755168 kB + VmallocTotal: 34359738367 kB + VmallocUsed: 163092 kB + VmallocChunk: 0 kB + Percpu: 525312 kB + HardwareCorrupted: 0 kB + AnonHugePages: 0 kB + ShmemHugePages: 0 kB + ShmemPmdMapped: 0 kB + FileHugePages: 0 kB + FilePmdMapped: 0 kB + HugePages_Total: 8192 + HugePages_Free: 8189 + HugePages_Rsvd: 61 + HugePages_Surp: 0 + Hugepagesize: 2048 kB + Hugetlb: 16777216 kB + DirectMap4k: 14918780 kB + DirectMap2M: 116037632 kB + DirectMap1G: 5242880 kB`}); + }); + + await model.getFreeMemory(); + console.log(model.freeMemory); + test.isTrue(model.freeMemory === 2135887872, 'should use the file format on linux'); + sinon.restore(); + } +); + +Tinytest.addAsync( + 'Models - System - freeMemory silent error', + async function (test) { + let model = new SystemModel(); + /** + * MAC OS + */ + sinon.stub(process, 'platform').value('darwin'); + sinon.replace(child_process, 'exec', (a, callback) => { + callback(/* error */ true,null); + }); + await model.getFreeMemory(); + test.isTrue(model.freeMemory > 0, 'should use fallback on mac'); + sinon.restore(); + + /** + * LINUX + */ + sinon.stub(process, 'platform').value('linux'); + model = new SystemModel(); + sinon.replace(fs, 'readFile', (_,callback) => { + callback(/* error */ true, null); + }); + + await model.getFreeMemory(); + test.isTrue(model.freeMemory > 0 , 'should use fallback linux'); + sinon.restore(); + } +); + Tinytest.add( 'Models - System - new Sessions - count new session', function (test) { From ae3495e0c6dacd08ea08f54c7c5e0ace6d0680bf Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 08:45:42 -0300 Subject: [PATCH 06/18] feat: downgrade sinon --- package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.js b/package.js index b00d2537..23c4622b 100644 --- a/package.js +++ b/package.js @@ -30,7 +30,7 @@ Package.onUse(function (api) { }); Package.onTest(function (api) { - Npm.depends({...npmModules, sinon: '17.0.1'}); + Npm.depends({...npmModules, sinon: '12.0.1'}); configurePackage(api, true); api.use([ 'peerlibrary:reactive-publish', From af68cc305cf99458e020ed9f49e3d455ff627dab Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 08:51:28 -0300 Subject: [PATCH 07/18] feat: skip test on older versions --- tests/models/system.js | 58 ++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/tests/models/system.js b/tests/models/system.js index 1dbf3461..f8c8c419 100644 --- a/tests/models/system.js +++ b/tests/models/system.js @@ -3,7 +3,7 @@ import fs from 'fs'; import { Meteor } from 'meteor/meteor'; import sinon from 'sinon'; import { MEMORY_ROUNDING_FACTOR, SystemModel } from '../../lib/models/system'; -import { Wait } from '../_helpers/helpers'; +import { Wait, releaseParts } from '../_helpers/helpers'; /** * @flaky */ @@ -26,18 +26,20 @@ Tinytest.add( } ); -Tinytest.addAsync( - 'Models - System - freeMemory', - async function (test) { - let model = new SystemModel(); - /** +// sinon cant stub fs/cp on older node versions +if (releaseParts[0] >= 1 && releaseParts[1] > 8 ) { + Tinytest.addAsync( + 'Models - System - freeMemory', + async function (test) { + let model = new SystemModel(); + /** * MAC OS */ - sinon.stub(process, 'platform').value('darwin'); + sinon.stub(process, 'platform').value('darwin'); - sinon.replace(child_process, 'exec', (a, callback) => { - callback(null, - `Mach Virtual Memory Statistics: (page size of 16384 bytes) + sinon.replace(child_process, 'exec', (a, callback) => { + callback(null, + `Mach Virtual Memory Statistics: (page size of 16384 bytes) Pages free: 3293. Pages active: 231224. Pages inactive: 238682. @@ -60,19 +62,19 @@ Tinytest.addAsync( Pageouts: 2172799. Swapins: 6971267. Swapouts: 8892364.`); - }); - await model.getFreeMemory(); - test.isTrue(model.freeMemory === 3964518400, 'should use the file format on mac'); - sinon.restore(); + }); + await model.getFreeMemory(); + test.isTrue(model.freeMemory === 3964518400, 'should use the file format on mac'); + sinon.restore(); - /** + /** * LINUX */ - sinon.stub(process, 'platform').value('linux'); - model = new SystemModel(); - sinon.replace(fs, 'readFile', (_,callback) => { - callback(null, - { toString: () => `MemTotal: 2097152 kB + sinon.stub(process, 'platform').value('linux'); + model = new SystemModel(); + sinon.replace(fs, 'readFile', (_,callback) => { + callback(null, + { toString: () => `MemTotal: 2097152 kB MemFree: 2085696 kB MemAvailable: 2085828 kB Buffers: 0 kB @@ -123,15 +125,15 @@ Tinytest.addAsync( DirectMap4k: 14918780 kB DirectMap2M: 116037632 kB DirectMap1G: 5242880 kB`}); - }); - - await model.getFreeMemory(); - console.log(model.freeMemory); - test.isTrue(model.freeMemory === 2135887872, 'should use the file format on linux'); - sinon.restore(); - } -); + }); + await model.getFreeMemory(); + console.log(model.freeMemory); + test.isTrue(model.freeMemory === 2135887872, 'should use the file format on linux'); + sinon.restore(); + } + ); +} Tinytest.addAsync( 'Models - System - freeMemory silent error', async function (test) { From 57e8d8789534e984b535a5360e1ac6d172750490 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 08:53:27 -0300 Subject: [PATCH 08/18] fix: lint --- tests/models/system.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/models/system.js b/tests/models/system.js index f8c8c419..f0ea75ed 100644 --- a/tests/models/system.js +++ b/tests/models/system.js @@ -1,4 +1,4 @@ -import child_process from 'child_process'; +import cp from 'child_process'; import fs from 'fs'; import { Meteor } from 'meteor/meteor'; import sinon from 'sinon'; @@ -37,7 +37,7 @@ if (releaseParts[0] >= 1 && releaseParts[1] > 8 ) { */ sinon.stub(process, 'platform').value('darwin'); - sinon.replace(child_process, 'exec', (a, callback) => { + sinon.replace(cp, 'exec', (a, callback) => { callback(null, `Mach Virtual Memory Statistics: (page size of 16384 bytes) Pages free: 3293. @@ -142,7 +142,7 @@ Tinytest.addAsync( * MAC OS */ sinon.stub(process, 'platform').value('darwin'); - sinon.replace(child_process, 'exec', (a, callback) => { + sinon.replace(cp, 'exec', (a, callback) => { callback(/* error */ true,null); }); await model.getFreeMemory(); From 497ea5f6a9bc5a0f693b624e017a0c52ca7a0659 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 21:30:24 -0300 Subject: [PATCH 09/18] fix: older versions --- package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.js b/package.js index 23c4622b..d078f09b 100644 --- a/package.js +++ b/package.js @@ -30,7 +30,7 @@ Package.onUse(function (api) { }); Package.onTest(function (api) { - Npm.depends({...npmModules, sinon: '12.0.1'}); + Npm.depends(Object.assign({}, npmModules, {sinon: '12.0.1'})); configurePackage(api, true); api.use([ 'peerlibrary:reactive-publish', From 9ee6e8778300b01fd5902e4a63b97b7b42850000 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 21:43:00 -0300 Subject: [PATCH 10/18] fix: sinon --- package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.js b/package.js index d078f09b..037c58b1 100644 --- a/package.js +++ b/package.js @@ -30,7 +30,7 @@ Package.onUse(function (api) { }); Package.onTest(function (api) { - Npm.depends(Object.assign({}, npmModules, {sinon: '12.0.1'})); + Npm.depends(Object.assign({}, npmModules, {sinon: '6.3.5'})); configurePackage(api, true); api.use([ 'peerlibrary:reactive-publish', From 016e190c82ba37a903ce0be2d2ee648d75f3cc0b Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 22:41:23 -0300 Subject: [PATCH 11/18] feat: catch error --- lib/models/system.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/models/system.js b/lib/models/system.js index dbc0c7e8..592e3d7c 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -48,7 +48,11 @@ export function SystemModel () { }, 2000); setInterval(async () => { - await this.getFreeMemory(); + try { + await this.getFreeMemory(); + } catch (e) { + console.log('Monti APM: failed to get memory info', e); + } }, 2000); } From b7fd6ef213f081dfae75da04d8e70819725fcb3e Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 23:13:31 -0300 Subject: [PATCH 12/18] feat: use regexp exec as it's not available on node < 8 --- lib/models/system.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 592e3d7c..33fea1d9 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -107,12 +107,12 @@ SystemModel.prototype.getFreeMemory = async function () { } }); }); - const pageSizeArray = [...output.matchAll(/page size of (\d*)/g)]; - const pageSize = parseInt(pageSizeArray[0][1], 10); - const freePagesMatches = [...output.matchAll(/Pages free:\s*(\d*)/g)]; - const freePages = parseInt(freePagesMatches[0][1], 10); - const inactivePagesMatches = [...output.matchAll(/Pages inactive:\s*(\d*)/g)]; - const inactivePages = parseInt(inactivePagesMatches[0][1],10); + const pageSizeArray = /page size of (\d*)/g.exec(output); + const pageSize = parseInt(pageSizeArray[1], 10); + const freePagesMatches = /Pages free:\s*(\d*)/g.exec(output); + const freePages = parseInt(freePagesMatches[1], 10); + const inactivePagesMatches = /Pages inactive:\s*(\d*)/g.exec(output); + const inactivePages = parseInt(inactivePagesMatches[1],10); [pageSize, freePages, inactivePages].forEach(o => { if (Number.isNaN(o)) { throw new Error('Monti APM: failed to parse vm_stat'); From f77e6658fa82d57e066193208675b37a4771e153 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 23:24:12 -0300 Subject: [PATCH 13/18] fix: older versions --- tests/models/system.js | 56 ++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/tests/models/system.js b/tests/models/system.js index f0ea75ed..72413a2c 100644 --- a/tests/models/system.js +++ b/tests/models/system.js @@ -133,36 +133,44 @@ if (releaseParts[0] >= 1 && releaseParts[1] > 8 ) { sinon.restore(); } ); -} -Tinytest.addAsync( - 'Models - System - freeMemory silent error', - async function (test) { - let model = new SystemModel(); - /** + Tinytest.addAsync( + 'Models - System - freeMemory silent error', + async function (test) { + let model = new SystemModel(); + /** * MAC OS */ - sinon.stub(process, 'platform').value('darwin'); - sinon.replace(cp, 'exec', (a, callback) => { - callback(/* error */ true,null); - }); - await model.getFreeMemory(); - test.isTrue(model.freeMemory > 0, 'should use fallback on mac'); - sinon.restore(); + sinon.stub(process, 'platform').value('darwin'); + sinon.replace(cp, 'exec', (a, callback) => { + callback(/* error */ true,null); + }); + await model.getFreeMemory(); + test.isTrue(model.freeMemory > 0, 'should use fallback on mac'); + sinon.restore(); - /** + /** * LINUX */ - sinon.stub(process, 'platform').value('linux'); - model = new SystemModel(); - sinon.replace(fs, 'readFile', (_,callback) => { - callback(/* error */ true, null); - }); + sinon.stub(process, 'platform').value('linux'); + model = new SystemModel(); + sinon.replace(fs, 'readFile', (_,callback) => { + callback(/* error */ true, null); + }); - await model.getFreeMemory(); - test.isTrue(model.freeMemory > 0 , 'should use fallback linux'); - sinon.restore(); - } -); + await model.getFreeMemory(); + test.isTrue(model.freeMemory > 0 , 'should use fallback linux'); + sinon.restore(); + } + ); +} else { + Tinytest.addAsync( + 'Models - System - freeMemory silent error', + async function (test) { + const model = new SystemModel(); + await model.getFreeMemory(); + test.isTrue(model.freeMemory > 0 , 'should use fallback linux'); + }); +} Tinytest.add( 'Models - System - new Sessions - count new session', From 4116dda88cf5567b633e2a22993ec56426589f9f Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 23:34:36 -0300 Subject: [PATCH 14/18] fix: older versions --- lib/models/system.js | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 33fea1d9..2c1483d1 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -10,6 +10,7 @@ import { Ntp } from '../ntp'; import os from 'os'; import fs from 'fs'; import cp from 'child_process'; +import { promisify } from 'util'; export const MEMORY_ROUNDING_FACTOR = 100 * 1024; // 100kb const EVENT_LOOP_ROUNDING_FACTOR = 500; // microseconds @@ -60,15 +61,8 @@ _.extend(SystemModel.prototype, KadiraModel.prototype); async function meminfo () { let info = {}; - const content = await new Promise((resolve, reject) => { - fs.readFile('/proc/meminfo', (error, data) => { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - }); + const content = await promisify(fs.readFile)('/proc/meminfo'); + console.log('AQUIUIQUIQUIQUQ'); let data = content.toString(); data.split(/\n/g).forEach(function (line) { line = line.split(':'); @@ -96,17 +90,7 @@ SystemModel.prototype.getFreeMemory = async function () { return; } if (isMac) { - const output = await new Promise((resolve, reject) => { - cp.exec( - 'vm_stat', - (error, stdout) => { - if (error) { - reject(error); - } else { - resolve(stdout); - } - }); - }); + const output = await promisify(cp.exec)('vm_stat'); const pageSizeArray = /page size of (\d*)/g.exec(output); const pageSize = parseInt(pageSizeArray[1], 10); const freePagesMatches = /Pages free:\s*(\d*)/g.exec(output); From 3853aa92abadc47a2af9c4635077092fc5186fb9 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Wed, 13 Mar 2024 23:43:23 -0300 Subject: [PATCH 15/18] fix: use promisify --- lib/models/system.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 2c1483d1..419ed6ea 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -62,7 +62,6 @@ _.extend(SystemModel.prototype, KadiraModel.prototype); async function meminfo () { let info = {}; const content = await promisify(fs.readFile)('/proc/meminfo'); - console.log('AQUIUIQUIQUIQUQ'); let data = content.toString(); data.split(/\n/g).forEach(function (line) { line = line.split(':'); @@ -90,7 +89,7 @@ SystemModel.prototype.getFreeMemory = async function () { return; } if (isMac) { - const output = await promisify(cp.exec)('vm_stat'); + const {stdout: output} = await promisify(cp.exec)('vm_stat'); const pageSizeArray = /page size of (\d*)/g.exec(output); const pageSize = parseInt(pageSizeArray[1], 10); const freePagesMatches = /Pages free:\s*(\d*)/g.exec(output); @@ -103,6 +102,7 @@ SystemModel.prototype.getFreeMemory = async function () { } }); const totalFreeMemory = pageSize * (freePages + inactivePages); + this.freeMemory = totalFreeMemory; return; } From 21c1fb0268ab612a61c5b0081af0a9c65475b72a Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Thu, 14 Mar 2024 08:58:38 -0300 Subject: [PATCH 16/18] fix: rollback promisify --- lib/models/system.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 419ed6ea..37906486 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -61,7 +61,15 @@ _.extend(SystemModel.prototype, KadiraModel.prototype); async function meminfo () { let info = {}; - const content = await promisify(fs.readFile)('/proc/meminfo'); + const content = await new Promise((resolve, reject) => { + fs.readFile('/proc/meminfo', (error, data) => { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + }); let data = content.toString(); data.split(/\n/g).forEach(function (line) { line = line.split(':'); @@ -89,7 +97,17 @@ SystemModel.prototype.getFreeMemory = async function () { return; } if (isMac) { - const {stdout: output} = await promisify(cp.exec)('vm_stat'); + const output = await new Promise((resolve, reject) => { + cp.exec( + 'vm_stat', + (error, stdout) => { + if (error) { + reject(error); + } else { + resolve(stdout); + } + }); + }); const pageSizeArray = /page size of (\d*)/g.exec(output); const pageSize = parseInt(pageSizeArray[1], 10); const freePagesMatches = /Pages free:\s*(\d*)/g.exec(output); @@ -102,7 +120,6 @@ SystemModel.prototype.getFreeMemory = async function () { } }); const totalFreeMemory = pageSize * (freePages + inactivePages); - this.freeMemory = totalFreeMemory; return; } From 687d4726f9b60806f65a8769a87b7f0bc5639eb8 Mon Sep 17 00:00:00 2001 From: Renan Castro Date: Thu, 14 Mar 2024 09:00:08 -0300 Subject: [PATCH 17/18] fix: lint --- lib/models/system.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/models/system.js b/lib/models/system.js index 37906486..33fea1d9 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -10,7 +10,6 @@ import { Ntp } from '../ntp'; import os from 'os'; import fs from 'fs'; import cp from 'child_process'; -import { promisify } from 'util'; export const MEMORY_ROUNDING_FACTOR = 100 * 1024; // 100kb const EVENT_LOOP_ROUNDING_FACTOR = 500; // microseconds From da59554617ec1c04dd448094bd1c8bc958453cb6 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 15 Mar 2024 12:09:55 -0500 Subject: [PATCH 18/18] Fix memory tests --- lib/models/system.js | 5 +++-- tests/models/system.js | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/models/system.js b/lib/models/system.js index 33fea1d9..bb88dbfc 100644 --- a/lib/models/system.js +++ b/lib/models/system.js @@ -93,7 +93,7 @@ SystemModel.prototype.getFreeMemory = async function () { const info = await meminfo(); // in kb to bytes this.freeMemory = 1024 * (info.MemFree + info.Buffers + info.Cached); - return; + return true; } if (isMac) { const output = await new Promise((resolve, reject) => { @@ -120,13 +120,14 @@ SystemModel.prototype.getFreeMemory = async function () { }); const totalFreeMemory = pageSize * (freePages + inactivePages); this.freeMemory = totalFreeMemory; - return; + return true; } } catch (e) { console.error('Monti APM: failed to get native memory info, falling back to default option', e); } this.freeMemory = os.freemem(); + return false; }; SystemModel.prototype.buildPayload = function () { diff --git a/tests/models/system.js b/tests/models/system.js index 72413a2c..abdc6006 100644 --- a/tests/models/system.js +++ b/tests/models/system.js @@ -27,7 +27,7 @@ Tinytest.add( ); // sinon cant stub fs/cp on older node versions -if (releaseParts[0] >= 1 && releaseParts[1] > 8 ) { +if (releaseParts[0] > 1 || (releaseParts[0] === 1 && releaseParts[1] > 8) ) { Tinytest.addAsync( 'Models - System - freeMemory', async function (test) { @@ -165,13 +165,26 @@ if (releaseParts[0] >= 1 && releaseParts[1] > 8 ) { } else { Tinytest.addAsync( 'Models - System - freeMemory silent error', - async function (test) { + async function (test, done) { const model = new SystemModel(); await model.getFreeMemory(); test.isTrue(model.freeMemory > 0 , 'should use fallback linux'); + done(); }); } +if (process.platform !== 'win32') { + Tinytest.addAsync( + 'Models - System - freeMemory succeed on osx/linux', + async function (test, done) { + const model = new SystemModel(); + let success = await model.getFreeMemory(); + test.isTrue(success); + done(); + } + ); +} + Tinytest.add( 'Models - System - new Sessions - count new session', function (test) {