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  }