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:
gadotroee 2022-07-05 15:30:39 +03:00 committed by GitHub
parent 52c9251c00
commit ec11b21b51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 95 deletions

View File

@ -1,6 +1,9 @@
package providers package providers
import ( import (
"crypto/md5"
"encoding/hex"
"fmt"
"reflect" "reflect"
"strings" "strings"
"sync" "sync"
@ -36,13 +39,13 @@ type SizeAndEntriesCount struct {
type AccumulativeStatsCounter struct { type AccumulativeStatsCounter struct {
Name string `json:"name"` Name string `json:"name"`
Color string `json:"color"`
EntriesCount int `json:"entriesCount"` EntriesCount int `json:"entriesCount"`
VolumeSizeBytes int `json:"volumeSizeBytes"` VolumeSizeBytes int `json:"volumeSizeBytes"`
} }
type AccumulativeStatsProtocol struct { type AccumulativeStatsProtocol struct {
AccumulativeStatsCounter AccumulativeStatsCounter
Color string `json:"color"`
Methods []*AccumulativeStatsCounter `json:"methods"` Methods []*AccumulativeStatsCounter `json:"methods"`
} }
@ -52,6 +55,7 @@ type AccumulativeStatsProtocolTime struct {
} }
type TrafficStatsResponse struct { type TrafficStatsResponse struct {
Protocols []string `json:"protocols"`
PieStats []*AccumulativeStatsProtocol `json:"pie"` PieStats []*AccumulativeStatsProtocol `json:"pie"`
TimelineStats []*AccumulativeStatsProtocolTime `json:"timeline"` TimelineStats []*AccumulativeStatsProtocolTime `json:"timeline"`
} }
@ -78,20 +82,36 @@ func GetGeneralStats() *GeneralStats {
func InitProtocolToColor(protocolMap map[string]*api.Protocol) { func InitProtocolToColor(protocolMap map[string]*api.Protocol) {
for item, value := range protocolMap { for item, value := range protocolMap {
protocolToColor[strings.Split(item, "/")[2]] = value.BackgroundColor splitted := strings.SplitN(item, "/", 3)
protocolToColor[splitted[len(splitted)-1]] = value.BackgroundColor
} }
} }
func GetTrafficStats() *TrafficStatsResponse { func GetTrafficStats() *TrafficStatsResponse {
bucketsStatsCopy := getBucketStatsCopy() bucketsStatsCopy := getBucketStatsCopy()
interval := calculateInterval(bucketsStatsCopy[0].BucketTime.Unix(), bucketsStatsCopy[len(bucketsStatsCopy)-1].BucketTime.Unix()) // in seconds
return &TrafficStatsResponse{ return &TrafficStatsResponse{
Protocols: getAvailableProtocols(bucketsStatsCopy),
PieStats: getAccumulativeStats(bucketsStatsCopy), PieStats: getAccumulativeStats(bucketsStatsCopy),
TimelineStats: getAccumulativeStatsTiming(bucketsStatsCopy, interval), TimelineStats: getAccumulativeStatsTiming(bucketsStatsCopy),
} }
} }
func EntryAdded(size int, summery *api.BaseEntry) {
generalStats.EntriesCount++
generalStats.EntriesVolumeInGB += float64(size) / (1 << 30)
currentTimestamp := int(time.Now().Unix())
if reflect.Value.IsZero(reflect.ValueOf(generalStats.FirstEntryTimestamp)) {
generalStats.FirstEntryTimestamp = currentTimestamp
}
addToBucketStats(size, summery)
generalStats.LastEntryTimestamp = currentTimestamp
}
func calculateInterval(firstTimestamp int64, lastTimestamp int64) time.Duration { func calculateInterval(firstTimestamp int64, lastTimestamp int64) time.Duration {
validDurations := []time.Duration{ validDurations := []time.Duration{
time.Minute, time.Minute,
@ -140,31 +160,17 @@ func getAccumulativeStats(stats BucketStats) []*AccumulativeStatsProtocol {
return convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated) return convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated)
} }
func getAccumulativeStatsTiming(stats BucketStats, interval time.Duration) []*AccumulativeStatsProtocolTime { func getAccumulativeStatsTiming(stats BucketStats) []*AccumulativeStatsProtocolTime {
if len(stats) == 0 { if len(stats) == 0 {
return make([]*AccumulativeStatsProtocolTime, 0) return make([]*AccumulativeStatsProtocolTime, 0)
} }
methodsPerProtocolPerTimeAggregated := getAggregatedResultTiming(interval, stats) interval := calculateInterval(stats[0].BucketTime.Unix(), stats[len(stats)-1].BucketTime.Unix()) // in seconds
methodsPerProtocolPerTimeAggregated := getAggregatedResultTiming(stats, interval)
return convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated) return convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated)
} }
func EntryAdded(size int, summery *api.BaseEntry) {
generalStats.EntriesCount++
generalStats.EntriesVolumeInGB += float64(size) / (1 << 30)
currentTimestamp := int(time.Now().Unix())
if reflect.Value.IsZero(reflect.ValueOf(generalStats.FirstEntryTimestamp)) {
generalStats.FirstEntryTimestamp = currentTimestamp
}
addToBucketStats(size, summery)
generalStats.LastEntryTimestamp = currentTimestamp
}
func addToBucketStats(size int, summery *api.BaseEntry) { func addToBucketStats(size int, summery *api.BaseEntry) {
entryTimeBucketRounded := getBucketFromTimeStamp(summery.Timestamp) entryTimeBucketRounded := getBucketFromTimeStamp(summery.Timestamp)
@ -207,11 +213,11 @@ func convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggreg
finalResult := make([]*AccumulativeStatsProtocolTime, 0) finalResult := make([]*AccumulativeStatsProtocolTime, 0)
for timeKey, item := range methodsPerProtocolPerTimeAggregated { for timeKey, item := range methodsPerProtocolPerTimeAggregated {
protocolsData := make([]*AccumulativeStatsProtocol, 0) protocolsData := make([]*AccumulativeStatsProtocol, 0)
for protocolName := range item { for protocolName, value := range item {
entriesCount := 0 entriesCount := 0
volumeSizeBytes := 0 volumeSizeBytes := 0
methods := make([]*AccumulativeStatsCounter, 0) methods := make([]*AccumulativeStatsCounter, 0)
for _, methodAccData := range methodsPerProtocolPerTimeAggregated[timeKey][protocolName] { for _, methodAccData := range value {
entriesCount += methodAccData.EntriesCount entriesCount += methodAccData.EntriesCount
volumeSizeBytes += methodAccData.VolumeSizeBytes volumeSizeBytes += methodAccData.VolumeSizeBytes
methods = append(methods, methodAccData) methods = append(methods, methodAccData)
@ -219,10 +225,10 @@ func convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggreg
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{ protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
AccumulativeStatsCounter: AccumulativeStatsCounter{ AccumulativeStatsCounter: AccumulativeStatsCounter{
Name: protocolName, Name: protocolName,
Color: protocolToColor[protocolName],
EntriesCount: entriesCount, EntriesCount: entriesCount,
VolumeSizeBytes: volumeSizeBytes, VolumeSizeBytes: volumeSizeBytes,
}, },
Color: protocolToColor[protocolName],
Methods: methods, Methods: methods,
}) })
} }
@ -248,10 +254,10 @@ func convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated map[string
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{ protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
AccumulativeStatsCounter: AccumulativeStatsCounter{ AccumulativeStatsCounter: AccumulativeStatsCounter{
Name: protocolName, Name: protocolName,
Color: protocolToColor[protocolName],
EntriesCount: entriesCount, EntriesCount: entriesCount,
VolumeSizeBytes: volumeSizeBytes, VolumeSizeBytes: volumeSizeBytes,
}, },
Color: protocolToColor[protocolName],
Methods: methods, Methods: methods,
}) })
} }
@ -269,7 +275,7 @@ func getBucketStatsCopy() BucketStats {
return bucketStatsCopy return bucketStatsCopy
} }
func getAggregatedResultTiming(interval time.Duration, stats BucketStats) map[time.Time]map[string]map[string]*AccumulativeStatsCounter { func getAggregatedResultTiming(stats BucketStats, interval time.Duration) map[time.Time]map[string]map[string]*AccumulativeStatsCounter {
methodsPerProtocolPerTimeAggregated := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{} methodsPerProtocolPerTimeAggregated := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{}
bucketStatsIndex := len(stats) - 1 bucketStatsIndex := len(stats) - 1
@ -289,6 +295,7 @@ func getAggregatedResultTiming(interval time.Duration, stats BucketStats) map[ti
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName]; !ok { if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName] = &AccumulativeStatsCounter{ methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName] = &AccumulativeStatsCounter{
Name: methodName, Name: methodName,
Color: getColorForMethod(protocolName, methodName),
EntriesCount: 0, EntriesCount: 0,
VolumeSizeBytes: 0, VolumeSizeBytes: 0,
} }
@ -303,9 +310,9 @@ func getAggregatedResultTiming(interval time.Duration, stats BucketStats) map[ti
return methodsPerProtocolPerTimeAggregated return methodsPerProtocolPerTimeAggregated
} }
func getAggregatedStats(bucketStatsCopy BucketStats) map[string]map[string]*AccumulativeStatsCounter { func getAggregatedStats(stats BucketStats) map[string]map[string]*AccumulativeStatsCounter {
methodsPerProtocolAggregated := make(map[string]map[string]*AccumulativeStatsCounter, 0) methodsPerProtocolAggregated := make(map[string]map[string]*AccumulativeStatsCounter, 0)
for _, countersOfTimeFrame := range bucketStatsCopy { for _, countersOfTimeFrame := range stats {
for protocolName, value := range countersOfTimeFrame.ProtocolStats { for protocolName, value := range countersOfTimeFrame.ProtocolStats {
for method, countersValue := range value.MethodsStats { for method, countersValue := range value.MethodsStats {
if _, found := methodsPerProtocolAggregated[protocolName]; !found { if _, found := methodsPerProtocolAggregated[protocolName]; !found {
@ -314,6 +321,7 @@ func getAggregatedStats(bucketStatsCopy BucketStats) map[string]map[string]*Accu
if _, found := methodsPerProtocolAggregated[protocolName][method]; !found { if _, found := methodsPerProtocolAggregated[protocolName][method]; !found {
methodsPerProtocolAggregated[protocolName][method] = &AccumulativeStatsCounter{ methodsPerProtocolAggregated[protocolName][method] = &AccumulativeStatsCounter{
Name: method, Name: method,
Color: getColorForMethod(protocolName, method),
EntriesCount: 0, EntriesCount: 0,
VolumeSizeBytes: 0, VolumeSizeBytes: 0,
} }
@ -325,3 +333,25 @@ func getAggregatedStats(bucketStatsCopy BucketStats) map[string]map[string]*Accu
} }
return methodsPerProtocolAggregated return methodsPerProtocolAggregated
} }
func getColorForMethod(protocolName string, methodName string) string {
hash := md5.Sum([]byte(fmt.Sprintf("%v_%v", protocolName, methodName)))
input := hex.EncodeToString(hash[:])
return fmt.Sprintf("#%v", input[:6])
}
func getAvailableProtocols(stats BucketStats) []string {
protocols := map[string]bool{}
for _, countersOfTimeFrame := range stats {
for protocolName := range countersOfTimeFrame.ProtocolStats {
protocols[protocolName] = true
}
}
result := make([]string, 0)
for protocol := range protocols {
result = append(result, protocol)
}
result = append(result, "ALL")
return result
}

View File

@ -2,7 +2,6 @@ package providers
import ( import (
"fmt" "fmt"
"reflect"
"testing" "testing"
"time" "time"
) )
@ -110,8 +109,8 @@ func TestGetAggregatedStatsAllTime(t *testing.T) {
} }
actual := getAggregatedStats(bucketStatsForTest) actual := getAggregatedStats(bucketStatsForTest)
if !reflect.DeepEqual(actual, expected) { if len(actual) != len(expected) {
t.Errorf("unexpected result - expected: %v, actual: %v", 3, len(actual)) t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
} }
} }
@ -195,10 +194,10 @@ func TestGetAggregatedStatsFromSpecificTime(t *testing.T) {
}, },
}, },
} }
actual := getAggregatedResultTiming(time.Minute*5, bucketStatsForTest) actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute*5)
if !reflect.DeepEqual(actual, expected) { if len(actual) != len(expected) {
t.Errorf("unexpected result - expected: %v, actual: %v", 3, len(actual)) t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
} }
} }
@ -291,9 +290,9 @@ func TestGetAggregatedStatsFromSpecificTimeMultipleBuckets(t *testing.T) {
}, },
}, },
} }
actual := getAggregatedResultTiming(time.Minute, bucketStatsForTest) actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute)
if !reflect.DeepEqual(actual, expected) { if len(actual) != len(expected) {
t.Errorf("unexpected result - expected: %v, actual: %v", 3, len(actual)) t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
} }
} }

