github.com/v2fly/tools@v0.100.0/internal/event/export/metric/data.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package metric
     6  
     7  import (
     8  	"fmt"
     9  	"sort"
    10  	"time"
    11  
    12  	"github.com/v2fly/tools/internal/event/keys"
    13  	"github.com/v2fly/tools/internal/event/label"
    14  )
    15  
    16  // Data represents a single point in the time series of a metric.
    17  // This provides the common interface to all metrics no matter their data
    18  // format.
    19  // To get the actual values for the metric you must type assert to a concrete
    20  // metric type.
    21  type Data interface {
    22  	// Handle returns the metric handle this data is for.
    23  	//TODO: rethink the concept of metric handles
    24  	Handle() string
    25  	// Groups reports the rows that currently exist for this metric.
    26  	Groups() [][]label.Label
    27  }
    28  
    29  // Int64Data is a concrete implementation of Data for int64 scalar metrics.
    30  type Int64Data struct {
    31  	// Info holds the original construction information.
    32  	Info *Scalar
    33  	// IsGauge is true for metrics that track values, rather than increasing over time.
    34  	IsGauge bool
    35  	// Rows holds the per group values for the metric.
    36  	Rows []int64
    37  	// End is the last time this metric was updated.
    38  	EndTime time.Time
    39  
    40  	groups [][]label.Label
    41  	key    *keys.Int64
    42  }
    43  
    44  // Float64Data is a concrete implementation of Data for float64 scalar metrics.
    45  type Float64Data struct {
    46  	// Info holds the original construction information.
    47  	Info *Scalar
    48  	// IsGauge is true for metrics that track values, rather than increasing over time.
    49  	IsGauge bool
    50  	// Rows holds the per group values for the metric.
    51  	Rows []float64
    52  	// End is the last time this metric was updated.
    53  	EndTime time.Time
    54  
    55  	groups [][]label.Label
    56  	key    *keys.Float64
    57  }
    58  
    59  // HistogramInt64Data is a concrete implementation of Data for int64 histogram metrics.
    60  type HistogramInt64Data struct {
    61  	// Info holds the original construction information.
    62  	Info *HistogramInt64
    63  	// Rows holds the per group values for the metric.
    64  	Rows []*HistogramInt64Row
    65  	// End is the last time this metric was updated.
    66  	EndTime time.Time
    67  
    68  	groups [][]label.Label
    69  	key    *keys.Int64
    70  }
    71  
    72  // HistogramInt64Row holds the values for a single row of a HistogramInt64Data.
    73  type HistogramInt64Row struct {
    74  	// Values is the counts per bucket.
    75  	Values []int64
    76  	// Count is the total count.
    77  	Count int64
    78  	// Sum is the sum of all the values recorded.
    79  	Sum int64
    80  	// Min is the smallest recorded value.
    81  	Min int64
    82  	// Max is the largest recorded value.
    83  	Max int64
    84  }
    85  
    86  // HistogramFloat64Data is a concrete implementation of Data for float64 histogram metrics.
    87  type HistogramFloat64Data struct {
    88  	// Info holds the original construction information.
    89  	Info *HistogramFloat64
    90  	// Rows holds the per group values for the metric.
    91  	Rows []*HistogramFloat64Row
    92  	// End is the last time this metric was updated.
    93  	EndTime time.Time
    94  
    95  	groups [][]label.Label
    96  	key    *keys.Float64
    97  }
    98  
    99  // HistogramFloat64Row holds the values for a single row of a HistogramFloat64Data.
   100  type HistogramFloat64Row struct {
   101  	// Values is the counts per bucket.
   102  	Values []int64
   103  	// Count is the total count.
   104  	Count int64
   105  	// Sum is the sum of all the values recorded.
   106  	Sum float64
   107  	// Min is the smallest recorded value.
   108  	Min float64
   109  	// Max is the largest recorded value.
   110  	Max float64
   111  }
   112  
   113  func labelListEqual(a, b []label.Label) bool {
   114  	//TODO: make this more efficient
   115  	return fmt.Sprint(a) == fmt.Sprint(b)
   116  }
   117  
   118  func labelListLess(a, b []label.Label) bool {
   119  	//TODO: make this more efficient
   120  	return fmt.Sprint(a) < fmt.Sprint(b)
   121  }
   122  
   123  func getGroup(lm label.Map, g *[][]label.Label, keys []label.Key) (int, bool) {
   124  	group := make([]label.Label, len(keys))
   125  	for i, key := range keys {
   126  		l := lm.Find(key)
   127  		if l.Valid() {
   128  			group[i] = l
   129  		}
   130  	}
   131  	old := *g
   132  	index := sort.Search(len(old), func(i int) bool {
   133  		return !labelListLess(old[i], group)
   134  	})
   135  	if index < len(old) && labelListEqual(group, old[index]) {
   136  		// not a new group
   137  		return index, false
   138  	}
   139  	*g = make([][]label.Label, len(old)+1)
   140  	copy(*g, old[:index])
   141  	copy((*g)[index+1:], old[index:])
   142  	(*g)[index] = group
   143  	return index, true
   144  }
   145  
   146  func (data *Int64Data) Handle() string          { return data.Info.Name }
   147  func (data *Int64Data) Groups() [][]label.Label { return data.groups }
   148  
   149  func (data *Int64Data) modify(at time.Time, lm label.Map, f func(v int64) int64) Data {
   150  	index, insert := getGroup(lm, &data.groups, data.Info.Keys)
   151  	old := data.Rows
   152  	if insert {
   153  		data.Rows = make([]int64, len(old)+1)
   154  		copy(data.Rows, old[:index])
   155  		copy(data.Rows[index+1:], old[index:])
   156  	} else {
   157  		data.Rows = make([]int64, len(old))
   158  		copy(data.Rows, old)
   159  	}
   160  	data.Rows[index] = f(data.Rows[index])
   161  	data.EndTime = at
   162  	frozen := *data
   163  	return &frozen
   164  }
   165  
   166  func (data *Int64Data) count(at time.Time, lm label.Map, l label.Label) Data {
   167  	return data.modify(at, lm, func(v int64) int64 {
   168  		return v + 1
   169  	})
   170  }
   171  
   172  func (data *Int64Data) sum(at time.Time, lm label.Map, l label.Label) Data {
   173  	return data.modify(at, lm, func(v int64) int64 {
   174  		return v + data.key.From(l)
   175  	})
   176  }
   177  
   178  func (data *Int64Data) latest(at time.Time, lm label.Map, l label.Label) Data {
   179  	return data.modify(at, lm, func(v int64) int64 {
   180  		return data.key.From(l)
   181  	})
   182  }
   183  
   184  func (data *Float64Data) Handle() string          { return data.Info.Name }
   185  func (data *Float64Data) Groups() [][]label.Label { return data.groups }
   186  
   187  func (data *Float64Data) modify(at time.Time, lm label.Map, f func(v float64) float64) Data {
   188  	index, insert := getGroup(lm, &data.groups, data.Info.Keys)
   189  	old := data.Rows
   190  	if insert {
   191  		data.Rows = make([]float64, len(old)+1)
   192  		copy(data.Rows, old[:index])
   193  		copy(data.Rows[index+1:], old[index:])
   194  	} else {
   195  		data.Rows = make([]float64, len(old))
   196  		copy(data.Rows, old)
   197  	}
   198  	data.Rows[index] = f(data.Rows[index])
   199  	data.EndTime = at
   200  	frozen := *data
   201  	return &frozen
   202  }
   203  
   204  func (data *Float64Data) sum(at time.Time, lm label.Map, l label.Label) Data {
   205  	return data.modify(at, lm, func(v float64) float64 {
   206  		return v + data.key.From(l)
   207  	})
   208  }
   209  
   210  func (data *Float64Data) latest(at time.Time, lm label.Map, l label.Label) Data {
   211  	return data.modify(at, lm, func(v float64) float64 {
   212  		return data.key.From(l)
   213  	})
   214  }
   215  
   216  func (data *HistogramInt64Data) Handle() string          { return data.Info.Name }
   217  func (data *HistogramInt64Data) Groups() [][]label.Label { return data.groups }
   218  
   219  func (data *HistogramInt64Data) modify(at time.Time, lm label.Map, f func(v *HistogramInt64Row)) Data {
   220  	index, insert := getGroup(lm, &data.groups, data.Info.Keys)
   221  	old := data.Rows
   222  	var v HistogramInt64Row
   223  	if insert {
   224  		data.Rows = make([]*HistogramInt64Row, len(old)+1)
   225  		copy(data.Rows, old[:index])
   226  		copy(data.Rows[index+1:], old[index:])
   227  	} else {
   228  		data.Rows = make([]*HistogramInt64Row, len(old))
   229  		copy(data.Rows, old)
   230  		v = *data.Rows[index]
   231  	}
   232  	oldValues := v.Values
   233  	v.Values = make([]int64, len(data.Info.Buckets))
   234  	copy(v.Values, oldValues)
   235  	f(&v)
   236  	data.Rows[index] = &v
   237  	data.EndTime = at
   238  	frozen := *data
   239  	return &frozen
   240  }
   241  
   242  func (data *HistogramInt64Data) record(at time.Time, lm label.Map, l label.Label) Data {
   243  	return data.modify(at, lm, func(v *HistogramInt64Row) {
   244  		value := data.key.From(l)
   245  		v.Sum += value
   246  		if v.Min > value || v.Count == 0 {
   247  			v.Min = value
   248  		}
   249  		if v.Max < value || v.Count == 0 {
   250  			v.Max = value
   251  		}
   252  		v.Count++
   253  		for i, b := range data.Info.Buckets {
   254  			if value <= b {
   255  				v.Values[i]++
   256  			}
   257  		}
   258  	})
   259  }
   260  
   261  func (data *HistogramFloat64Data) Handle() string          { return data.Info.Name }
   262  func (data *HistogramFloat64Data) Groups() [][]label.Label { return data.groups }
   263  
   264  func (data *HistogramFloat64Data) modify(at time.Time, lm label.Map, f func(v *HistogramFloat64Row)) Data {
   265  	index, insert := getGroup(lm, &data.groups, data.Info.Keys)
   266  	old := data.Rows
   267  	var v HistogramFloat64Row
   268  	if insert {
   269  		data.Rows = make([]*HistogramFloat64Row, len(old)+1)
   270  		copy(data.Rows, old[:index])
   271  		copy(data.Rows[index+1:], old[index:])
   272  	} else {
   273  		data.Rows = make([]*HistogramFloat64Row, len(old))
   274  		copy(data.Rows, old)
   275  		v = *data.Rows[index]
   276  	}
   277  	oldValues := v.Values
   278  	v.Values = make([]int64, len(data.Info.Buckets))
   279  	copy(v.Values, oldValues)
   280  	f(&v)
   281  	data.Rows[index] = &v
   282  	data.EndTime = at
   283  	frozen := *data
   284  	return &frozen
   285  }
   286  
   287  func (data *HistogramFloat64Data) record(at time.Time, lm label.Map, l label.Label) Data {
   288  	return data.modify(at, lm, func(v *HistogramFloat64Row) {
   289  		value := data.key.From(l)
   290  		v.Sum += value
   291  		if v.Min > value || v.Count == 0 {
   292  			v.Min = value
   293  		}
   294  		if v.Max < value || v.Count == 0 {
   295  			v.Max = value
   296  		}
   297  		v.Count++
   298  		for i, b := range data.Info.Buckets {
   299  			if value <= b {
   300  				v.Values[i]++
   301  			}
   302  		}
   303  	})
   304  }