From 22b96d001d994b9ae994512ca1a6cf3751cadd45 Mon Sep 17 00:00:00 2001 From: Mikolaj Pawlikowski Date: Thu, 21 Feb 2019 13:50:59 +0000 Subject: [PATCH 01/10] add a skeleton for creating a heatmap png Signed-off-by: Mikolaj Pawlikowski --- pkg/goldpinger/heatmap.go | 116 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 pkg/goldpinger/heatmap.go diff --git a/pkg/goldpinger/heatmap.go b/pkg/goldpinger/heatmap.go new file mode 100644 index 0000000..88e6478 --- /dev/null +++ b/pkg/goldpinger/heatmap.go @@ -0,0 +1,116 @@ +// Copyright 2018 Bloomberg Finance L.P. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file is safe to edit. Once it exists it will not be overwritten + +package goldpinger + +import ( + "bytes" + "fmt" + "image" + "image/color" + "image/png" + "log" + "net/http" + "sort" + "strconv" +) + +// Calculates the color of the box to draw based on the latency and tresholds +// We are aiming at slightly more palatable colors than just moving from 255 green to 255 red, +// so we will use 25B, and then move from (25R, 200G) to (200R, 25G), so our scale is effectively 350 points +func getPingBoxColor(latency, tresholdA, tresholdB, tresholdC int64) *color.RGBA { + var red, green uint8 = 25, 200 + if latency > tresholdC { + red, green = 200, 25 + } else if latency > tresholdB { + red, green = 200, 200 + diff := (float32(latency-tresholdB) / float32(tresholdC-tresholdB)) * 175 + green = green - uint8(diff) + } else if latency > tresholdA { + red, green = 25, 200 + diff := (float32(latency-tresholdA) / float32(tresholdB-tresholdA)) * 175 + red = red + uint8(diff) + } + return &color.RGBA{red, green, 25, 255} +} + +func drawPingBox(img *image.RGBA, _x, _y, size int, color *color.RGBA) { + for x := _x; x < _x+size; x++ { + for y := _y; y < _y+size; y++ { + img.Set(x, y, *color) + } + } +} + +func getPingBoxCoordinates(col, row, boxSize, padding int) (int, int) { + return col * (boxSize + padding), row * (boxSize + padding) +} + +// HeatmapHandler returns a PNG with a heatmap representation +func HeatmapHandler(w http.ResponseWriter, r *http.Request) { + + // get the results + checkResults := CheckAllPods(GetAllPods()) + + // set some sizes + numberOfPods := len(checkResults.Responses) + boxSize := 20 + paddingSize := 1 + heatmapSize := numberOfPods * (boxSize + paddingSize) + var tresholdLatencyA int64 = 50 + var tresholdLatencyB int64 = 100 + var tresholdLatencyC int64 = 200 + + canvas := image.NewRGBA(image.Rect(0, 0, heatmapSize, heatmapSize)) + + // establish an order and fix the max delay + var keys []string + for sourceIP := range checkResults.Responses { + keys = append(keys, sourceIP) + } + sort.Strings(keys) + order := make(map[string]int) + for index, key := range keys { + order[key] = index + } + + // draw all the boxes + for sourceIP, results := range checkResults.Responses { + fmt.Println("source", sourceIP) + fmt.Println("OK ?", *results.OK) + + keys = append(keys, sourceIP) + + if *results.OK { + for destinationIP, response := range results.Response { + x, y := getPingBoxCoordinates(order[sourceIP], order[destinationIP], boxSize, paddingSize) + color := getPingBoxColor(response.ResponseTimeMs, tresholdLatencyA, tresholdLatencyB, tresholdLatencyC) + drawPingBox(canvas, x, y, boxSize, color) + } + } + } + + buffer := new(bytes.Buffer) + if err := png.Encode(buffer, canvas); err != nil { + log.Println("error encoding png", err) + } + + w.Header().Set("Content-Type", "image/png") + w.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes()))) + if _, err := w.Write(buffer.Bytes()); err != nil { + log.Println("error writing heatmap buffer out", err) + } +} From f5c27630005e34a412e446103f16853dde29a296 Mon Sep 17 00:00:00 2001 From: Mikolaj Pawlikowski Date: Thu, 21 Feb 2019 13:51:20 +0000 Subject: [PATCH 02/10] add an endpoint for generating a /heatmap.png Signed-off-by: Mikolaj Pawlikowski --- pkg/restapi/configure_goldpinger.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/restapi/configure_goldpinger.go b/pkg/restapi/configure_goldpinger.go index bb5abf7..4bec7d0 100644 --- a/pkg/restapi/configure_goldpinger.go +++ b/pkg/restapi/configure_goldpinger.go @@ -110,6 +110,8 @@ func fileServerMiddleware(next http.Handler) http.Handler { fileServer := http.FileServer(http.Dir(goldpinger.GoldpingerConfig.StaticFilePath)) if r.URL.Path == "/" { http.StripPrefix("/", fileServer).ServeHTTP(w, r) + } else if r.URL.Path == "/heatmap.png" { + goldpinger.HeatmapHandler(w, r) } else if strings.HasPrefix(r.URL.Path, "/static/") { http.StripPrefix("/static/", fileServer).ServeHTTP(w, r) } else { From fd8459915774b194735eb0d2cb8726d24444c1af Mon Sep 17 00:00:00 2001 From: Mikolaj Pawlikowski Date: Thu, 21 Feb 2019 16:13:20 +0000 Subject: [PATCH 03/10] remove debug print statements Signed-off-by: Mikolaj Pawlikowski --- pkg/goldpinger/heatmap.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pkg/goldpinger/heatmap.go b/pkg/goldpinger/heatmap.go index 88e6478..abac9c1 100644 --- a/pkg/goldpinger/heatmap.go +++ b/pkg/goldpinger/heatmap.go @@ -18,7 +18,6 @@ package goldpinger import ( "bytes" - "fmt" "image" "image/color" "image/png" @@ -89,11 +88,6 @@ func HeatmapHandler(w http.ResponseWriter, r *http.Request) { // draw all the boxes for sourceIP, results := range checkResults.Responses { - fmt.Println("source", sourceIP) - fmt.Println("OK ?", *results.OK) - - keys = append(keys, sourceIP) - if *results.OK { for destinationIP, response := range results.Response { x, y := getPingBoxCoordinates(order[sourceIP], order[destinationIP], boxSize, paddingSize) From 3a729bf196ff3400230a1c4d130d60d3f4e1a50e Mon Sep 17 00:00:00 2001 From: Mikolaj Pawlikowski Date: Thu, 21 Feb 2019 16:14:48 +0000 Subject: [PATCH 04/10] minor version bump Signed-off-by: Mikolaj Pawlikowski --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cd48870..3a6001d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ name ?= goldpinger -version ?= 1.3.0 +version ?= 1.4.0 bin ?= goldpinger pkg ?= "github.com/bloomberg/goldpinger" tag = $(name):$(version) From 2efee0f5e5a1f91a62f89552f914583e74354e6d Mon Sep 17 00:00:00 2001 From: Mikolaj Pawlikowski Date: Thu, 21 Feb 2019 17:40:06 +0000 Subject: [PATCH 05/10] read the tresholds from the query params Signed-off-by: Mikolaj Pawlikowski --- pkg/goldpinger/heatmap.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pkg/goldpinger/heatmap.go b/pkg/goldpinger/heatmap.go index abac9c1..c400db6 100644 --- a/pkg/goldpinger/heatmap.go +++ b/pkg/goldpinger/heatmap.go @@ -18,6 +18,7 @@ package goldpinger import ( "bytes" + "fmt" "image" "image/color" "image/png" @@ -30,17 +31,17 @@ import ( // Calculates the color of the box to draw based on the latency and tresholds // We are aiming at slightly more palatable colors than just moving from 255 green to 255 red, // so we will use 25B, and then move from (25R, 200G) to (200R, 25G), so our scale is effectively 350 points -func getPingBoxColor(latency, tresholdA, tresholdB, tresholdC int64) *color.RGBA { +func getPingBoxColor(latency int64, tresholdLatencies [3]int64) *color.RGBA { var red, green uint8 = 25, 200 - if latency > tresholdC { + if latency > tresholdLatencies[2] { red, green = 200, 25 - } else if latency > tresholdB { + } else if latency >= tresholdLatencies[1] { red, green = 200, 200 - diff := (float32(latency-tresholdB) / float32(tresholdC-tresholdB)) * 175 + diff := (float32(latency-tresholdLatencies[1]) / float32(tresholdLatencies[2]-tresholdLatencies[1])) * 175 green = green - uint8(diff) - } else if latency > tresholdA { + } else if latency >= tresholdLatencies[0] { red, green = 25, 200 - diff := (float32(latency-tresholdA) / float32(tresholdB-tresholdA)) * 175 + diff := (float32(latency-tresholdLatencies[0]) / float32(tresholdLatencies[1]-tresholdLatencies[0])) * 175 red = red + uint8(diff) } return &color.RGBA{red, green, 25, 255} @@ -61,6 +62,9 @@ func getPingBoxCoordinates(col, row, boxSize, padding int) (int, int) { // HeatmapHandler returns a PNG with a heatmap representation func HeatmapHandler(w http.ResponseWriter, r *http.Request) { + // parse the query to set the parameters + query := r.URL.Query() + // get the results checkResults := CheckAllPods(GetAllPods()) @@ -69,9 +73,16 @@ func HeatmapHandler(w http.ResponseWriter, r *http.Request) { boxSize := 20 paddingSize := 1 heatmapSize := numberOfPods * (boxSize + paddingSize) - var tresholdLatencyA int64 = 50 - var tresholdLatencyB int64 = 100 - var tresholdLatencyC int64 = 200 + tresholdLatencies := [3]int64{1, 10, 100} + for index := range tresholdLatencies { + stringValue := query["t"+fmt.Sprintf("%d", index)] + if len(stringValue) == 0 { + continue + } + if v, err := strconv.ParseInt(stringValue[0], 0, 64); err == nil && v >= 0 { + tresholdLatencies[index] = v + } + } canvas := image.NewRGBA(image.Rect(0, 0, heatmapSize, heatmapSize)) @@ -91,7 +102,7 @@ func HeatmapHandler(w http.ResponseWriter, r *http.Request) { if *results.OK { for destinationIP, response := range results.Response { x, y := getPingBoxCoordinates(order[sourceIP], order[destinationIP], boxSize, paddingSize) - color := getPingBoxColor(response.ResponseTimeMs, tresholdLatencyA, tresholdLatencyB, tresholdLatencyC) + color := getPingBoxColor(response.ResponseTimeMs, tresholdLatencies) drawPingBox(canvas, x, y, boxSize, color) } } From 767d2dba7f1c05058076b9df374f08800da5fd76 Mon Sep 17 00:00:00 2001 From: Mikolaj Pawlikowski Date: Thu, 21 Feb 2019 17:41:19 +0000 Subject: [PATCH 06/10] quick test of how to integrate with the UI Signed-off-by: Mikolaj Pawlikowski --- static/index.html | 85 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/static/index.html b/static/index.html index d2baae5..73cc6e6 100644 --- a/static/index.html +++ b/static/index.html @@ -86,6 +86,7 @@ limitations under the License. @@ -106,24 +107,70 @@ limitations under the License. -