github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/agent/mcorpc/aggregate/chart.go (about) 1 // Copyright (c) 2020-2022, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package aggregate 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "strconv" 11 "sync" 12 13 "github.com/guptarohit/asciigraph" 14 ) 15 16 // ChartAggregator tracks seen values and produce a chart with values bucketed in groups of 50 17 type ChartAggregator struct { 18 items []float64 19 20 sync.Mutex 21 } 22 23 // NewChartAggregator creates a new ChartAggregator with the specific options 24 func NewChartAggregator(args []any) (*ChartAggregator, error) { 25 agg := &ChartAggregator{ 26 items: []float64{}, 27 } 28 29 return agg, nil 30 } 31 32 // Type is the type of Aggregator 33 func (s *ChartAggregator) Type() string { 34 return "chart" 35 } 36 37 // ProcessValue processes and tracks the specific value 38 func (s *ChartAggregator) ProcessValue(v any) error { 39 s.Lock() 40 defer s.Unlock() 41 42 if s.processInt(v) { 43 return nil 44 } 45 46 if s.processInt64(v) { 47 return nil 48 } 49 50 if s.processFloat(v) { 51 return nil 52 } 53 54 if s.processString(v) { 55 return nil 56 } 57 58 return fmt.Errorf("unsupported data type for chart aggregator") 59 } 60 61 // ResultJSON return the chart as a JSON document with the key "chart" 62 func (s *ChartAggregator) ResultJSON() ([]byte, error) { 63 s.Lock() 64 defer s.Unlock() 65 66 line := s.chart() 67 68 return json.Marshal(map[string]string{ 69 "chart": line, 70 }) 71 } 72 73 // ResultStrings returns a map of results in string format in the key "Chart" 74 func (s *ChartAggregator) ResultStrings() (map[string]string, error) { 75 s.Lock() 76 defer s.Unlock() 77 78 line := s.chart() 79 80 return map[string]string{"Chart": line}, nil 81 } 82 83 // ResultFormattedStrings returns the chart as a formatted string 84 func (s *ChartAggregator) ResultFormattedStrings(format string) ([]string, error) { 85 s.Lock() 86 defer s.Unlock() 87 88 if format == "" { 89 format = "%s" 90 } 91 92 line := s.chart() 93 94 return []string{fmt.Sprintf(format, line)}, nil 95 } 96 97 func (s *ChartAggregator) processString(v any) bool { 98 str, ok := v.(string) 99 if !ok { 100 return false 101 } 102 103 f, err := strconv.ParseFloat(str, 64) 104 if err != nil { 105 return false 106 } 107 108 s.items = append(s.items, f) 109 110 return true 111 } 112 113 func (s *ChartAggregator) processFloat(v any) bool { 114 f, ok := v.(float64) 115 if !ok { 116 return false 117 } 118 119 s.items = append(s.items, f) 120 121 return true 122 } 123 124 func (s *ChartAggregator) processInt(v any) bool { 125 i, ok := v.(int) 126 if !ok { 127 return false 128 } 129 130 s.items = append(s.items, float64(i)) 131 132 return true 133 } 134 135 func (s *ChartAggregator) processInt64(v any) bool { 136 i, ok := v.(int64) 137 if !ok { 138 return false 139 } 140 141 s.items = append(s.items, float64(i)) 142 143 return true 144 } 145 146 func (s *ChartAggregator) chart() string { 147 return asciigraph.Plot(s.items, asciigraph.Height(15), asciigraph.Width(60), asciigraph.Offset(5)) 148 }