...

Source file src/go.opencensus.io/metric/common.go

Documentation: go.opencensus.io/metric

     1  // Copyright 2019, OpenCensus Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package metric
    16  
    17  import (
    18  	"sync"
    19  	"time"
    20  
    21  	"go.opencensus.io/internal/tagencoding"
    22  
    23  	"go.opencensus.io/metric/metricdata"
    24  )
    25  
    26  // baseMetric is common representation for gauge and cumulative metrics.
    27  //
    28  // baseMetric maintains a value for each combination of label values passed to
    29  // Set, Add, or Inc method.
    30  //
    31  // baseMetric should not be used directly, use metric specific type such as
    32  // Float64Gauge or Int64Gauge.
    33  type baseMetric struct {
    34  	vals             sync.Map
    35  	desc             metricdata.Descriptor
    36  	start            time.Time
    37  	keys             []metricdata.LabelKey
    38  	constLabelValues []metricdata.LabelValue
    39  	bmType           baseMetricType
    40  }
    41  
    42  type baseMetricType int
    43  
    44  const (
    45  	gaugeInt64 baseMetricType = iota
    46  	gaugeFloat64
    47  	derivedGaugeInt64
    48  	derivedGaugeFloat64
    49  	cumulativeInt64
    50  	cumulativeFloat64
    51  	derivedCumulativeInt64
    52  	derivedCumulativeFloat64
    53  )
    54  
    55  type baseEntry interface {
    56  	read(t time.Time) metricdata.Point
    57  }
    58  
    59  func (bm *baseMetric) startTime() *time.Time {
    60  	switch bm.bmType {
    61  	case cumulativeInt64, cumulativeFloat64, derivedCumulativeInt64, derivedCumulativeFloat64:
    62  		return &bm.start
    63  	default:
    64  		// gauges don't have start time.
    65  		return nil
    66  	}
    67  }
    68  
    69  // Read returns the current values of the baseMetric as a metric for export.
    70  func (bm *baseMetric) read() *metricdata.Metric {
    71  	now := time.Now()
    72  	startTime := bm.startTime()
    73  	if startTime == nil {
    74  		startTime = &now
    75  	}
    76  	m := &metricdata.Metric{
    77  		Descriptor: bm.desc,
    78  	}
    79  	bm.vals.Range(func(k, v interface{}) bool {
    80  		entry := v.(baseEntry)
    81  		key := k.(string)
    82  		labelVals := bm.decodeLabelVals(key)
    83  		m.TimeSeries = append(m.TimeSeries, &metricdata.TimeSeries{
    84  			StartTime:   *startTime,
    85  			LabelValues: labelVals,
    86  			Points: []metricdata.Point{
    87  				entry.read(now),
    88  			},
    89  		})
    90  		return true
    91  	})
    92  	return m
    93  }
    94  
    95  func (bm *baseMetric) encodeLabelVals(labelVals []metricdata.LabelValue) string {
    96  	vb := &tagencoding.Values{}
    97  	for _, v := range labelVals {
    98  		b := make([]byte, 1, len(v.Value)+1)
    99  		if v.Present {
   100  			b[0] = 1
   101  			b = append(b, []byte(v.Value)...)
   102  		}
   103  		vb.WriteValue(b)
   104  	}
   105  	return string(vb.Bytes())
   106  }
   107  
   108  func (bm *baseMetric) decodeLabelVals(s string) []metricdata.LabelValue {
   109  	vals := make([]metricdata.LabelValue, 0, len(bm.keys))
   110  	vb := &tagencoding.Values{Buffer: []byte(s)}
   111  	for range bm.keys {
   112  		v := vb.ReadValue()
   113  		if v[0] == 0 {
   114  			vals = append(vals, metricdata.LabelValue{})
   115  		} else {
   116  			vals = append(vals, metricdata.NewLabelValue(string(v[1:])))
   117  		}
   118  	}
   119  	return vals
   120  }
   121  
   122  func (bm *baseMetric) entryForValues(labelVals []metricdata.LabelValue, newEntry func() baseEntry) (interface{}, error) {
   123  	labelVals = append(bm.constLabelValues, labelVals...)
   124  	if len(labelVals) != len(bm.keys) {
   125  		return nil, errKeyValueMismatch
   126  	}
   127  	mapKey := bm.encodeLabelVals(labelVals)
   128  	if entry, ok := bm.vals.Load(mapKey); ok {
   129  		return entry, nil
   130  	}
   131  	entry, _ := bm.vals.LoadOrStore(mapKey, newEntry())
   132  	return entry, nil
   133  }
   134  
   135  func (bm *baseMetric) upsertEntry(labelVals []metricdata.LabelValue, newEntry func() baseEntry) error {
   136  	labelVals = append(bm.constLabelValues, labelVals...)
   137  	if len(labelVals) != len(bm.keys) {
   138  		return errKeyValueMismatch
   139  	}
   140  	mapKey := bm.encodeLabelVals(labelVals)
   141  	bm.vals.Delete(mapKey)
   142  	bm.vals.Store(mapKey, newEntry())
   143  	return nil
   144  }
   145  

View as plain text