github.com/v2fly/tools@v0.100.0/internal/event/export/ocagent/metrics.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 ocagent
     6  
     7  import (
     8  	"time"
     9  
    10  	"github.com/v2fly/tools/internal/event/export/metric"
    11  	"github.com/v2fly/tools/internal/event/export/ocagent/wire"
    12  	"github.com/v2fly/tools/internal/event/label"
    13  )
    14  
    15  // dataToMetricDescriptor return a *wire.MetricDescriptor based on data.
    16  func dataToMetricDescriptor(data metric.Data) *wire.MetricDescriptor {
    17  	if data == nil {
    18  		return nil
    19  	}
    20  	descriptor := &wire.MetricDescriptor{
    21  		Name:        data.Handle(),
    22  		Description: getDescription(data),
    23  		// TODO: Unit?
    24  		Type:      dataToMetricDescriptorType(data),
    25  		LabelKeys: getLabelKeys(data),
    26  	}
    27  
    28  	return descriptor
    29  }
    30  
    31  // getDescription returns the description of data.
    32  func getDescription(data metric.Data) string {
    33  	switch d := data.(type) {
    34  	case *metric.Int64Data:
    35  		return d.Info.Description
    36  
    37  	case *metric.Float64Data:
    38  		return d.Info.Description
    39  
    40  	case *metric.HistogramInt64Data:
    41  		return d.Info.Description
    42  
    43  	case *metric.HistogramFloat64Data:
    44  		return d.Info.Description
    45  	}
    46  
    47  	return ""
    48  }
    49  
    50  // getLabelKeys returns a slice of *wire.LabelKeys based on the keys
    51  // in data.
    52  func getLabelKeys(data metric.Data) []*wire.LabelKey {
    53  	switch d := data.(type) {
    54  	case *metric.Int64Data:
    55  		return infoKeysToLabelKeys(d.Info.Keys)
    56  
    57  	case *metric.Float64Data:
    58  		return infoKeysToLabelKeys(d.Info.Keys)
    59  
    60  	case *metric.HistogramInt64Data:
    61  		return infoKeysToLabelKeys(d.Info.Keys)
    62  
    63  	case *metric.HistogramFloat64Data:
    64  		return infoKeysToLabelKeys(d.Info.Keys)
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // dataToMetricDescriptorType returns a wire.MetricDescriptor_Type based on the
    71  // underlying type of data.
    72  func dataToMetricDescriptorType(data metric.Data) wire.MetricDescriptor_Type {
    73  	switch d := data.(type) {
    74  	case *metric.Int64Data:
    75  		if d.IsGauge {
    76  			return wire.MetricDescriptor_GAUGE_INT64
    77  		}
    78  		return wire.MetricDescriptor_CUMULATIVE_INT64
    79  
    80  	case *metric.Float64Data:
    81  		if d.IsGauge {
    82  			return wire.MetricDescriptor_GAUGE_DOUBLE
    83  		}
    84  		return wire.MetricDescriptor_CUMULATIVE_DOUBLE
    85  
    86  	case *metric.HistogramInt64Data:
    87  		return wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION
    88  
    89  	case *metric.HistogramFloat64Data:
    90  		return wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION
    91  	}
    92  
    93  	return wire.MetricDescriptor_UNSPECIFIED
    94  }
    95  
    96  // dataToTimeseries returns a slice of *wire.TimeSeries based on the
    97  // points in data.
    98  func dataToTimeseries(data metric.Data, start time.Time) []*wire.TimeSeries {
    99  	if data == nil {
   100  		return nil
   101  	}
   102  
   103  	numRows := numRows(data)
   104  	startTimestamp := convertTimestamp(start)
   105  	timeseries := make([]*wire.TimeSeries, 0, numRows)
   106  
   107  	for i := 0; i < numRows; i++ {
   108  		timeseries = append(timeseries, &wire.TimeSeries{
   109  			StartTimestamp: &startTimestamp,
   110  			// TODO: labels?
   111  			Points: dataToPoints(data, i),
   112  		})
   113  	}
   114  
   115  	return timeseries
   116  }
   117  
   118  // numRows returns the number of rows in data.
   119  func numRows(data metric.Data) int {
   120  	switch d := data.(type) {
   121  	case *metric.Int64Data:
   122  		return len(d.Rows)
   123  	case *metric.Float64Data:
   124  		return len(d.Rows)
   125  	case *metric.HistogramInt64Data:
   126  		return len(d.Rows)
   127  	case *metric.HistogramFloat64Data:
   128  		return len(d.Rows)
   129  	}
   130  
   131  	return 0
   132  }
   133  
   134  // dataToPoints returns an array of *wire.Points based on the point(s)
   135  // in data at index i.
   136  func dataToPoints(data metric.Data, i int) []*wire.Point {
   137  	switch d := data.(type) {
   138  	case *metric.Int64Data:
   139  		timestamp := convertTimestamp(d.EndTime)
   140  		return []*wire.Point{
   141  			{
   142  				Value: wire.PointInt64Value{
   143  					Int64Value: d.Rows[i],
   144  				},
   145  				Timestamp: &timestamp,
   146  			},
   147  		}
   148  	case *metric.Float64Data:
   149  		timestamp := convertTimestamp(d.EndTime)
   150  		return []*wire.Point{
   151  			{
   152  				Value: wire.PointDoubleValue{
   153  					DoubleValue: d.Rows[i],
   154  				},
   155  				Timestamp: &timestamp,
   156  			},
   157  		}
   158  	case *metric.HistogramInt64Data:
   159  		row := d.Rows[i]
   160  		bucketBounds := make([]float64, len(d.Info.Buckets))
   161  		for i, val := range d.Info.Buckets {
   162  			bucketBounds[i] = float64(val)
   163  		}
   164  		return distributionToPoints(row.Values, row.Count, float64(row.Sum), bucketBounds, d.EndTime)
   165  	case *metric.HistogramFloat64Data:
   166  		row := d.Rows[i]
   167  		return distributionToPoints(row.Values, row.Count, row.Sum, d.Info.Buckets, d.EndTime)
   168  	}
   169  
   170  	return nil
   171  }
   172  
   173  // distributionToPoints returns an array of *wire.Points containing a
   174  // wire.PointDistributionValue representing a distribution with the
   175  // supplied counts, count, and sum.
   176  func distributionToPoints(counts []int64, count int64, sum float64, bucketBounds []float64, end time.Time) []*wire.Point {
   177  	buckets := make([]*wire.Bucket, len(counts))
   178  	for i := 0; i < len(counts); i++ {
   179  		buckets[i] = &wire.Bucket{
   180  			Count: counts[i],
   181  		}
   182  	}
   183  	timestamp := convertTimestamp(end)
   184  	return []*wire.Point{
   185  		{
   186  			Value: wire.PointDistributionValue{
   187  				DistributionValue: &wire.DistributionValue{
   188  					Count: count,
   189  					Sum:   sum,
   190  					// TODO: SumOfSquaredDeviation?
   191  					Buckets: buckets,
   192  					BucketOptions: &wire.BucketOptionsExplicit{
   193  						Bounds: bucketBounds,
   194  					},
   195  				},
   196  			},
   197  			Timestamp: &timestamp,
   198  		},
   199  	}
   200  }
   201  
   202  // infoKeysToLabelKeys returns an array of *wire.LabelKeys containing the
   203  // string values of the elements of labelKeys.
   204  func infoKeysToLabelKeys(infoKeys []label.Key) []*wire.LabelKey {
   205  	labelKeys := make([]*wire.LabelKey, 0, len(infoKeys))
   206  	for _, key := range infoKeys {
   207  		labelKeys = append(labelKeys, &wire.LabelKey{
   208  			Key: key.Name(),
   209  		})
   210  	}
   211  
   212  	return labelKeys
   213  }