github.com/go-graphite/carbonapi@v0.17.0/expr/functions/heatMap/function.go (about)

     1  package heatMap
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  
     7  	pb "github.com/go-graphite/protocol/carbonapi_v3_pb"
     8  
     9  	"github.com/go-graphite/carbonapi/expr/helper"
    10  	"github.com/go-graphite/carbonapi/expr/interfaces"
    11  	"github.com/go-graphite/carbonapi/expr/types"
    12  	"github.com/go-graphite/carbonapi/pkg/parser"
    13  )
    14  
    15  type heatMap struct{}
    16  
    17  func GetOrder() interfaces.Order {
    18  	return interfaces.Any
    19  }
    20  
    21  func New(_ string) []interfaces.FunctionMetadata {
    22  	return []interfaces.FunctionMetadata{{
    23  		F:    &heatMap{},
    24  		Name: "heatMap",
    25  	}}
    26  }
    27  
    28  func (f *heatMap) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    29  	series, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  
    34  	series = sortMetricData(series)
    35  	seriesQty := len(series)
    36  	result := make([]*types.MetricData, 0, seriesQty-1)
    37  
    38  	if err = validateNeighbourSeries(series); err != nil {
    39  		return nil, err
    40  	}
    41  	for i := 1; i < seriesQty; i++ {
    42  		curr, prev := series[i], series[i-1]
    43  
    44  		pointsQty := len(curr.Values)
    45  		r := &types.MetricData{
    46  			FetchResponse: pb.FetchResponse{
    47  				Name:      "heatMap(" + curr.Name + "," + prev.Name + ")",
    48  				Values:    make([]float64, pointsQty),
    49  				StartTime: curr.StartTime,
    50  				StopTime:  curr.StopTime,
    51  				StepTime:  curr.StepTime,
    52  			},
    53  			Tags: curr.Tags,
    54  		}
    55  
    56  		for j := 0; j < pointsQty; j++ {
    57  			if math.IsNaN(curr.Values[j]) || math.IsNaN(prev.Values[j]) {
    58  				r.Values[j] = math.NaN()
    59  				continue
    60  			}
    61  			r.Values[j] = curr.Values[j] - prev.Values[j]
    62  		}
    63  
    64  		result = append(result, r)
    65  	}
    66  
    67  	return result, nil
    68  }
    69  
    70  const description = `Compute heat-map like result based on a values of a metric.
    71  
    72  All metrics are assigned weights, based on the sum of their first 5 values and then sorted based on that.
    73  
    74  After that for the sorted metrics, diff with the previous one will be computed.
    75  
    76  Assuming seriesList has values N series in total (sorted by sum of the first 5 values):
    77  (a[1], a[2], ..., a[N]). Then heatMap will output N-1 series: (a[2] - a[1], a[3] - a[2], ..., a[N] - a[N-1]).
    78  
    79  That function produce similar result to prometheus heatmaps for any list of incrementing counters and plays well with
    80  grafana heatmap graph type.'
    81  `
    82  
    83  func (f *heatMap) Description() map[string]types.FunctionDescription {
    84  	return map[string]types.FunctionDescription{
    85  		"heatMap": {
    86  			Description: description,
    87  			Function:    "heatMap(seriesList)",
    88  			Group:       "Transform",
    89  			Module:      "graphite.render.functions",
    90  			Name:        "heatMap",
    91  			Params: []types.FunctionParam{
    92  				{
    93  					Name:     "seriesList",
    94  					Required: true,
    95  					Type:     types.SeriesList,
    96  				},
    97  			},
    98  			SeriesChange: true, // function aggregate metrics or change series items count
    99  			NameChange:   true, // name changed
   100  			ValuesChange: true, // values changed
   101  		},
   102  	}
   103  }