From 94feb2b4b76568a06dfd88de24f2ca8943062802 Mon Sep 17 00:00:00 2001 From: "Kyriakos (Dominick) Sidiropoulos" Date: Thu, 26 May 2022 00:18:55 +0200 Subject: [PATCH] #69 new flag --display-subscriptions-column (#70) * chore (.gitignore): ignore .vscode folder and any *.code-workspace files * feat (--version): add support for printing version via the --version flag * feat (--display-subscriptions-column): new flag * feat (version): bump to 0.5.3 (old was: 0.5.2) * fix (csv output): when emitting csv output via '-o' the subs will be printed separated by whitespace chars instead of ',' because the ',' is frequently reserved to separate entire csv-columns in the resulting output * fix (nats-top.go): fix a bug which was causing the SUBSCRIPTIONS column to not be delimiter-separator when the --display-subscriptions-column flag would be used in conjunction with -o Co-authored-by: Kyriakos Sidiropoulos --- nats-top.go | 75 +++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/nats-top.go b/nats-top.go index 84d7135..1923681 100644 --- a/nats-top.go +++ b/nats-top.go @@ -15,20 +15,21 @@ import ( ui "gopkg.in/gizak/termui.v1" ) -const version = "0.5.2" +const version = "0.5.3" var ( - host = flag.String("s", "127.0.0.1", "The nats server host.") - port = flag.Int("m", 8222, "The NATS server monitoring port.") - conns = flag.Int("n", 1024, "Maximum number of connections to poll.") - delay = flag.Int("d", 1, "Refresh interval in seconds.") - sortBy = flag.String("sort", "cid", "Value for which to sort by the connections.") - lookupDNS = flag.Bool("lookup", false, "Enable client addresses DNS lookup.") - outputFile = flag.String("o", "", "Save the very first nats-top snapshot to the given file and exit. If '-' is passed then the snapshot is printed the standard output.") - showVersion = flag.Bool("v", false, "Show nats-top version.") - outputDelimiter = flag.String("l", "", "Specifies the delimiter to use for the output file when the '-o' parameter is used. By default this option is unset which means that standard grid-like plain-text output will be used.") - displayRawBytes = flag.Bool("b", false, "Display traffic in raw bytes.") - maxStatsRefreshes = flag.Int("r", -1, "Specifies the maximum number of times nats-top should refresh nats-stats before exiting.") + host = flag.String("s", "127.0.0.1", "The nats server host.") + port = flag.Int("m", 8222, "The NATS server monitoring port.") + conns = flag.Int("n", 1024, "Maximum number of connections to poll.") + delay = flag.Int("d", 1, "Refresh interval in seconds.") + sortBy = flag.String("sort", "cid", "Value for which to sort by the connections.") + lookupDNS = flag.Bool("lookup", false, "Enable client addresses DNS lookup.") + outputFile = flag.String("o", "", "Save the very first nats-top snapshot to the given file and exit. If '-' is passed then the snapshot is printed the standard output.") + showVersion = false + outputDelimiter = flag.String("l", "", "Specifies the delimiter to use for the output file when the '-o' parameter is used. By default this option is unset which means that standard grid-like plain-text output will be used.") + displayRawBytes = flag.Bool("b", false, "Display traffic in raw bytes.") + maxStatsRefreshes = flag.Int("r", -1, "Specifies the maximum number of times nats-top should refresh nats-stats before exiting.") + displaySubscriptionsColumn = flag.Bool("display-subscriptions-column", false, "Display subscriptions column upon launch.") // Secure options httpsPort = flag.Int("ms", 0, "The NATS server secure monitoring port.") @@ -40,7 +41,7 @@ var ( const usageHelp = ` usage: nats-top [-s server] [-m http_port] [-ms https_port] [-n num_connections] [-d delay_secs] [-r max] [-o FILE] [-l DELIMITER] [-sort by] - [-cert FILE] [-key FILE ][-cacert FILE] [-k] [-b] + [-cert FILE] [-key FILE] [-cacert FILE] [-k] [-b] [-v|--version] [-display-subscriptions-column] ` @@ -49,14 +50,16 @@ func usage() { } func init() { + flag.BoolVar(&showVersion, "v", false, "Same as --version.") + flag.BoolVar(&showVersion, "version", false, "Show nats-top version.") + log.SetFlags(0) flag.Usage = usage flag.Parse() } func main() { - - if *showVersion { + if showVersion { log.Printf("nats-top v%s", version) os.Exit(0) } @@ -100,6 +103,10 @@ func main() { } engine.SortOpt = sortOpt + if *displaySubscriptionsColumn { + engine.DisplaySubs = true + } + if *outputFile != "" { saveStatsSnapshotToFile(engine, outputFile, *outputDelimiter) return @@ -297,11 +304,10 @@ func generateParagraphPlainText( var connRows string if displaySubs { header = append(header, "SUBSCRIPTIONS") - connRows = fmt.Sprintf(connHeader, header...) - } else { - connRows = fmt.Sprintf(connHeader, header...) } + connRows = fmt.Sprintf(connHeader, header...) + text += connRows // Add to screen! connValues := DEFAULT_PADDING @@ -403,6 +409,7 @@ func generateParagraphCSV( inMsgs, inBytes, inMsgsRate, inBytesRate, outMsgs, outBytes, outMsgsRate, outBytesRate, ) + text += fmt.Sprintf("\n\nConnections Polled:[__DELIM__]%d\n", numConns) displaySubs := engine.DisplaySubs @@ -442,8 +449,9 @@ func generateParagraphCSV( header = append(header, standardHeaders...) connHeader += strings.Join(defaultHeaderAndRowColumnsForCsv, "[__DELIM__]") + if displaySubs { - connHeader += "%s" + connHeader += "[__DELIM__]%s" // SUBSCRIPTIONS } connHeader += "\n" // ...LAST ACTIVITY @@ -485,14 +493,14 @@ func generateParagraphCSV( connLineInfo = append(connLineInfo, conn.Uptime, conn.LastActivity) if displaySubs { - subs := strings.Join(conn.Subs, "[__DELIM__]") + subs := "[__DELIM__]" + strings.Join(conn.Subs, " ") // its safer to use a couple of whitespaces instead of commas to separate the subs because comma is reserved to separate entire columns! connLineInfo = append(connLineInfo, subs) } - text += fmt.Sprintf(connValues, connLineInfo...) // Add line to screen! + text += fmt.Sprintf(connValues, connLineInfo...) } - text = strings.Replace(text, "[__DELIM__]", delimiter, -1) + text = strings.ReplaceAll(text, "[__DELIM__]", delimiter) return text } @@ -567,7 +575,6 @@ func StartUI(engine *top.Engine) { // Flags for capturing options waitingSortOption := false waitingLimitOption := false - displaySubscriptions := false optionBuf := "" refreshOptionHeader := func() { @@ -659,13 +666,7 @@ func StartUI(engine *top.Engine) { } if e.Type == ui.EventKey && e.Ch == 's' && !(waitingLimitOption || waitingSortOption) { - if displaySubscriptions { - displaySubscriptions = false - engine.DisplaySubs = false - } else { - displaySubscriptions = true - engine.DisplaySubs = true - } + engine.DisplaySubs = !engine.DisplaySubs } if e.Type == ui.EventKey && viewMode == HelpViewMode { @@ -697,21 +698,11 @@ func StartUI(engine *top.Engine) { } if e.Type == ui.EventKey && (e.Ch == 'd') && !(waitingSortOption || waitingLimitOption) { - switch *lookupDNS { - case true: - *lookupDNS = false - case false: - *lookupDNS = true - } + *lookupDNS = !*lookupDNS } if e.Type == ui.EventKey && (e.Ch == 'b') && !(waitingSortOption || waitingLimitOption) { - switch *displayRawBytes { - case true: - *displayRawBytes = false - case false: - *displayRawBytes = true - } + *displayRawBytes = !*displayRawBytes } if e.Type == ui.EventResize {