View File

@ -19,21 +19,21 @@ interface TimelineBarChartProps {
export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarChartMode, data, selectedProtocol }) => { export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarChartMode, data, selectedProtocol }) => {
const [protocolStats, setProtocolStats] = useState([]); const [protocolStats, setProtocolStats] = useState([]);
const [protocolsNamesAndColors, setProtocolsNamesAndColors] = useState([]); const [protocolsNamesAndColors, setProtocolsNamesAndColors] = useState([]);
const [commandStats, setCommandStats] = useState(null); const [methodsStats, setMethodsStats] = useState(null);
const [commandNames, setcommandNames] = useState(null); const [methodsNamesAndColors, setMethodsNamesAndColors] = useState(null);
useEffect(() => { useEffect(() => {
if (!data) return; if (!data) return;
const protocolsBarsData = []; const protocolsBarsData = [];
const prtcNames = []; const prtcNames = [];
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => { data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
let newProtocolbj: { [k: string]: any } = {}; let newProtocolObj: { [k: string]: any } = {};
newProtocolbj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp); newProtocolObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
protocolObj.protocols.forEach(protocol => { protocolObj.protocols.forEach(protocol => {
newProtocolbj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]]; newProtocolObj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
prtcNames.push({ name: protocol.name, color: protocol.color }); prtcNames.push({ name: protocol.name, color: protocol.color });
}) })
protocolsBarsData.push(newProtocolbj); protocolsBarsData.push(newProtocolObj);
}) })
const uniqueObjArray = Utils.creatUniqueObjArrayByProp(prtcNames, "name") const uniqueObjArray = Utils.creatUniqueObjArrayByProp(prtcNames, "name")
setProtocolStats(protocolsBarsData); setProtocolStats(protocolsBarsData);
@ -42,49 +42,52 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
useEffect(() => { useEffect(() => {
if (selectedProtocol === ALL_PROTOCOLS) { if (selectedProtocol === ALL_PROTOCOLS) {
setCommandStats(null); setMethodsStats(null);
setcommandNames(null); setMethodsNamesAndColors(null);
return; return;
} }
const commandsNames = []; const protocolsMethodsNamesAndColors = [];
const protocolsCommands = []; const protocolsMethods = [];
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => { data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
let newCommandlbj: { [k: string]: any } = {}; let newMethodObj: { [k: string]: any } = {};
newCommandlbj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp); newMethodObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(command => { protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(method => {
newCommandlbj[`${command.name}`] = command[StatsMode[timeLineBarChartMode]] newMethodObj[`${method.name}`] = method[StatsMode[timeLineBarChartMode]]
if (commandsNames.indexOf(command.name) === -1) protocolsMethodsNamesAndColors.push({name: method.name, color: method.color});
commandsNames.push(command.name);
}) })
protocolsCommands.push(newCommandlbj); protocolsMethods.push(newMethodObj);
}) })
setcommandNames(commandsNames); const uniqueObjArray = Utils.creatUniqueObjArrayByProp(protocolsMethodsNamesAndColors, "name")
setCommandStats(protocolsCommands); setMethodsNamesAndColors(uniqueObjArray);
setMethodsStats(protocolsMethods);
}, [data, timeLineBarChartMode, selectedProtocol]) }, [data, timeLineBarChartMode, selectedProtocol])
const bars = useMemo(() => (commandNames || protocolsNamesAndColors).map((entry) => { const bars = useMemo(() => (methodsNamesAndColors || protocolsNamesAndColors).map((entry) => {
return <Bar key={entry.name || entry} dataKey={entry.name || entry} stackId="a" fill={entry.color || Utils.stringToColor(entry)} barSize={30} /> return <Bar key={entry.name} dataKey={entry.name} stackId="a" fill={entry.color} />
}), [protocolsNamesAndColors, commandNames]) }), [protocolsNamesAndColors, methodsNamesAndColors])
const renderTick = (tickProps) => { const renderTick = (tickProps) => {
const { x, y, payload } = tickProps; const { x, y, payload } = tickProps;
const { index, value } = payload; const { index, value } = payload;
if (protocolStats.length > 5) {
if (index % 3 === 0) { if (index % 3 === 0) {
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>; return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
} }
return null; return null;
}
else {
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
}
}; };
return ( return (
<div className={styles.barChartContainer}> <div className={styles.barChartContainer}>
{protocolStats.length > 0 && <BarChart {protocolStats.length > 0 && <BarChart
width={750} width={750}
height={250} height={250}
data={commandStats || protocolStats} data={methodsStats || protocolStats}
barCategoryGap={0} barCategoryGap={1}
barSize={30}
margin={{ margin={{
top: 20, top: 20,
right: 30, right: 30,
@ -92,8 +95,8 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
bottom: 5 bottom: 5
}} }}
> >
<XAxis dataKey="timestamp" tick={renderTick} tickLine={false} /> <XAxis dataKey="timestamp" tick={renderTick} tickLine={false} interval="preserveStart" />
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} /> <YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} interval="preserveEnd"/>
<Tooltip formatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value + " Requests"} /> <Tooltip formatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value + " Requests"} />
{bars} {bars}
</BarChart>} </BarChart>}

