mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-09-23 11:07:16 +00:00
Add available protocols to the stats endpoint (colors for methods are coming from server) (#1184)
* add protocols array to the endpoint * no message * no message * fix tests and small fix for the iteration * fix the color of the protocol * Get protocols list and method colors from server * fix tests * cr fixes Co-authored-by: Amit Fainholts <amit@up9.com>
This commit is contained in:
@@ -19,21 +19,21 @@ interface TimelineBarChartProps {
|
||||
export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarChartMode, data, selectedProtocol }) => {
|
||||
const [protocolStats, setProtocolStats] = useState([]);
|
||||
const [protocolsNamesAndColors, setProtocolsNamesAndColors] = useState([]);
|
||||
const [commandStats, setCommandStats] = useState(null);
|
||||
const [commandNames, setcommandNames] = useState(null);
|
||||
|
||||
const [methodsStats, setMethodsStats] = useState(null);
|
||||
const [methodsNamesAndColors, setMethodsNamesAndColors] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
const protocolsBarsData = [];
|
||||
const prtcNames = [];
|
||||
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
||||
let newProtocolbj: { [k: string]: any } = {};
|
||||
newProtocolbj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
let newProtocolObj: { [k: string]: any } = {};
|
||||
newProtocolObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
protocolObj.protocols.forEach(protocol => {
|
||||
newProtocolbj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
|
||||
newProtocolObj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
|
||||
prtcNames.push({ name: protocol.name, color: protocol.color });
|
||||
})
|
||||
protocolsBarsData.push(newProtocolbj);
|
||||
protocolsBarsData.push(newProtocolObj);
|
||||
})
|
||||
const uniqueObjArray = Utils.creatUniqueObjArrayByProp(prtcNames, "name")
|
||||
setProtocolStats(protocolsBarsData);
|
||||
@@ -42,49 +42,52 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProtocol === ALL_PROTOCOLS) {
|
||||
setCommandStats(null);
|
||||
setcommandNames(null);
|
||||
setMethodsStats(null);
|
||||
setMethodsNamesAndColors(null);
|
||||
return;
|
||||
}
|
||||
const commandsNames = [];
|
||||
const protocolsCommands = [];
|
||||
const protocolsMethodsNamesAndColors = [];
|
||||
const protocolsMethods = [];
|
||||
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
||||
let newCommandlbj: { [k: string]: any } = {};
|
||||
newCommandlbj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(command => {
|
||||
newCommandlbj[`${command.name}`] = command[StatsMode[timeLineBarChartMode]]
|
||||
if (commandsNames.indexOf(command.name) === -1)
|
||||
commandsNames.push(command.name);
|
||||
let newMethodObj: { [k: string]: any } = {};
|
||||
newMethodObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(method => {
|
||||
newMethodObj[`${method.name}`] = method[StatsMode[timeLineBarChartMode]]
|
||||
protocolsMethodsNamesAndColors.push({name: method.name, color: method.color});
|
||||
})
|
||||
protocolsCommands.push(newCommandlbj);
|
||||
protocolsMethods.push(newMethodObj);
|
||||
})
|
||||
setcommandNames(commandsNames);
|
||||
setCommandStats(protocolsCommands);
|
||||
const uniqueObjArray = Utils.creatUniqueObjArrayByProp(protocolsMethodsNamesAndColors, "name")
|
||||
setMethodsNamesAndColors(uniqueObjArray);
|
||||
setMethodsStats(protocolsMethods);
|
||||
}, [data, timeLineBarChartMode, selectedProtocol])
|
||||
|
||||
const bars = useMemo(() => (commandNames || protocolsNamesAndColors).map((entry) => {
|
||||
return <Bar key={entry.name || entry} dataKey={entry.name || entry} stackId="a" fill={entry.color || Utils.stringToColor(entry)} barSize={30} />
|
||||
}), [protocolsNamesAndColors, commandNames])
|
||||
const bars = useMemo(() => (methodsNamesAndColors || protocolsNamesAndColors).map((entry) => {
|
||||
return <Bar key={entry.name} dataKey={entry.name} stackId="a" fill={entry.color} />
|
||||
}), [protocolsNamesAndColors, methodsNamesAndColors])
|
||||
|
||||
const renderTick = (tickProps) => {
|
||||
const { x, y, payload } = tickProps;
|
||||
const { index, value } = payload;
|
||||
|
||||
if (index % 3 === 0) {
|
||||
if (protocolStats.length > 5) {
|
||||
if (index % 3 === 0) {
|
||||
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.barChartContainer}>
|
||||
{protocolStats.length > 0 && <BarChart
|
||||
width={750}
|
||||
height={250}
|
||||
data={commandStats || protocolStats}
|
||||
barCategoryGap={0}
|
||||
barSize={30}
|
||||
data={methodsStats || protocolStats}
|
||||
barCategoryGap={1}
|
||||
margin={{
|
||||
top: 20,
|
||||
right: 30,
|
||||
@@ -92,8 +95,8 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
||||
bottom: 5
|
||||
}}
|
||||
>
|
||||
<XAxis dataKey="timestamp" tick={renderTick} tickLine={false} />
|
||||
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} />
|
||||
<XAxis dataKey="timestamp" tick={renderTick} tickLine={false} interval="preserveStart" />
|
||||
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} interval="preserveEnd"/>
|
||||
<Tooltip formatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value + " Requests"} />
|
||||
{bars}
|
||||
</BarChart>}
|
||||
|
@@ -41,7 +41,7 @@ interface TrafficPieChartProps {
|
||||
export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode, data, selectedProtocol }) => {
|
||||
|
||||
const [protocolsStats, setProtocolsStats] = useState([]);
|
||||
const [commandStats, setCommandStats] = useState(null);
|
||||
const [methodsStats, setMethodsStats] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
@@ -57,16 +57,17 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProtocol === ALL_PROTOCOLS) {
|
||||
setCommandStats(null);
|
||||
setMethodsStats(null);
|
||||
return;
|
||||
}
|
||||
const commandsPieData = data.find(protocol => protocol.name === selectedProtocol)?.methods.map(command => {
|
||||
const methodsPieData = data.find(protocol => protocol.name === selectedProtocol)?.methods.map(method => {
|
||||
return {
|
||||
name: command.name,
|
||||
value: command[PieChartMode[pieChartMode]]
|
||||
name: method.name,
|
||||
value: method[PieChartMode[pieChartMode]],
|
||||
color: method.color
|
||||
}
|
||||
})
|
||||
setCommandStats(commandsPieData);
|
||||
setMethodsStats(methodsPieData);
|
||||
}, [selectedProtocol, pieChartMode, data])
|
||||
|
||||
const pieLegend = useMemo(() => {
|
||||
@@ -82,7 +83,7 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
} else {
|
||||
legend = data.find(protocol => protocol.name === selectedProtocol)?.methods.map((method) => <div
|
||||
style={{ marginBottom: 5, display: "flex" }}>
|
||||
<div style={{ height: 15, width: 30, background: Utils.stringToColor(method.name)}} />
|
||||
<div style={{ height: 15, width: 30, background: method.color}} />
|
||||
<span style={{ marginLeft: 5 }}>
|
||||
{method.name}
|
||||
</span>
|
||||
@@ -96,7 +97,7 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
{protocolsStats?.length > 0 && <div style={{ width: "100%", display: "flex", justifyContent: "center" }}>
|
||||
<PieChart width={300} height={300}>
|
||||
<Pie
|
||||
data={commandStats || protocolsStats}
|
||||
data={methodsStats || protocolsStats}
|
||||
dataKey="value"
|
||||
cx={150}
|
||||
cy={125}
|
||||
@@ -104,8 +105,8 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
label={renderCustomizedLabel}
|
||||
outerRadius={125}
|
||||
fill="#8884d8">
|
||||
{(commandStats || protocolsStats).map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color || Utils.stringToColor(entry.name)} />)
|
||||
{(methodsStats || protocolsStats).map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color} />)
|
||||
)}
|
||||
</Pie>
|
||||
<Legend wrapperStyle={{ position: "absolute", width: "auto", height: "auto", right: -150, top: 0 }} content={pieLegend} />
|
||||
|
@@ -33,9 +33,7 @@ interface TrafficStatsModalProps {
|
||||
getTrafficStatsDataApi: () => Promise<any>
|
||||
}
|
||||
|
||||
|
||||
export const PROTOCOLS = ["ALL", "gRPC", "REDIS", "HTTP", "GQL", "AMQP", "KAFKA"];
|
||||
export const ALL_PROTOCOLS = PROTOCOLS[0];
|
||||
export const ALL_PROTOCOLS = "ALL";
|
||||
|
||||
export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, onClose, getTrafficStatsDataApi }) => {
|
||||
|
||||
@@ -44,6 +42,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
|
||||
const [selectedProtocol, setSelectedProtocol] = useState(ALL_PROTOCOLS);
|
||||
const [pieStatsData, setPieStatsData] = useState(null);
|
||||
const [timelineStatsData, setTimelineStatsData] = useState(null);
|
||||
const [protocols, setProtocols] = useState([])
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const commonClasses = useCommonStyles();
|
||||
|
||||
@@ -55,6 +54,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
|
||||
const statsData = await getTrafficStatsDataApi();
|
||||
setPieStatsData(statsData.pie);
|
||||
setTimelineStatsData(statsData.timeline);
|
||||
setProtocols(statsData.protocols)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
@@ -109,7 +109,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
|
||||
<div>
|
||||
<span style={{ marginRight: 15 }}>Protocol</span>
|
||||
<select className={styles.select} value={selectedProtocol} onChange={(e) => setSelectedProtocol(e.target.value)}>
|
||||
{PROTOCOLS.map(protocol => <option key={protocol} value={protocol}>{protocol}</option>)}
|
||||
{protocols.map(protocol => <option key={protocol} value={protocol}>{protocol}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -51,17 +51,4 @@ export class Utils {
|
||||
return true;
|
||||
}
|
||||
|
||||
static stringToColor = (str) => {
|
||||
let colors = ["#e51c23", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#5677fc", "#03a9f4", "#00bcd4", "#009688", "#259b24", "#8bc34a", "#afb42b", "#ff9800", "#ff5722", "#795548", "#607d8b"]
|
||||
|
||||
let hash = 0;
|
||||
if (str.length === 0) return hash;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
hash = hash & hash;
|
||||
}
|
||||
hash = ((hash % colors.length) + colors.length) % colors.length;
|
||||
return colors[hash];
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user