package main import ( "fmt" "io" "sort" "github.com/aquasecurity/table" log "github.com/sirupsen/logrus" ) func lapiMetricsToTable(t *table.Table, stats map[string]map[string]map[string]int) int { // stats: machine -> route -> method -> count // sort keys to keep consistent order when printing machineKeys := []string{} for k := range stats { machineKeys = append(machineKeys, k) } sort.Strings(machineKeys) numRows := 0 for _, machine := range machineKeys { // oneRow: route -> method -> count machineRow := stats[machine] for routeName, route := range machineRow { for methodName, count := range route { row := []string{ machine, routeName, methodName, } if count != 0 { row = append(row, fmt.Sprintf("%d", count)) } else { row = append(row, "-") } t.AddRow(row...) numRows++ } } } return numRows } func metricsToTable(t *table.Table, stats map[string]map[string]int, keys []string) (int, error) { if t == nil { return 0, fmt.Errorf("nil table") } // sort keys to keep consistent order when printing sortedKeys := []string{} for k := range stats { sortedKeys = append(sortedKeys, k) } sort.Strings(sortedKeys) numRows := 0 for _, alabel := range sortedKeys { astats, ok := stats[alabel] if !ok { continue } row := []string{ alabel, } for _, sl := range keys { if v, ok := astats[sl]; ok && v != 0 { numberToShow := fmt.Sprintf("%d", v) if !noUnit { numberToShow = formatNumber(v) } row = append(row, numberToShow) } else { row = append(row, "-") } } t.AddRow(row...) numRows++ } return numRows, nil } func bucketStatsTable(out io.Writer, stats map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Bucket", "Current Count", "Overflows", "Instantiated", "Poured", "Expired") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) keys := []string{"curr_count", "overflow", "instantiation", "pour", "underflow"} if numRows, err := metricsToTable(t, stats, keys); err != nil { log.Warningf("while collecting acquis stats: %s", err) } else if numRows > 0 { renderTableTitle(out, "\nBucket Metrics:") t.Render() } } func acquisStatsTable(out io.Writer, stats map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Source", "Lines read", "Lines parsed", "Lines unparsed", "Lines poured to bucket") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) keys := []string{"reads", "parsed", "unparsed", "pour"} if numRows, err := metricsToTable(t, stats, keys); err != nil { log.Warningf("while collecting acquis stats: %s", err) } else if numRows > 0 { renderTableTitle(out, "\nAcquisition Metrics:") t.Render() } } func parserStatsTable(out io.Writer, stats map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Parsers", "Hits", "Parsed", "Unparsed") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) keys := []string{"hits", "parsed", "unparsed"} if numRows, err := metricsToTable(t, stats, keys); err != nil { log.Warningf("while collecting acquis stats: %s", err) } else if numRows > 0 { renderTableTitle(out, "\nParser Metrics:") t.Render() } } func lapiStatsTable(out io.Writer, stats map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Route", "Method", "Hits") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft) // unfortunately, we can't reuse metricsToTable as the structure is too different :/ sortedKeys := []string{} for k := range stats { sortedKeys = append(sortedKeys, k) } sort.Strings(sortedKeys) numRows := 0 for _, alabel := range sortedKeys { astats := stats[alabel] subKeys := []string{} for skey := range astats { subKeys = append(subKeys, skey) } sort.Strings(subKeys) for _, sl := range subKeys { row := []string{ alabel, sl, fmt.Sprintf("%d", astats[sl]), } t.AddRow(row...) numRows++ } } if numRows > 0 { renderTableTitle(out, "\nLocal Api Metrics:") t.Render() } } func lapiMachineStatsTable(out io.Writer, stats map[string]map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Machine", "Route", "Method", "Hits") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) numRows := lapiMetricsToTable(t, stats) if numRows > 0 { renderTableTitle(out, "\nLocal Api Machines Metrics:") t.Render() } } func lapiBouncerStatsTable(out io.Writer, stats map[string]map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Bouncer", "Route", "Method", "Hits") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) numRows := lapiMetricsToTable(t, stats) if numRows > 0 { renderTableTitle(out, "\nLocal Api Bouncers Metrics:") t.Render() } } func lapiDecisionStatsTable(out io.Writer, stats map[string]struct { NonEmpty int Empty int }, ) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Bouncer", "Empty answers", "Non-empty answers") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft) numRows := 0 for bouncer, hits := range stats { t.AddRow( bouncer, fmt.Sprintf("%d", hits.Empty), fmt.Sprintf("%d", hits.NonEmpty), ) numRows++ } if numRows > 0 { renderTableTitle(out, "\nLocal Api Bouncers Decisions:") t.Render() } } func decisionStatsTable(out io.Writer, stats map[string]map[string]map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Reason", "Origin", "Action", "Count") t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) numRows := 0 for reason, origins := range stats { for origin, actions := range origins { for action, hits := range actions { t.AddRow( reason, origin, action, fmt.Sprintf("%d", hits), ) numRows++ } } } if numRows > 0 { renderTableTitle(out, "\nLocal Api Decisions:") t.Render() } } func alertStatsTable(out io.Writer, stats map[string]int) { t := newTable(out) t.SetRowLines(false) t.SetHeaders("Reason", "Count") t.SetAlignment(table.AlignLeft, table.AlignLeft) numRows := 0 for scenario, hits := range stats { t.AddRow( scenario, fmt.Sprintf("%d", hits), ) numRows++ } if numRows > 0 { renderTableTitle(out, "\nLocal Api Alerts:") t.Render() } }