From 8b89fedc91e67ce3ebacd977d0a0f848c83920ca Mon Sep 17 00:00:00 2001 From: Gustavo Massaneiro Date: Tue, 4 Jan 2022 18:30:21 -0300 Subject: [PATCH] new render endpoint to render the graph in real time --- agent/go.mod | 1 + agent/go.sum | 3 + .../pkg/controllers/service_map_controller.go | 94 +++++++++++++++++++ agent/pkg/routes/service_map_routes.go | 1 + 4 files changed, 99 insertions(+) diff --git a/agent/go.mod b/agent/go.mod index a4ccbb693..2332a2989 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -8,6 +8,7 @@ require ( github.com/getkin/kin-openapi v0.76.0 github.com/gin-contrib/static v0.0.1 github.com/gin-gonic/gin v1.7.7 + github.com/go-echarts/go-echarts/v2 v2.2.4 github.com/go-playground/locales v0.13.0 github.com/go-playground/universal-translator v0.17.0 github.com/go-playground/validator/v10 v10.5.0 diff --git a/agent/go.sum b/agent/go.sum index ed288cfc1..03c5b58aa 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -129,6 +129,8 @@ github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-echarts/go-echarts/v2 v2.2.4 h1:SKJpdyNIyD65XjbUZjzg6SwccTNXEgmh+PlaO23g2H0= +github.com/go-echarts/go-echarts/v2 v2.2.4/go.mod h1:6TOomEztzGDVDkOSCFBq3ed7xOYfbOqhaBzD0YV771A= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -441,6 +443,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/agent/pkg/controllers/service_map_controller.go b/agent/pkg/controllers/service_map_controller.go index a6f671d47..e5e52e9c3 100644 --- a/agent/pkg/controllers/service_map_controller.go +++ b/agent/pkg/controllers/service_map_controller.go @@ -5,9 +5,88 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/go-echarts/go-echarts/v2/charts" + "github.com/go-echarts/go-echarts/v2/components" + "github.com/go-echarts/go-echarts/v2/opts" "github.com/up9inc/mizu/shared" ) +func calcNodeSize(value float32) float32 { + //TODO: Linear interpolation + if value < 1 { + value = 1 + } + if value > 300 { + value = 300 + } + return value +} + +func buildGraph() *components.Page { + page := components.NewPage() + page.SetLayout(components.PageFlexLayout) + page.PageTitle = "Mizu Service Map" + + graph := charts.NewGraph() + graph.SetGlobalOptions( + charts.WithInitializationOpts(opts.Initialization{ + PageTitle: "MIZU", + Width: "1800px", + Height: "1000px", + //Theme: types.ThemeInfographic, + }), + charts.WithTitleOpts(opts.Title{ + Title: "Service Map Graph", + })) + + // TODO: Sort nodes by name + // TODO: Add protocol color + + var graphNodes []opts.GraphNode + for _, n := range api.GetServiceMapInstance().GetNodes() { + graphNodes = append(graphNodes, opts.GraphNode{ + Name: n.Name, + Value: float32(n.Count), + Fixed: true, + SymbolSize: calcNodeSize(float32(n.Count)), + }) + } + + var graphEdges []opts.GraphLink + for _, e := range api.GetServiceMapInstance().GetEdges() { + graphEdges = append(graphEdges, opts.GraphLink{ + Source: e.Source, + Target: e.Destination, + Value: float32(e.Count), + }) + } + + graph.AddSeries("graph", graphNodes, graphEdges). + SetSeriesOptions( + charts.WithGraphChartOpts(opts.GraphChart{ + Layout: "circular", + Force: &opts.GraphForce{Repulsion: 8000}, + Roam: true, + FocusNodeAdjacency: true, + }), + charts.WithEmphasisOpts(opts.Emphasis{ + Label: &opts.Label{ + Show: true, + Color: "red", + Position: "top", + }, + }), + charts.WithLineStyleOpts(opts.LineStyle{ + Curveness: 0.3, + Width: 2, + Type: "dotted", + }), + charts.WithLabelOpts(opts.Label{Show: true, Position: "top"}), + ) + + return page.AddCharts(graph) +} + type ServiceMapController struct{} func NewServiceMapController() *ServiceMapController { @@ -34,6 +113,21 @@ func (s *ServiceMapController) Get(c *gin.Context) { c.JSON(http.StatusOK, response) } +func (s *ServiceMapController) Render(c *gin.Context) { + w := c.Writer + header := w.Header() + header.Set("Content-Type", "text/html") + + err := buildGraph().Render(w) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + } else { + w.WriteHeader(http.StatusOK) + } + + w.(http.Flusher).Flush() +} + func (s *ServiceMapController) Reset(c *gin.Context) { serviceMap := api.GetServiceMapInstance() serviceMap.Reset() diff --git a/agent/pkg/routes/service_map_routes.go b/agent/pkg/routes/service_map_routes.go index 455f5e57d..64e25409e 100644 --- a/agent/pkg/routes/service_map_routes.go +++ b/agent/pkg/routes/service_map_routes.go @@ -13,5 +13,6 @@ func ServiceMapRoutes(ginApp *gin.Engine) { routeGroup.GET("/status", controller.Status) routeGroup.GET("/get", controller.Get) + routeGroup.GET("/render", controller.Render) routeGroup.GET("/reset", controller.Reset) }