I/O metrics (#224)

* feat: Proxy Node IO stats to the FE

* chore: Sync up FE

* feat: Charts for cache sizes

* feat: All graphs are in

* chore: Remove browserlist
This commit is contained in:
Maciej Hirsz
2020-01-30 15:03:19 +01:00
committed by GitHub
parent 668065c1a8
commit 19f57d71be
14 changed files with 211 additions and 21 deletions
+8 -1
View File
@@ -10,6 +10,7 @@ import {
NodeCount,
NodeDetails,
NodeStats,
NodeIO,
NodeHardware,
NodeLocation,
BlockNumber,
@@ -43,6 +44,7 @@ export const Actions = {
AfgReceivedPrecommit : 0x12 as 0x12,
AfgAuthoritySet : 0x13 as 0x13,
StaleNode : 0x14 as 0x14,
NodeIO : 0x15 as 0x15,
};
export type Action = typeof Actions[keyof typeof Actions];
@@ -70,7 +72,7 @@ export namespace Variants {
export interface AddedNodeMessage extends MessageBase {
action: typeof Actions.AddedNode;
payload: [NodeId, NodeDetails, NodeStats, NodeHardware, BlockDetails, Maybe<NodeLocation>, Timestamp];
payload: [NodeId, NodeDetails, NodeStats, NodeIO, NodeHardware, BlockDetails, Maybe<NodeLocation>, Timestamp];
}
export interface RemovedNodeMessage extends MessageBase {
@@ -103,6 +105,11 @@ export namespace Variants {
payload: [NodeId, NodeHardware];
}
export interface NodeIOMessage extends MessageBase {
action: typeof Actions.NodeIO;
payload: [NodeId, NodeIO];
}
export interface TimeSyncMessage extends MessageBase {
action: typeof Actions.TimeSync;
payload: Timestamp;
+1 -1
View File
@@ -9,4 +9,4 @@ import * as FeedMessage from './feed';
export { Types, FeedMessage };
// Increment this if breaking changes were made to types in `feed.ts`
export const VERSION: Types.FeedVersion = 28 as Types.FeedVersion;
export const VERSION: Types.FeedVersion = 29 as Types.FeedVersion;
+2
View File
@@ -22,6 +22,7 @@ export type Longitude = Opaque<number, 'Longitude'>;
export type City = Opaque<string, 'City'>;
export type MemoryUse = Opaque<number, 'MemoryUse'>;
export type CPUUse = Opaque<number, 'CPUUse'>;
export type Bytes = Opaque<number, 'Bytes'>;
export type BytesPerSecond = Opaque<number, 'BytesPerSecond'>;
export type NetworkId = Opaque<string, 'NetworkId'>;
export type NetworkState = Opaque<string | object, 'NetworkState'>;
@@ -29,6 +30,7 @@ export type NetworkState = Opaque<string | object, 'NetworkState'>;
export type BlockDetails = [BlockNumber, BlockHash, Milliseconds, Timestamp, Maybe<PropagationTime>];
export type NodeDetails = [NodeName, NodeImplementation, NodeVersion, Maybe<Address>, Maybe<NetworkId>];
export type NodeStats = [PeerCount, TransactionCount];
export type NodeIO = [Array<Bytes>, Array<Bytes>, Array<BytesPerSecond>, Array<BytesPerSecond>];
export type NodeHardware = [Array<MemoryUse>, Array<CPUUse>, Array<BytesPerSecond>, Array<BytesPerSecond>, Array<Timestamp>];
export type NodeLocation = [Latitude, Longitude, City];
+4
View File
@@ -34,6 +34,10 @@ export default class App extends React.Component<{}, State> {
mem: true,
upload: false,
download: false,
stateCacheSize: false,
dbCacheSize: false,
diskRead: false,
diskWrite: false,
blocknumber: true,
blockhash: true,
blocktime: true,
+2 -2
View File
@@ -166,9 +166,9 @@ export class Connection {
}
case Actions.AddedNode: {
const [id, nodeDetails, nodeStats, nodeHardware, blockDetails, location, connectedAt] = message.payload;
const [id, nodeDetails, nodeStats, nodeIO, nodeHardware, blockDetails, location, connectedAt] = message.payload;
const pinned = this.pins.has(nodeDetails[0]);
const node = new Node(pinned, id, nodeDetails, nodeStats, nodeHardware, blockDetails, location, connectedAt);
const node = new Node(pinned, id, nodeDetails, nodeStats, nodeIO, nodeHardware, blockDetails, location, connectedAt);
nodes.add(node);
@@ -31,6 +31,10 @@ import cpuIcon from '../../icons/microchip-solid.svg';
import memoryIcon from '../../icons/memory-solid.svg';
import uploadIcon from '../../icons/cloud-upload.svg';
import downloadIcon from '../../icons/cloud-download.svg';
import readIcon from '../../icons/arrow-up.svg';
import writeIcon from '../../icons/arrow-down.svg';
import databaseIcon from '../../icons/database.svg';
import stateIcon from '../../icons/git-branch.svg';
import networkIcon from '../../icons/network.svg';
import uptimeIcon from '../../icons/pulse.svg';
import externalLinkIcon from '../../icons/link-external.svg';
@@ -210,6 +214,74 @@ export namespace Column {
}
};
export const STATE_CACHE: Column = {
label: 'State Cache Size',
icon: stateIcon,
width: 40,
setting: 'stateCacheSize',
sortBy: ({ stateCacheSize }) => stateCacheSize.length < 3 ? 0 : stateCacheSize[stateCacheSize.length - 1],
render: ({ stateCacheSize, chartstamps }) => {
if (stateCacheSize.length < 3) {
return '-';
}
return (
<Sparkline width={44} height={16} stroke={1} format={formatBytes} values={stateCacheSize} stamps={chartstamps} minScale={MEMORY_SCALE} />
);
}
};
export const DB_CACHE: Column = {
label: 'Database Cache Size',
icon: databaseIcon,
width: 40,
setting: 'dbCacheSize',
sortBy: ({ dbCacheSize }) => dbCacheSize.length < 3 ? 0 : dbCacheSize[dbCacheSize.length - 1],
render: ({ dbCacheSize, chartstamps }) => {
if (dbCacheSize.length < 3) {
return '-';
}
return (
<Sparkline width={44} height={16} stroke={1} format={formatBytes} values={dbCacheSize} stamps={chartstamps} minScale={MEMORY_SCALE} />
);
}
};
export const DISK_READ: Column = {
label: 'Disk Read',
icon: readIcon,
width: 40,
setting: 'diskRead',
sortBy: ({ diskRead }) => diskRead.length < 3 ? 0 : diskRead[diskRead.length - 1],
render: ({ diskRead, chartstamps }) => {
if (diskRead.length < 3) {
return '-';
}
return (
<Sparkline width={44} height={16} stroke={1} format={formatBandwidth} values={diskRead} stamps={chartstamps} minScale={MEMORY_SCALE} />
);
}
};
export const DISK_WRITE: Column = {
label: 'Disk Write',
icon: writeIcon,
width: 40,
setting: 'diskWrite',
sortBy: ({ diskWrite }) => diskWrite.length < 3 ? 0 : diskWrite[diskWrite.length - 1],
render: ({ diskWrite, chartstamps }) => {
if (diskWrite.length < 3) {
return '-';
}
return (
<Sparkline width={44} height={16} stroke={1} format={formatBandwidth} values={diskWrite} stamps={chartstamps} minScale={MEMORY_SCALE} />
);
}
};
export const BLOCK_NUMBER: Column = {
label: 'Block',
icon: blockIcon,
@@ -330,6 +402,18 @@ function formatMemory(kbs: number, stamp: Maybe<Types.Timestamp>): string {
}
}
function formatBytes(bytes: number, stamp: Maybe<Types.Timestamp>): string {
const ago = stamp ? ` (${formatStamp(stamp)})` : '';
if (bytes >= 1024 * 1024) {
return `${(bytes / (1024 * 1024)).toFixed(1)} MB${ago}`;
} else if (bytes >= 1000) {
return `${(bytes / 1024).toFixed(1)} kB${ago}`;
} else {
return `${bytes} B${ago}`;
}
}
function formatBandwidth(bps: number, stamp: Maybe<Types.Timestamp>): string {
const ago = stamp ? ` (${formatStamp(stamp)})` : '';
@@ -36,6 +36,10 @@ export class Row extends React.Component<Row.Props, Row.State> {
Column.MEM,
Column.UPLOAD,
Column.DOWNLOAD,
Column.STATE_CACHE,
Column.DB_CACHE,
Column.DISK_READ,
Column.DISK_WRITE,
Column.BLOCK_NUMBER,
Column.BLOCK_HASH,
Column.FINALIZED,
+21
View File
@@ -43,6 +43,10 @@ export class Node {
public cpu: Types.CPUUse[];
public upload: Types.BytesPerSecond[];
public download: Types.BytesPerSecond[];
public stateCacheSize: Types.Bytes[];
public dbCacheSize: Types.Bytes[];
public diskRead: Types.BytesPerSecond[];
public diskWrite: Types.BytesPerSecond[];
public chartstamps: Types.Timestamp[];
public height: Types.BlockNumber;
@@ -66,6 +70,7 @@ export class Node {
id: Types.NodeId,
nodeDetails: Types.NodeDetails,
nodeStats: Types.NodeStats,
nodeIO: Types.NodeIO,
nodeHardware: Types.NodeHardware,
blockDetails: Types.BlockDetails,
location: Maybe<Types.NodeLocation>,
@@ -89,6 +94,7 @@ export class Node {
this.sortableVersion = (major * 1000 + minor * 100 + patch) | 0;
this.updateStats(nodeStats);
this.updateIO(nodeIO);
this.updateHardware(nodeHardware);
this.updateBlock(blockDetails);
@@ -106,6 +112,17 @@ export class Node {
this.trigger();
}
public updateIO(io: Types.NodeIO) {
const [stateCacheSize, dbCacheSize, diskRead, diskWrite] = io;
this.stateCacheSize = stateCacheSize;
this.dbCacheSize = dbCacheSize;
this.diskRead = diskRead;
this.diskWrite = diskWrite;
this.trigger();
}
public updateHardware(hardware: Types.NodeHardware) {
const [mem, cpu, upload, download, chartstamps] = hardware;
@@ -202,6 +219,10 @@ export namespace State {
mem: boolean;
upload: boolean;
download: boolean;
stateCacheSize: boolean;
dbCacheSize: boolean;
diskRead: boolean;
diskWrite: boolean;
blocknumber: boolean;
blockhash: boolean;
finalized: boolean;