package protocol import ( "fmt" "sort" "strings" "text/tabwriter" ) type Cluster struct { ClusterID string Controller int32 Brokers map[int32]Broker Topics map[string]Topic } func (c Cluster) BrokerIDs() []int32 { brokerIDs := make([]int32, 0, len(c.Brokers)) for id := range c.Brokers { brokerIDs = append(brokerIDs, id) } sort.Slice(brokerIDs, func(i, j int) bool { return brokerIDs[i] < brokerIDs[j] }) return brokerIDs } func (c Cluster) TopicNames() []string { topicNames := make([]string, 0, len(c.Topics)) for name := range c.Topics { topicNames = append(topicNames, name) } sort.Strings(topicNames) return topicNames } func (c Cluster) IsZero() bool { return c.ClusterID == "" && c.Controller == 0 && len(c.Brokers) == 0 && len(c.Topics) == 0 } func (c Cluster) Format(w fmt.State, _ rune) { tw := new(tabwriter.Writer) fmt.Fprintf(w, "CLUSTER: %q\n\n", c.ClusterID) tw.Init(w, 0, 8, 2, ' ', 0) fmt.Fprint(tw, " BROKER\tHOST\tPORT\tRACK\tCONTROLLER\n") for _, id := range c.BrokerIDs() { broker := c.Brokers[id] fmt.Fprintf(tw, " %d\t%s\t%d\t%s\t%t\n", broker.ID, broker.Host, broker.Port, broker.Rack, broker.ID == c.Controller) } tw.Flush() fmt.Fprintln(w) tw.Init(w, 0, 8, 2, ' ', 0) fmt.Fprint(tw, " TOPIC\tPARTITIONS\tBROKERS\n") topicNames := c.TopicNames() brokers := make(map[int32]struct{}, len(c.Brokers)) brokerIDs := make([]int32, 0, len(c.Brokers)) for _, name := range topicNames { topic := c.Topics[name] for _, p := range topic.Partitions { for _, id := range p.Replicas { brokers[id] = struct{}{} } } for id := range brokers { brokerIDs = append(brokerIDs, id) } fmt.Fprintf(tw, " %s\t%d\t%s\n", topic.Name, len(topic.Partitions), formatBrokerIDs(brokerIDs, -1)) for id := range brokers { delete(brokers, id) } brokerIDs = brokerIDs[:0] } tw.Flush() fmt.Fprintln(w) if w.Flag('+') { for _, name := range topicNames { fmt.Fprintf(w, " TOPIC: %q\n\n", name) tw.Init(w, 0, 8, 2, ' ', 0) fmt.Fprint(tw, " PARTITION\tREPLICAS\tISR\tOFFLINE\n") for _, p := range c.Topics[name].Partitions { fmt.Fprintf(tw, " %d\t%s\t%s\t%s\n", p.ID, formatBrokerIDs(p.Replicas, -1), formatBrokerIDs(p.ISR, p.Leader), formatBrokerIDs(p.Offline, -1), ) } tw.Flush() fmt.Fprintln(w) } } } func formatBrokerIDs(brokerIDs []int32, leader int32) string { if len(brokerIDs) == 0 { return "" } if len(brokerIDs) == 1 { return itoa(brokerIDs[0]) } sort.Slice(brokerIDs, func(i, j int) bool { id1 := brokerIDs[i] id2 := brokerIDs[j] if id1 == leader { return true } if id2 == leader { return false } return id1 < id2 }) brokerNames := make([]string, len(brokerIDs)) for i, id := range brokerIDs { brokerNames[i] = itoa(id) } return strings.Join(brokerNames, ",") } var ( _ fmt.Formatter = Cluster{} )