Skip to content
This repository was archived by the owner on Jan 6, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@
"electron-updater": "^4.6.5",
"history": "^5.3.0",
"node-fetch": "^3.2.3",
"pidusage": "^3.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.3.1",
Expand Down
4 changes: 4 additions & 0 deletions src/main/geth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,7 @@ export const initialize = async () => {
}
registerChildProcess(gethProcess);
};

export const getPid = () => {
return gethProcess?.pid;
};
3 changes: 3 additions & 0 deletions src/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { getStatus, startGeth, stopGeth } from './geth';
import { store } from './store';
import logger from './logger';
import { getMainProcessUsage, getNodeUsage } from './monitor';

// eslint-disable-next-line import/prefer-default-export
export const initialize = () => {
Expand All @@ -32,4 +33,6 @@ export const initialize = () => {
});
ipcMain.handle('getGethLogs', getGethLogs);
ipcMain.handle('getGethErrorLogs', getGethErrorLogs);
ipcMain.handle('getNodeUsage', getNodeUsage);
ipcMain.handle('getMainProcessUsage', getMainProcessUsage);
};
23 changes: 23 additions & 0 deletions src/main/monitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getPid } from './geth';

const pidusage = require('pidusage');

export const getProcessUsageByPid = async (pid: number) => {
const stats = await pidusage(pid);
return stats;
};

export const getNodeUsage = async () => {
const nodePid = await getPid();
if (typeof nodePid !== 'number') {
return undefined;
}
const gethUsage = await getProcessUsageByPid(nodePid);
return gethUsage;
};

export const getMainProcessUsage = async () => {
const memory = await process.getProcessMemoryInfo();
const cpu = await process.getCPUUsage();
return { memory, cpu };
};
7 changes: 7 additions & 0 deletions src/main/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,11 @@ contextBridge.exposeInMainWorld('electron', {
ipcRenderer.invoke('setStoreValue', key, value),
getGethLogs: () => ipcRenderer.invoke('getGethLogs'),
getGethErrorLogs: () => ipcRenderer.invoke('getGethErrorLogs'),
getMainProcessUsage: () => ipcRenderer.invoke('getMainProcessUsage'),
getRendererProcessUsage: async () => {
const memory = await process.getProcessMemoryInfo();
const cpu = await process.getCPUUsage();
return { memory, cpu };
},
getNodeUsage: () => ipcRenderer.invoke('getNodeUsage'),
});
88 changes: 85 additions & 3 deletions src/renderer/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const Footer = () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [sGethErrorLogs, setGethErrorLogs] = useState<any>();
const [sGethDeleteResult, setGethDeleteResult] = useState<boolean>();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [sMonitoringData, setMonitoringData] = useState<any>();

