Skip to content

Commit

Permalink
Merged pull request influxdata#1018 from influxdata/nc-cli-widths
Browse files Browse the repository at this point in the history
Sort and dynamically adjust column widths in CLI output
  • Loading branch information
nathanielc committed Nov 4, 2016
2 parents 0eb8c34 + 07c34d6 commit 4dae25d
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ See the API docs for more details.
- [#984](https://github.com/influxdata/kapacitor/issues/984): Fix bug where keeping a list of fields that where not referenced in the eval expressions would cause an error.
- [#955](https://github.com/influxdata/kapacitor/issues/955): Fix the number of subscriptions statistic.
- [#999](https://github.com/influxdata/kapacitor/issues/999): Fix inconsistency with InfluxDB by adding config option to set a default retention policy.
- [#1018](https://github.com/influxdata/kapacitor/pull/1018): Sort and dynamically adjust column width in CLI output. Fixes #785

## v1.0.2 [2016-10-06]

Expand Down
162 changes: 135 additions & 27 deletions cmd/kapacitor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,18 @@ If no ID or pattern is given then all items will be listed.
fmt.Fprintln(os.Stderr, u)
}

type TaskList []client.Task

func (t TaskList) Len() int { return len(t) }
func (t TaskList) Less(i, j int) bool { return t[i].ID < t[j].ID }
func (t TaskList) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

type TemplateList []client.Template

func (t TemplateList) Len() int { return len(t) }
func (t TemplateList) Less(i, j int) bool { return t[i].ID < t[j].ID }
func (t TemplateList) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

func doList(args []string) error {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "Must specify 'tasks', 'recordings', or 'replays'")
Expand All @@ -1380,8 +1392,8 @@ func doList(args []string) error {

switch kind := args[0]; kind {
case "tasks":
outFmt := "%-30s%-10v%-10v%-10v%s\n"
fmt.Fprintf(os.Stdout, outFmt, "ID", "Type", "Status", "Executing", "Databases and Retention Policies")
maxID := 2 // len("ID")
var allTasks TaskList
for _, pattern := range patterns {
offset := 0
for {
Expand All @@ -1394,19 +1406,27 @@ func doList(args []string) error {
if err != nil {
return err
}

allTasks = append(allTasks, tasks...)
for _, t := range tasks {
fmt.Fprintf(os.Stdout, outFmt, t.ID, t.Type, t.Status, t.Executing, t.DBRPs)
if l := len(t.ID); l > maxID {
maxID = l
}
}
if len(tasks) != limit {
break
}
offset += limit
}
}
outFmt := fmt.Sprintf("%%-%ds%%-10v%%-10v%%-10v%%s\n", maxID+1)
fmt.Fprintf(os.Stdout, outFmt, "ID", "Type", "Status", "Executing", "Databases and Retention Policies")
sort.Sort(allTasks)
for _, t := range allTasks {
fmt.Fprintf(os.Stdout, outFmt, t.ID, t.Type, t.Status, t.Executing, t.DBRPs)
}
case "templates":
outFmt := "%-30s%-10v%-40v\n"
fmt.Fprintf(os.Stdout, outFmt, "ID", "Type", "Vars")
maxID := 2 // len("ID")
var allTemplates TemplateList
for _, pattern := range patterns {
offset := 0
for {
Expand All @@ -1419,24 +1439,34 @@ func doList(args []string) error {
if err != nil {
return err
}
allTemplates = append(allTemplates, templates...)

for _, t := range templates {
vars := make([]string, 0, len(t.Vars))
for name := range t.Vars {
vars = append(vars, name)
if l := len(t.ID); l > maxID {
maxID = l
}
sort.Strings(vars)
fmt.Fprintf(os.Stdout, outFmt, t.ID, t.Type, strings.Join(vars, ","))
}
if len(templates) != limit {
break
}
offset += limit
}
}
outFmt := fmt.Sprintf("%%-%ds%%-10v%%-40v\n", maxID+1)
fmt.Fprintf(os.Stdout, outFmt, "ID", "Type", "Vars")
sort.Sort(allTemplates)
for _, t := range allTemplates {
vars := make([]string, 0, len(t.Vars))
for name := range t.Vars {
vars = append(vars, name)
}
sort.Strings(vars)
fmt.Fprintf(os.Stdout, outFmt, t.ID, t.Type, strings.Join(vars, ","))
}
case "recordings":
outFmt := "%-40s%-8v%-10s%-10s%-23s\n"
fmt.Fprintf(os.Stdout, outFmt, "ID", "Type", "Status", "Size", "Date")
maxID := 2 // len("ID")
// The recordings are returned in sorted order already, no need to sort them here.
var allRecordings []client.Recording
for _, pattern := range patterns {
offset := 0
for {
Expand All @@ -1449,19 +1479,30 @@ func doList(args []string) error {
if err != nil {
return err
}

allRecordings = append(allRecordings, recordings...)
for _, r := range recordings {
fmt.Fprintf(os.Stdout, outFmt, r.ID, r.Type, r.Status, humanize.Bytes(uint64(r.Size)), r.Date.Local().Format(time.RFC822))
if l := len(r.ID); l > maxID {
maxID = l
}
}

if len(recordings) != limit {
break
}
offset += limit
}
}
outFmt := fmt.Sprintf("%%-%ds%%-8v%%-10s%%-10s%%-23s\n", maxID+1)
fmt.Fprintf(os.Stdout, outFmt, "ID", "Type", "Status", "Size", "Date")
for _, r := range allRecordings {
fmt.Fprintf(os.Stdout, outFmt, r.ID, r.Type, r.Status, humanize.Bytes(uint64(r.Size)), r.Date.Local().Format(time.RFC822))
}
case "replays":
outFmt := "%-40v%-20v%-40v%-9v%-8v%-23v\n"
fmt.Fprintf(os.Stdout, outFmt, "ID", "Task", "Recording", "Status", "Clock", "Date")
maxID := 2 // len("ID")
maxTask := 4 // len("Task")
maxRecording := 9 // len("Recording")
// The replays are returned in sorted order already, no need to sort them here.
var allReplays []client.Replay
for _, pattern := range patterns {
offset := 0
for {
Expand All @@ -1474,16 +1515,30 @@ func doList(args []string) error {
if err != nil {
return err
}
allReplays = append(allReplays, replays...)

for _, r := range replays {
fmt.Fprintf(os.Stdout, outFmt, r.ID, r.Task, r.Recording, r.Status, r.Clock, r.Date.Local().Format(time.RFC822))
if l := len(r.ID); l > maxID {
maxID = l
}
if l := len(r.Task); l > maxTask {
maxTask = l
}
if l := len(r.Recording); l > maxRecording {
maxRecording = l
}
}
if len(replays) != limit {
break
}
offset += limit
}
}
outFmt := fmt.Sprintf("%%-%dv%%-%dv%%-%dv%%-9v%%-8v%%-23v\n", maxID+1, maxTask+1, maxRecording+1)
fmt.Fprintf(os.Stdout, outFmt, "ID", "Task", "Recording", "Status", "Clock", "Date")
for _, r := range allReplays {
fmt.Fprintf(os.Stdout, outFmt, r.ID, r.Task, r.Recording, r.Status, r.Clock, r.Date.Local().Format(time.RFC822))
}
case "service-tests":
outFmt := "%s\n"
fmt.Fprintf(os.Stdout, outFmt, "Service Name")
Expand Down Expand Up @@ -1664,6 +1719,27 @@ func statsUsage() {
fmt.Fprintln(os.Stderr, u)
}

type IngressStat struct {
Database string
RetentionPolicy string
Measurement string
PointsReceived int64
}

type IngressStatList []IngressStat

func (l IngressStatList) Len() int { return len(l) }
func (l IngressStatList) Less(i, j int) bool {
if di, dj := l[i].Database, l[j].Database; di != dj {
return di < dj
}
if ri, rj := l[i].RetentionPolicy, l[j].RetentionPolicy; ri != rj {
return ri < rj
}
return l[i].Measurement < l[j].Measurement
}
func (l IngressStatList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }

func doStats(args []string) error {
if len(args) != 1 {
statsUsage()
Expand All @@ -1685,23 +1761,55 @@ func doStats(args []string) error {
fmt.Fprintf(os.Stdout, outFmtNum, "Subscriptions:", vars.NumSubscriptions)
fmt.Fprintf(os.Stdout, outFmtStr, "Version:", vars.Version)
case "ingress":
outFmt := "%-30s%-30s%-30s%-20.0f\n"
fmt.Fprintf(os.Stdout, "%-30s%-30s%-30s%-20s\n", "Database", "Retention Policy", "Measurement", "Points Received")
maxDB := 8 // len("Database")
maxRP := 16 // len("Retention Policy")
maxM := 11 // len("Measurement")
var allIngressStats IngressStatList
for _, stat := range vars.Stats {
if stat.Name != "ingress" || stat.Tags["task_master"] != "main" {
continue
}
var pr float64
if i, ok := stat.Values["points_received"].(float64); ok {
pr = i
var pr int64
if f, ok := stat.Values["points_received"].(float64); ok {
pr = int64(f)
}
s := IngressStat{
Database: stat.Tags["database"],
RetentionPolicy: stat.Tags["retention_policy"],
Measurement: stat.Tags["measurement"],
PointsReceived: pr,
}
allIngressStats = append(allIngressStats, s)
if l := len(s.Database); l > maxDB {
maxDB = l
}
if l := len(s.RetentionPolicy); l > maxRP {
maxRP = l
}
if l := len(s.Measurement); l > maxM {
maxM = l
}
}
// Add one space padding
maxRP++
maxDB++
maxM++

// Create outFmt strings
outFmt := fmt.Sprintf("%%-%ds%%-%ds%%-%ds%%15d\n", maxDB, maxRP, maxM)
outFmtHeader := fmt.Sprintf("%%-%ds%%-%ds%%-%ds%%s\n", maxDB, maxRP, maxM)

// Print output
fmt.Fprintf(os.Stdout, outFmtHeader, "Database", "Retention Policy", "Measurement", "Points Received")
sort.Sort(allIngressStats)
for _, s := range allIngressStats {
fmt.Fprintf(
os.Stdout,
outFmt,
stat.Tags["database"],
stat.Tags["retention_policy"],
stat.Tags["measurement"],
pr,
s.Database,
s.RetentionPolicy,
s.Measurement,
s.PointsReceived,
)
}
}
Expand Down

0 comments on commit 4dae25d

Please sign in to comment.