From 70b5bec4deb0c71b533115d1f958b90af1235972 Mon Sep 17 00:00:00 2001 From: "ChrisH (CruftMaster)" Date: Sat, 14 Mar 2015 09:28:33 +0000 Subject: [PATCH] Tidying up: Switching to camelCase, adding some comments, removing some cruft --- DEBIAN/md5sums | 16 ------- display.go | 100 ++++++++++++++++++++-------------------- handlers.go | 17 +++---- main.go | 43 ++++++++++------- metricscollectormx4j.go | 48 +++++++++++-------- sorting.go | 5 ++ 6 files changed, 115 insertions(+), 114 deletions(-) diff --git a/DEBIAN/md5sums b/DEBIAN/md5sums index df64487..e69de29 100644 --- a/DEBIAN/md5sums +++ b/DEBIAN/md5sums @@ -1,16 +0,0 @@ -9f2d62b9104016299653a3d0a26907d8 usr/local/bin/zoo-disencrufter -1775f4b499fc40fb418525318a16aa1d usr/local/bin/zoo-encrufter -b98d7fbf3624e3b81a8f551bc55a5647 usr/local/bin/zoo-nodegetter -e033957321c3cd9fd716177d453b3c89 usr/local/bin/zoo-watcher -07a8e2ec94060cd375c9736699b79870 usr/local/bin/zoo-locker -6438a6dceb527a55ccc2c00730a92f2a usr/share/zoo-disencrufter/zoo-disencrufter.cfg-HAILO-STAGING-GLOBAL02 -31524844d87f1bf308562fd83e971ec2 usr/share/zoo-disencrufter/zoo-disencrufter.cfg-HAILO-TEST-GLOBAL01 -c3bedb047347f2d5038923edec6ccd5e usr/share/zoo-disencrufter/zoo-disencrufter.cfg-CRUFT -a1b9a590b193003547e0697fa49e3998 usr/share/zoo-disencrufter/zoo-disencrufter.cfg-HAILO-STAGING-GLOBAL01 -04ef4a86253fedbb20cc53a8a45833bc usr/share/zoo-disencrufter/zoo-disencrufter.cfg-HAILO-LIVE-GLOBAL01 -7d265d9c39c016f19d5dd88e572a7133 usr/share/zoo-disencrufter/zoo-disencrufter.cfg-HAILO-TEST-GLOBAL02 -a5d643862153f2b3cc3dcb03801ab3a1 usr/share/zoo-disencrufter/zoo-disencrufter.cfg-HAILO-LIVE-GLOBAL02 -670f666e4b7f37d771ce204e5c432aef etc/.DS_Store -68c5df9c57c6f5db62801d64a7b48a77 etc/cron.d/zoo-disencrufter -a057902a60540c7532bf72ced7912f97 etc/cron.d/ubuntu-zookeeper -1251a0f35df20303261799102a0635ef etc/zoo-disencrufter.cfg diff --git a/display.go b/display.go index 840c803..0160dc4 100644 --- a/display.go +++ b/display.go @@ -1,46 +1,44 @@ package main import ( - // "flag" "fmt" "github.com/nsf/termbox-go" "time" - // "os" ) // Reads log-messages out of the logMessage chan and displays them to screen: -func show_logs() { +func showLogs() { termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) - printf_tb(2, 1, messageForeGroundColour, termbox.ColorBlack, " |") - printf_tb(2, 1, messageForeGroundColour|termbox.AttrBold, termbox.ColorBlack, "Severity") - printf_tb(13, 1, messageForeGroundColour|termbox.AttrBold, termbox.ColorBlack, "Message") + printfTb(2, 1, messageForeGroundColour, termbox.ColorBlack, " |") + printfTb(2, 1, messageForeGroundColour|termbox.AttrBold, termbox.ColorBlack, "Severity") + printfTb(13, 1, messageForeGroundColour|termbox.AttrBold, termbox.ColorBlack, "Message") for y := 2; y < termHeight; y++ { select { // attempt to receive from channel: case logMessage := <-messageChannel: - printf_tb(2, y, messageForeGroundColour, termbox.ColorBlack, "%s", logMessage.Severity) - printf_tb(13, y, messageForeGroundColour, termbox.ColorBlack, "%s", logMessage.Message) + printfTb(2, y, messageForeGroundColour, termbox.ColorBlack, "%s", logMessage.Severity) + printfTb(13, y, messageForeGroundColour, termbox.ColorBlack, "%s", logMessage.Message) default: - printf_tb(2, y, messageForeGroundColour, termbox.ColorBlack, "No more logs") + printfTb(2, y, messageForeGroundColour, termbox.ColorBlack, "No more logs") return } } } // Draws stats on the screen: -func show_stats() { +func showStats() { termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) // Positions: 2 22 42 52 63 79 94 - printf_tb(2, 1, messageForeGroundColour|termbox.AttrBold, termbox.ColorBlack, "KeySpace ColumnFamily Reads/s Writes/s LiveSpace(B) R-Latency(ms) W-Latency(ms)") - printf_tb(20, 1, messageForeGroundColour, termbox.ColorBlack, "|") - printf_tb(40, 1, messageForeGroundColour, termbox.ColorBlack, "|") - printf_tb(50, 1, messageForeGroundColour, termbox.ColorBlack, "|") - printf_tb(61, 1, messageForeGroundColour, termbox.ColorBlack, "|") - printf_tb(76, 1, messageForeGroundColour, termbox.ColorBlack, "|") - printf_tb(92, 1, messageForeGroundColour, termbox.ColorBlack, "|") + printfTb(2, 1, messageForeGroundColour|termbox.AttrBold, termbox.ColorBlack, "KeySpace ColumnFamily Reads/s Writes/s LiveSpace(B) R-Latency(ms) W-Latency(ms)") + printfTb(20, 1, messageForeGroundColour, termbox.ColorBlack, "|") + printfTb(40, 1, messageForeGroundColour, termbox.ColorBlack, "|") + printfTb(50, 1, messageForeGroundColour, termbox.ColorBlack, "|") + printfTb(61, 1, messageForeGroundColour, termbox.ColorBlack, "|") + printfTb(76, 1, messageForeGroundColour, termbox.ColorBlack, "|") + printfTb(92, 1, messageForeGroundColour, termbox.ColorBlack, "|") y := 2 @@ -51,29 +49,29 @@ func show_stats() { for _, cfStatsKey := range sortedStats { if y < termHeight { - // printf_tb(2, y, messageForeGroundColour, termbox.ColorBlack, "(%s:%s) r:%d, w:%d", cfStats.KeySpace, cfStats.ColumnFamily, cfStats.ReadCount, cfStats.WriteCount) - printf_tb(2, y, messageForeGroundColour, termbox.ColorBlack, "%s", stats[cfStatsKey].KeySpace) - printf_tb(20, y, messageForeGroundColour, termbox.ColorBlack, " %s", stats[cfStatsKey].ColumnFamily) - printf_tb(40, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].ReadRate) - printf_tb(50, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].WriteRate) - printf_tb(61, y, messageForeGroundColour, termbox.ColorBlack, " %d", stats[cfStatsKey].LiveDiskSpaceUsed) - printf_tb(76, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].ReadLatency) - printf_tb(92, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].WriteLatency) + // printfTb(2, y, messageForeGroundColour, termbox.ColorBlack, "(%s:%s) r:%d, w:%d", cfStats.KeySpace, cfStats.ColumnFamily, cfStats.ReadCount, cfStats.WriteCount) + printfTb(2, y, messageForeGroundColour, termbox.ColorBlack, "%s", stats[cfStatsKey].KeySpace) + printfTb(20, y, messageForeGroundColour, termbox.ColorBlack, " %s", stats[cfStatsKey].ColumnFamily) + printfTb(40, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].ReadRate) + printfTb(50, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].WriteRate) + printfTb(61, y, messageForeGroundColour, termbox.ColorBlack, " %d", stats[cfStatsKey].LiveDiskSpaceUsed) + printfTb(76, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].ReadLatency) + printfTb(92, y, messageForeGroundColour, termbox.ColorBlack, " %f", stats[cfStatsKey].WriteLatency) y++ } } } // Refreshes the on-screen data: -func refresh_screen() { +func refreshScreen() { for { if dataDisplayed == "Metrics" { - show_stats() + showStats() } if dataDisplayed == "Logs" { - show_logs() + showLogs() } // Sleep: @@ -82,7 +80,7 @@ func refresh_screen() { } // Print function for TermBox: -func print_tb(x, y int, fg, bg termbox.Attribute, msg string) { +func printTb(x, y int, fg, bg termbox.Attribute, msg string) { for _, c := range msg { termbox.SetCell(x, y, c, fg, bg) x++ @@ -90,13 +88,13 @@ func print_tb(x, y int, fg, bg termbox.Attribute, msg string) { } // PrintF function for TermBox: -func printf_tb(x, y int, fg, bg termbox.Attribute, format string, args ...interface{}) { +func printfTb(x, y int, fg, bg termbox.Attribute, format string, args ...interface{}) { s := fmt.Sprintf(format, args...) - print_tb(x, y, fg, bg, s) + printTb(x, y, fg, bg, s) } // Draw the border around the edge of the screen: -func draw_border(width int, height int) { +func drawBorder(width int, height int) { // Sides: for x := 0; x < width; x++ { termbox.SetCell(x, 0, '-', defaultForeGroundColour, defaultBackGroundColour) @@ -116,43 +114,43 @@ func draw_border(width int, height int) { termbox.SetCell(width-1, height-1, '+', defaultForeGroundColour, defaultBackGroundColour) // Title: - print_tb(1, 0, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, " C-top ") - print_tb(8, 0, termbox.ColorBlue, defaultBackGroundColour, "(top for Cassandra) ") + printTb(1, 0, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, " C-top ") + printTb(8, 0, termbox.ColorBlue, defaultBackGroundColour, "(top for Cassandra) ") // Menu: - // Positions: 2 15 28 42 58 76 94 105 113 - print_tb(1, height-1, termbox.ColorBlue, defaultBackGroundColour, " Organise by (1)Reads/s / (2)Writes/s / (3)Space-used / (4)Read-latency / (5)Write-latency, (M)etrics, (L)ogs, (Q)uit ") - print_tb(15, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "1") - print_tb(28, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "2") - print_tb(42, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "3") - print_tb(58, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "4") - print_tb(76, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "5") - print_tb(94, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "M") - print_tb(105, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "L") - print_tb(113, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "Q") + // Positions: 2 15 28 42 58 76 94 105 113 + printTb(1, height-1, termbox.ColorBlue, defaultBackGroundColour, " Organise by (1)Reads/s / (2)Writes/s / (3)Space-used / (4)Read-latency / (5)Write-latency, (M)etrics, (L)ogs, (Q)uit ") + printTb(15, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "1") + printTb(28, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "2") + printTb(42, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "3") + printTb(58, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "4") + printTb(76, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "5") + printTb(94, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "M") + printTb(105, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "L") + printTb(113, height-1, termbox.ColorBlue|termbox.AttrBold, defaultBackGroundColour, "Q") // Highlight the sorting mode: if dataSortedBy == "Reads" { - print_tb(15, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "1") + printTb(15, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "1") } if dataSortedBy == "Writes" { - print_tb(28, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "2") + printTb(28, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "2") } if dataSortedBy == "Space" { - print_tb(42, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "3") + printTb(42, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "3") } if dataSortedBy == "ReadLatency" { - print_tb(58, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "4") + printTb(58, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "4") } if dataSortedBy == "WriteLatency" { - print_tb(76, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "5") + printTb(76, height-1, termbox.ColorWhite|termbox.AttrBold, defaultBackGroundColour, "5") } // Show what mode we're in: if dataDisplayed == "Metrics" { - printf_tb(termWidth-10, 0, termbox.ColorBlue|termbox.AttrBold, termbox.ColorBlack, " Metrics ") + printfTb(termWidth-10, 0, termbox.ColorBlue|termbox.AttrBold, termbox.ColorBlack, " Metrics ") } if dataDisplayed == "Logs" { - printf_tb(termWidth-7, 0, termbox.ColorBlue|termbox.AttrBold, termbox.ColorBlack, " Logs ") + printfTb(termWidth-7, 0, termbox.ColorBlue|termbox.AttrBold, termbox.ColorBlack, " Logs ") } } diff --git a/handlers.go b/handlers.go index d25af9e..ba408e8 100644 --- a/handlers.go +++ b/handlers.go @@ -2,15 +2,12 @@ package main import ( types "./types" - // "flag" "fmt" "github.com/nsf/termbox-go" - // "time" - // "os" ) // Logging to a channel (from anywhere): -func log_to_channel(severity string, message string) { +func logToChannel(severity string, message string) { // Make a new LogMessage struct: logMessage := types.LogMessage{ Severity: severity, @@ -27,14 +24,14 @@ func log_to_channel(severity string, message string) { } // Takes metrics off the channel and adds them up: -func handle_metrics() { +func handleMetrics() { var cfStats types.CFStats for { // Get a metric from the channel: cfMetric := <-metricsChannel - log_to_channel("debug", fmt.Sprintf("Received a metric! %s", cfMetric.MetricName)) + logToChannel("debug", fmt.Sprintf("Received a metric! %s", cfMetric.MetricName)) // Build the key: statName := cfMetric.KeySpace + ":" + cfMetric.ColumnFamily @@ -45,11 +42,11 @@ func handle_metrics() { // See if we already have a stats-entry: if _, ok := stats[statName]; ok { // Use the existing stats-entry: - log_to_channel("debug", fmt.Sprintf("Updating existing stat (%s)", statName)) + logToChannel("debug", fmt.Sprintf("Updating existing stat (%s)", statName)) cfStats = stats[statName] } else { // Add a new entry to the map: - log_to_channel("debug", fmt.Sprintf("Adding new stat (%s)", statName)) + logToChannel("debug", fmt.Sprintf("Adding new stat (%s)", statName)) cfStats = types.CFStats{ ReadCount: 0, ReadCountTS: 0, @@ -116,6 +113,6 @@ func handle_metrics() { } // Returns the key-code: -func handle_keypress(ev *termbox.Event) { - log_to_channel("debug", fmt.Sprintf("Key pressed: %s", ev.Ch)) +func handleKeypress(ev *termbox.Event) { + logToChannel("debug", fmt.Sprintf("Key pressed: %s", ev.Ch)) } diff --git a/main.go b/main.go index 0b3e933..f331fb7 100644 --- a/main.go +++ b/main.go @@ -31,8 +31,7 @@ const ( func init() { // Default to localhost (MX4J needs to be configured to listen to this address in cassandra-env.sh though): - // hostName, _ := os.Hostname() - hostName := "127.0.0.1" + hostName, _ := os.Hostname() flag.StringVar(&cassandraHost, "cassandraHost", hostName, "The address of the Cassandra host to run against") } @@ -42,31 +41,40 @@ func main() { // Set the vars from the command-line args: flag.Parse() - err := check_connection(cassandraHost) - if err != nil { - fmt.Printf("Can't connect to stats-provider! (%s)\n", cassandraHost) - os.Exit(2) + // Check our connection to MX4J: + if checkConnection(cassandraHost) != nil { + fmt.Printf("Can't connect to stats-provider (%s)! Trying localhost before bailing...\n", cassandraHost) + if checkConnection("localhost") != nil { + fmt.Println("Can't even connect to localhost! Are you running C* with MX4J?") + os.Exit(2) + } else { + fmt.Println("Proceeding with localhost..") + cassandraHost = "localhost" + } } // Initialise "termbox" (console interface): - err = termbox.Init() + err := termbox.Init() if err != nil { panic(err) } defer termbox.Close() + // Get the initial window-size: termWidth, termHeight = termbox.Size() + // Get the display running in the right mode: termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse) + // Render the initial "UI": termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) - draw_border(termWidth, termHeight) + drawBorder(termWidth, termHeight) termbox.Flush() // Run the metrics-collector: go MetricsCollector(cassandraHost) - go handle_metrics() - go refresh_screen() + go handleMetrics() + go refreshScreen() loop: for { @@ -77,13 +85,13 @@ loop: // Handle keypresses: if ev.Ch == 113 { // "q" (quit): - printf_tb(2, 1, messageForeGroundColour, termbox.ColorBlack, "Goodbye!: %s", ev.Ch) + printfTb(2, 1, messageForeGroundColour, termbox.ColorBlack, "Goodbye!: %s", ev.Ch) break loop - } else if ev.Ch == 0 { // "Space" - show_stats() + } else if ev.Ch == 0 { // "Space-bar (refresh)" + showStats() } else if ev.Ch == 109 { // "M" dataDisplayed = "Metrics" - show_stats() + showStats() } else if ev.Ch == 108 { // "L" dataDisplayed = "Logs" } else if ev.Ch == 49 { // "1" @@ -98,10 +106,11 @@ loop: dataSortedBy = "WriteLatency" } else { // Anything else: - handle_keypress(&ev) + handleKeypress(&ev) } - draw_border(termWidth, termHeight) + // Redraw the display: + drawBorder(termWidth, termHeight) termbox.Flush() // Window is re-sized: @@ -111,7 +120,7 @@ loop: termHeight = ev.Height // Redraw the screen: - draw_border(termWidth, termHeight) + drawBorder(termWidth, termHeight) termbox.Flush() // Error: diff --git a/metricscollectormx4j.go b/metricscollectormx4j.go index b34a840..1f9db41 100644 --- a/metricscollectormx4j.go +++ b/metricscollectormx4j.go @@ -16,12 +16,20 @@ const ( ) var ( - // cfMetrics = []string{"ReadCount", "WriteCount", "LiveDiskSpaceUsed", "MeanRowSize", "MaxRowSize"} + // Define a list of metrics to collect (sticking to 5 important ones to save on HTTP calls): cfMetrics = []string{"ReadCount", "WriteCount", "LiveDiskSpaceUsed", "RecentReadLatencyMicros", "RecentWriteLatencyMicros"} + + // "ReadCount" - The number of reads to a CF + // "WriteCount" - The number of writes to a CF + // "LiveDiskSpaceUsed" - Disk space used + // "MeanRowSize" - Mean row-size + // "MaxRowSize" - Max row-size + // "RecentReadLatencyMicros" - Read latency + // "RecentWriteLatencyMicros" - Write latency ) // Checks the connection to MX4J: -func check_connection(cassandraIP string) error { +func checkConnection(cassandraIP string) error { // Request the root URL: URL := fmt.Sprintf("http://%s:%s/", cassandraHost, MX4JPort) @@ -32,7 +40,7 @@ func check_connection(cassandraIP string) error { // Return a list of keySpaces and columnFamilies from MX4J: func getCluster(cassandraIP string) (types.Cluster, error) { - log_to_channel("info", fmt.Sprintf("Getting list of KeySpaces and ColumnFamilies from (%s:%s)", cassandraIP, MX4JPort)) + logToChannel("info", fmt.Sprintf("Getting list of KeySpaces and ColumnFamilies from (%s:%s)", cassandraIP, MX4JPort)) // Create a new MX4JCFList{} to unmarshal the XML into: columnFamilyList := types.MX4JCFList{} @@ -43,23 +51,23 @@ func getCluster(cassandraIP string) (types.Cluster, error) { // Request the data from MX4J: httpResponse, err := http.Get(URL) if err != nil { - log_to_channel("error", fmt.Sprintf("Trouble talking to MX4J (%s)\n%s", URL, err)) + logToChannel("error", fmt.Sprintf("Trouble talking to MX4J (%s)\n%s", URL, err)) } else { - log_to_channel("debug", fmt.Sprintf("Got HTTP response code (%d)", httpResponse.StatusCode)) + logToChannel("debug", fmt.Sprintf("Got HTTP response code (%d)", httpResponse.StatusCode)) } // Read the response: xmlResponse, err := ioutil.ReadAll(httpResponse.Body) if err != nil { - log_to_channel("error", fmt.Sprintf("Couldn't get response body!\n%s", err)) + logToChannel("error", fmt.Sprintf("Couldn't get response body!\n%s", err)) } // UnMarshal the XML response: err = xml.Unmarshal([]byte(xmlResponse), &columnFamilyList) if err != nil { - log_to_channel("error", fmt.Sprintf("Couldn't unmarshal the response!\n%s", err)) + logToChannel("error", fmt.Sprintf("Couldn't unmarshal the response!\n%s", err)) } else { - log_to_channel("debug", fmt.Sprintf("Got a ColumnFamily list - great success!")) + logToChannel("debug", fmt.Sprintf("Got a ColumnFamily list - great success!")) //log.Debugf("- %s", columnFamilyList) } @@ -94,7 +102,7 @@ func getCluster(cassandraIP string) (types.Cluster, error) { // Create a new ColumnFamily{}: if columnFamilyType[1] == "ColumnFamilies" { - log_to_channel("debug", fmt.Sprintf("Found KS:CF - %s:%s (%s)", keySpaceName[1], columnFamilyName[1], columnFamilyType[1])) + logToChannel("debug", fmt.Sprintf("Found KS:CF - %s:%s (%s)", keySpaceName[1], columnFamilyName[1], columnFamilyType[1])) cluster.KeySpaces[keySpaceName[1]].ColumnFamilies[columnFamilyName[1]] = types.ColumnFamily{} } } @@ -105,7 +113,7 @@ func getCluster(cassandraIP string) (types.Cluster, error) { // Retreive metrics from MX4J: func getCFMetrics(cluster types.Cluster, cassandraIP string) (types.Cluster, error) { - log_to_channel("debug", fmt.Sprintf("Getting metrics from (%s:%s)", cassandraIP, MX4JPort)) + logToChannel("debug", fmt.Sprintf("Getting metrics from (%s:%s)", cassandraIP, MX4JPort)) // Iterate through our Cluster{}: for name, keySpace := range cluster.KeySpaces { @@ -117,7 +125,7 @@ func getCFMetrics(cluster types.Cluster, cassandraIP string) (types.Cluster, err // Create a new MX4JCassandraCFLongData{} to unmarshal the XML into: metric := types.MX4JCassandraCFLongData{} - log_to_channel("info", fmt.Sprintf("Getting %s:%s:%s", name, columnFamily, cfMetrics[i])) + logToChannel("info", fmt.Sprintf("Getting %s:%s:%s", name, columnFamily, cfMetrics[i])) // Build the reqest URL: URL := fmt.Sprintf("http://%s:%s/getattribute?objectname=org.apache.cassandra.db:type=ColumnFamilies,keyspace=%s,columnfamily=%s&attribute=%s&format=long&template=identity", cassandraIP, MX4JPort, name, columnFamily, cfMetrics[i]) @@ -125,23 +133,23 @@ func getCFMetrics(cluster types.Cluster, cassandraIP string) (types.Cluster, err // Request the data from MX4J: httpResponse, err := http.Get(URL) if err != nil { - log_to_channel("error", fmt.Sprintf("Trouble talking to MX4J (%s)\n%s", URL, err)) + logToChannel("error", fmt.Sprintf("Trouble talking to MX4J (%s)\n%s", URL, err)) } else { - log_to_channel("debug", fmt.Sprintf("Got HTTP response code (%d)", httpResponse.StatusCode)) + logToChannel("debug", fmt.Sprintf("Got HTTP response code (%d)", httpResponse.StatusCode)) } // Read the response: xmlResponse, err := ioutil.ReadAll(httpResponse.Body) if err != nil { - log_to_channel("error", fmt.Sprintf("Couldn't get response body!\n%s", err)) + logToChannel("error", fmt.Sprintf("Couldn't get response body!\n%s", err)) } // UnMarshal the XML response: err = xml.Unmarshal([]byte(xmlResponse), &metric) if err != nil { - log_to_channel("error", fmt.Sprintf("Couldn't unmarshal the response!\n%s", err)) + logToChannel("error", fmt.Sprintf("Couldn't unmarshal the response!\n%s", err)) } else { - log_to_channel("debug", fmt.Sprintf("Got a metric - GREAT SUCCESS!")) + logToChannel("debug", fmt.Sprintf("Got a metric - GREAT SUCCESS!")) // Make an int64: metricIntValue, _ := strconv.ParseInt(metric.CFLongData.Value, 0, 64) @@ -160,9 +168,9 @@ func getCFMetrics(cluster types.Cluster, cassandraIP string) (types.Cluster, err // Put it in the metrics channel: select { case metricsChannel <- cfMetric: - log_to_channel("debug", fmt.Sprintf("Sent a metric.")) + logToChannel("debug", fmt.Sprintf("Sent a metric.")) default: - log_to_channel("info", fmt.Sprintf("Couldn't send metric!")) + logToChannel("info", fmt.Sprintf("Couldn't send metric!")) } } } @@ -177,14 +185,14 @@ func MetricsCollector(cassandraHost string) { // Get a list of cluster KeySpaces and ColumnFamilies from MX4J: cluster, err := getCluster(cassandraHost) if err != nil { - log_to_channel("error", fmt.Sprintf("Couldn't get cluster schema!\n%s", err)) + logToChannel("error", fmt.Sprintf("Couldn't get cluster schema!\n%s", err)) } for { // Get metrics for each ColumnFamily from MX4J: cluster, err = getCFMetrics(cluster, cassandraHost) if err != nil { - log_to_channel("error", fmt.Sprintf("Couldn't get metrics!\n%s", err)) + logToChannel("error", fmt.Sprintf("Couldn't get metrics!\n%s", err)) } time.Sleep(5 * time.Second) } diff --git a/sorting.go b/sorting.go index 1dec975..b8602e0 100644 --- a/sorting.go +++ b/sorting.go @@ -5,15 +5,18 @@ import ( "sort" ) +// Define a type for a sorted-map of columnfamily-stats: type sortedMap struct { m map[string]types.CFStats s []string } +// Return the length of a sorted-map: func (sm *sortedMap) Len() int { return len(sm.m) } +// Handles the different attributes we might sort by: func (sm *sortedMap) Less(i, j int) bool { if dataSortedBy == "Reads" { return sm.m[sm.s[i]].ReadRate > sm.m[sm.s[j]].ReadRate @@ -35,10 +38,12 @@ func (sm *sortedMap) Less(i, j int) bool { } } +// Replace two values in a list: func (sm *sortedMap) Swap(i, j int) { sm.s[i], sm.s[j] = sm.s[j], sm.s[i] } +// Return keys in order: func sortedKeys(m map[string]types.CFStats) []string { sm := new(sortedMap) sm.m = m