const getGethLogs = async () => {
const gethLogs = await electron.getGethLogs();
Expand All @@ -25,15 +27,80 @@ const Footer = () => {
setGethErrorLogs(gethLogs);
};

const getMonitoringData = async () => {
const rendererProcessUsage = await electron.getRendererProcessUsage();
const mainProcessUsage = await electron.getMainProcessUsage();
const nodeUsage = await electron.getNodeUsage();

// --- Memory ---
let totalMemoryUsed = 0;
if (nodeUsage?.memory) {
nodeUsage.memory *= 1e-9;
totalMemoryUsed += nodeUsage.memory;
}
if (rendererProcessUsage?.memory?.residentSet) {
rendererProcessUsage.memory.residentSet *= 1e-9;
totalMemoryUsed += rendererProcessUsage.memory.residentSet;
}
if (mainProcessUsage?.memory?.residentSet) {
mainProcessUsage.memory.residentSet *= 1e-9;
totalMemoryUsed += mainProcessUsage.memory.residentSet;
}
let uiMemoryUsage;
// https://thewebdev.info/2022/01/08/how-to-programmatically-get-memory-usage-in-chrome-with-javascript/
if (typeof window?.performance?.memory?.usedJSHeapSize === 'number') {
uiMemoryUsage = window.performance.memory.usedJSHeapSize * 1e-9;
totalMemoryUsed += uiMemoryUsage;
}
if (uiMemoryUsage) {
uiMemoryUsage = `${uiMemoryUsage.toFixed(3)}GB`;
}
let totalMemoryUsedStr;
if (totalMemoryUsed) {
totalMemoryUsedStr = `Total memory used: ${totalMemoryUsed.toFixed(3)}GB`;
}

// --- CPU ---
let totalCpuUsed = 0;
if (nodeUsage?.cpu) {
totalCpuUsed += nodeUsage.cpu;
}
if (rendererProcessUsage?.cpu?.percentCPUUsage) {
totalCpuUsed += rendererProcessUsage.cpu.percentCPUUsage;
}
if (mainProcessUsage?.cpu?.percentCPUUsage) {
totalCpuUsed += rendererProcessUsage.cpu.percentCPUUsage;
}
let totalCpuUsedStr;
if (totalCpuUsed) {
totalCpuUsedStr = `Total cpu used: ${totalCpuUsed.toFixed(
1
)}% of virtual CPU cores`;
}
setMonitoringData({
total: {
memory: totalMemoryUsedStr,
cpu: totalCpuUsedStr,
},
nodeProcess: nodeUsage,
uiMemoryUsage,
rendererProcess: rendererProcessUsage,
mainProcess: mainProcessUsage,
});
};

useEffect(() => {
getGethLogs();
getGethErrorLogs();
getMonitoringData();
}, []);

useEffect(() => {
if (sSelectedMenuDrawer === 'debugging') {
getGethLogs();
getGethErrorLogs();
} else if (sSelectedMenuDrawer === 'monitoring') {
getMonitoringData();
}
}, [sSelectedMenuDrawer]);

Expand Down Expand Up @@ -102,19 +169,21 @@ const Footer = () => {
>
<h4>Geth Info Logs</h4>
<ReactJson
style={{ overflow: 'auto', maxHeight: '80%' }}
src={{ logs: sLogs }}
theme="monokai"
displayDataTypes={false}
enableClipboard={false}
style={{ overflow: 'auto', maxHeight: '80%' }}
collapsed
/>
<h4>Geth Error Logs</h4>
<ReactJson
src={{ logs: sGethErrorLogs }}
style={{ overflow: 'auto', maxHeight: '80%' }}
src={{ logs: sGethErrorLogs }}
theme="monokai"
displayDataTypes={false}
enableClipboard={false}
collapsed
/>
</MenuDrawer>
<MenuDrawer
Expand Down Expand Up @@ -158,7 +227,20 @@ const Footer = () => {
isSelected={sSelectedMenuDrawer === 'monitoring'}
onClickCloseButton={() => setSelectedMenuDrawer(undefined)}
>
<div style={{ flex: 1, overflow: 'auto' }}>Monitoring</div>
<div style={{ flex: 1, overflow: 'auto' }}>
<h2>Memory</h2>
{sMonitoringData?.total?.memory}
<h2>CPU</h2>
{sMonitoringData?.total?.cpu}
<h2>All available metrics</h2>
<ReactJson
src={sMonitoringData}
theme="monokai"
displayDataTypes={false}
enableClipboard={false}
style={{ overflow: 'auto', maxHeight: '80%' }}
/>
</div>
</MenuDrawer>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const Header = () => {
});

useEffect(() => {
console.log('qExeuctionIsSyncing: ', qExeuctionIsSyncing);
// console.log('qExeuctionIsSyncing: ', qExeuctionIsSyncing);
if (qExeuctionIsSyncing.isError) {
setSyncPercent('');
setIsSyncing(false);
Expand All @@ -45,7 +45,7 @@ const Header = () => {
}, [qExeuctionIsSyncing]);

useEffect(() => {
console.log('qExecutionPeers: ', qExecutionPeers);
// console.log('qExecutionPeers: ', qExecutionPeers);
if (qExecutionPeers.isError) {
setPeers(undefined);
return;
Expand Down
15 changes: 15 additions & 0 deletions src/renderer/__mocks__/custom-preload-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,19 @@ export const getGethErrorLogs = (): any => {
return [{ level: 'info', message: 'one log' }];
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getRendererProcessUsage = (): any => {
return { cpu: 200000, memory: 'high' };
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getMainProcessUsage = (): any => {
return { cpu: 200000, memory: 'high' };
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getNodeUsage = (): any => {
return { cpu: 200000, memory: 'high' };
};

export const SENTRY_DSN = 'fake_sentry_dsn';
27 changes: 20 additions & 7 deletions src/renderer/preload.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

// Since we are using Chrome only in Electron and this is not a web standard yet,
// we extend window.performance to include Chrome's memory stats
interface Performance extends Performance {
memory?: {
/** The maximum size of the heap, in bytes, that is available to the context. */
jsHeapSizeLimit: number;
/** The total allocated heap size, in bytes. */
totalJSHeapSize: number;
/** The currently active segment of JS heap, in bytes. */
usedJSHeapSize: number;
};
}

declare global {
interface Window {
electron: {
SENTRY_DSN: string;
ipcRenderer: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
on(channel: string, func: (...args: any[]) => void): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
once(channel: string, func: (...args: any[]) => void): void;
};
getGethStatus(): string;
Expand All @@ -14,17 +27,17 @@ declare global {
deleteGethDisk(): boolean;
getGethDiskUsed(): number;
getSystemFreeDiskSpace(): number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getDebugInfo(): any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getStoreValue(key: string): any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setStoreValue(key: string, value: any): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getGethLogs(): any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getGethErrorLogs(): any;
getRendererProcessUsage(): any;
getMainProcessUsage(): any;
getNodeUsage(): any;
};

performance: Performance;
}
}

Expand Down