View File

@ -41,7 +41,7 @@ interface TrafficPieChartProps {
export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode, data, selectedProtocol }) => { export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode, data, selectedProtocol }) => {
const [protocolsStats, setProtocolsStats] = useState([]); const [protocolsStats, setProtocolsStats] = useState([]);
const [commandStats, setCommandStats] = useState(null); const [methodsStats, setMethodsStats] = useState(null);
useEffect(() => { useEffect(() => {
if (!data) return; if (!data) return;
@ -57,16 +57,17 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
useEffect(() => { useEffect(() => {
if (selectedProtocol === ALL_PROTOCOLS) { if (selectedProtocol === ALL_PROTOCOLS) {
setCommandStats(null); setMethodsStats(null);
return; return;
} }
const commandsPieData = data.find(protocol => protocol.name === selectedProtocol)?.methods.map(command => { const methodsPieData = data.find(protocol => protocol.name === selectedProtocol)?.methods.map(method => {
return { return {
name: command.name, name: method.name,
value: command[PieChartMode[pieChartMode]] value: method[PieChartMode[pieChartMode]],
color: method.color
} }
}) })
setCommandStats(commandsPieData); setMethodsStats(methodsPieData);
}, [selectedProtocol, pieChartMode, data]) }, [selectedProtocol, pieChartMode, data])
const pieLegend = useMemo(() => { const pieLegend = useMemo(() => {
@ -82,7 +83,7 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
} else { } else {
legend = data.find(protocol => protocol.name === selectedProtocol)?.methods.map((method) => <div legend = data.find(protocol => protocol.name === selectedProtocol)?.methods.map((method) => <div
style={{ marginBottom: 5, display: "flex" }}> 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 }}> <span style={{ marginLeft: 5 }}>
{method.name} {method.name}
</span> </span>
@ -96,7 +97,7 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
{protocolsStats?.length > 0 && <div style={{ width: "100%", display: "flex", justifyContent: "center" }}> {protocolsStats?.length > 0 && <div style={{ width: "100%", display: "flex", justifyContent: "center" }}>
<PieChart width={300} height={300}> <PieChart width={300} height={300}>
<Pie <Pie
data={commandStats || protocolsStats} data={methodsStats || protocolsStats}
dataKey="value" dataKey="value"
cx={150} cx={150}
cy={125} cy={125}
@ -104,8 +105,8 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
label={renderCustomizedLabel} label={renderCustomizedLabel}
outerRadius={125} outerRadius={125}
fill="#8884d8"> fill="#8884d8">
{(commandStats || protocolsStats).map((entry, index) => ( {(methodsStats || protocolsStats).map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color || Utils.stringToColor(entry.name)} />) <Cell key={`cell-${index}`} fill={entry.color} />)
)} )}
</Pie> </Pie>
<Legend wrapperStyle={{ position: "absolute", width: "auto", height: "auto", right: -150, top: 0 }} content={pieLegend} /> <Legend wrapperStyle={{ position: "absolute", width: "auto", height: "auto", right: -150, top: 0 }} content={pieLegend} />

View File

@ -33,9 +33,7 @@ interface TrafficStatsModalProps {
getTrafficStatsDataApi: () => Promise<any> getTrafficStatsDataApi: () => Promise<any>
} }
export const ALL_PROTOCOLS = "ALL";
export const PROTOCOLS = ["ALL", "gRPC", "REDIS", "HTTP", "GQL", "AMQP", "KAFKA"];
export const ALL_PROTOCOLS = PROTOCOLS[0];
export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, onClose, getTrafficStatsDataApi }) => { 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 [selectedProtocol, setSelectedProtocol] = useState(ALL_PROTOCOLS);
const [pieStatsData, setPieStatsData] = useState(null); const [pieStatsData, setPieStatsData] = useState(null);
const [timelineStatsData, setTimelineStatsData] = useState(null); const [timelineStatsData, setTimelineStatsData] = useState(null);
const [protocols, setProtocols] = useState([])
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const commonClasses = useCommonStyles(); const commonClasses = useCommonStyles();
@ -55,6 +54,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
const statsData = await getTrafficStatsDataApi(); const statsData = await getTrafficStatsDataApi();
setPieStatsData(statsData.pie); setPieStatsData(statsData.pie);
setTimelineStatsData(statsData.timeline); setTimelineStatsData(statsData.timeline);
setProtocols(statsData.protocols)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} finally { } finally {
@ -109,7 +109,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
<div> <div>
<span style={{ marginRight: 15 }}>Protocol</span> <span style={{ marginRight: 15 }}>Protocol</span>
<select className={styles.select} value={selectedProtocol} onChange={(e) => setSelectedProtocol(e.target.value)}> <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> </select>
</div> </div>
</div> </div>

View File

@ -51,17 +51,4 @@ export class Utils {
return true; 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];
}
} }