github.com/m3db/m3@v1.5.0/src/metrics/aggregation/types_options.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package aggregation
    22  
    23  import (
    24  	"bytes"
    25  	"strconv"
    26  	"strings"
    27  
    28  	"github.com/m3db/m3/src/metrics/metric"
    29  	"github.com/m3db/m3/src/x/pool"
    30  )
    31  
    32  // QuantileTypeStringFn returns the type string for a quantile value.
    33  type QuantileTypeStringFn func(quantile float64) []byte
    34  
    35  // TypeStringTransformFn transforms the type string.
    36  type TypeStringTransformFn func(typeString []byte) []byte
    37  
    38  // TypesOptions provides a set of options for aggregation types.
    39  type TypesOptions interface {
    40  	// Read-Write methods.
    41  
    42  	// SetDefaultCounterAggregationTypes sets the default aggregation types for counters.
    43  	SetDefaultCounterAggregationTypes(value Types) TypesOptions
    44  
    45  	// DefaultCounterAggregationTypes returns the default aggregation types for counters.
    46  	DefaultCounterAggregationTypes() Types
    47  
    48  	// SetDefaultTimerAggregationTypes sets the default aggregation types for timers.
    49  	SetDefaultTimerAggregationTypes(value Types) TypesOptions
    50  
    51  	// DefaultTimerAggregationTypes returns the default aggregation types for timers.
    52  	DefaultTimerAggregationTypes() Types
    53  
    54  	// SetDefaultGaugeAggregationTypes sets the default aggregation types for gauges.
    55  	SetDefaultGaugeAggregationTypes(value Types) TypesOptions
    56  
    57  	// DefaultGaugeAggregationTypes returns the default aggregation types for gauges.
    58  	DefaultGaugeAggregationTypes() Types
    59  
    60  	// SetQuantileTypeStringFn sets the quantile type string function for timers.
    61  	SetQuantileTypeStringFn(value QuantileTypeStringFn) TypesOptions
    62  
    63  	// QuantileTypeStringFn returns the quantile type string function for timers.
    64  	QuantileTypeStringFn() QuantileTypeStringFn
    65  
    66  	// SetCounterTypeStringTransformFn sets the transformation function for counter type strings.
    67  	SetCounterTypeStringTransformFn(value TypeStringTransformFn) TypesOptions
    68  
    69  	// CounterTypeStringTransformFn returns the transformation function for counter type strings.
    70  	CounterTypeStringTransformFn() TypeStringTransformFn
    71  
    72  	// SetTimerTypeStringTransformFn sets the transformation function for timer type strings.
    73  	SetTimerTypeStringTransformFn(value TypeStringTransformFn) TypesOptions
    74  
    75  	// TimerTypeStringTransformFn returns the transformation function for timer type strings.
    76  	TimerTypeStringTransformFn() TypeStringTransformFn
    77  
    78  	// SetGaugeTypeStringTransformFn sets the transformation function for gauge type strings.
    79  	SetGaugeTypeStringTransformFn(value TypeStringTransformFn) TypesOptions
    80  
    81  	// GaugeTypeStringTransformFn returns the transformation function for gauge type strings.
    82  	GaugeTypeStringTransformFn() TypeStringTransformFn
    83  
    84  	// SetTypesPool sets the aggregation types pool.
    85  	SetTypesPool(pool TypesPool) TypesOptions
    86  
    87  	// TypesPool returns the aggregation types pool.
    88  	TypesPool() TypesPool
    89  
    90  	// SetQuantilesPool sets the timer quantiles pool.
    91  	SetQuantilesPool(pool pool.FloatsPool) TypesOptions
    92  
    93  	// QuantilesPool returns the timer quantiles pool.
    94  	QuantilesPool() pool.FloatsPool
    95  
    96  	// Read only methods.
    97  
    98  	// TypeStringForCounter returns the type string for the aggregation type for counters.
    99  	TypeStringForCounter(value Type) []byte
   100  
   101  	// TypeStringForTimer returns the type string for the aggregation type for timers.
   102  	TypeStringForTimer(value Type) []byte
   103  
   104  	// TypeStringForGauge returns the type string for the aggregation type for gauges.
   105  	TypeStringForGauge(value Type) []byte
   106  
   107  	// TypeForCounter returns the aggregation type for given counter type string.
   108  	TypeForCounter(value []byte) Type
   109  
   110  	// TypeForTimer returns the aggregation type for given timer type string.
   111  	TypeForTimer(value []byte) Type
   112  
   113  	// TypeForGauge returns the aggregation type for given gauge type string.
   114  	TypeForGauge(value []byte) Type
   115  
   116  	// Quantiles returns the quantiles for timers.
   117  	Quantiles() []float64
   118  
   119  	// IsContainedInDefaultAggregationTypes checks if the given aggregation type is
   120  	// contained in the default aggregation types for the metric type.
   121  	IsContainedInDefaultAggregationTypes(at Type, mt metric.Type) bool
   122  }
   123  
   124  var (
   125  	defaultDefaultCounterAggregationTypes = Types{
   126  		Sum,
   127  	}
   128  	defaultDefaultTimerAggregationTypes = Types{
   129  		Sum,
   130  		SumSq,
   131  		Mean,
   132  		Min,
   133  		Max,
   134  		Count,
   135  		Stdev,
   136  		Median,
   137  		P50,
   138  		P95,
   139  		P99,
   140  	}
   141  	defaultDefaultGaugeAggregationTypes = Types{
   142  		Last,
   143  	}
   144  	defaultTypeStringsMap = map[Type][]byte{
   145  		Last:   []byte("last"),
   146  		Sum:    []byte("sum"),
   147  		SumSq:  []byte("sum_sq"),
   148  		Mean:   []byte("mean"),
   149  		Min:    []byte("lower"),
   150  		Max:    []byte("upper"),
   151  		Count:  []byte("count"),
   152  		Stdev:  []byte("stdev"),
   153  		Median: []byte("median"),
   154  	}
   155  )
   156  
   157  type options struct {
   158  	defaultCounterAggregationTypes Types
   159  	defaultTimerAggregationTypes   Types
   160  	defaultGaugeAggregationTypes   Types
   161  	quantileTypeStringFn           QuantileTypeStringFn
   162  	counterTypeStringTransformFn   TypeStringTransformFn
   163  	timerTypeStringTransformFn     TypeStringTransformFn
   164  	gaugeTypeStringTransformFn     TypeStringTransformFn
   165  	aggTypesPool                   TypesPool
   166  	quantilesPool                  pool.FloatsPool
   167  
   168  	counterTypeStrings [][]byte
   169  	timerTypeStrings   [][]byte
   170  	gaugeTypeStrings   [][]byte
   171  	quantiles          []float64
   172  }
   173  
   174  // NewTypesOptions returns a default TypesOptions.
   175  func NewTypesOptions() TypesOptions {
   176  	o := &options{
   177  		defaultCounterAggregationTypes: defaultDefaultCounterAggregationTypes,
   178  		defaultGaugeAggregationTypes:   defaultDefaultGaugeAggregationTypes,
   179  		defaultTimerAggregationTypes:   defaultDefaultTimerAggregationTypes,
   180  		quantileTypeStringFn:           defaultQuantileTypeStringFn,
   181  		counterTypeStringTransformFn:   NoOpTransform,
   182  		timerTypeStringTransformFn:     NoOpTransform,
   183  		gaugeTypeStringTransformFn:     NoOpTransform,
   184  	}
   185  	o.initPools()
   186  	o.computeAllDerived()
   187  	return o
   188  }
   189  
   190  func (o *options) initPools() {
   191  	o.aggTypesPool = NewTypesPool(nil)
   192  	o.aggTypesPool.Init(func() Types {
   193  		return make(Types, 0, len(ValidTypes))
   194  	})
   195  
   196  	o.quantilesPool = pool.NewFloatsPool(nil, nil)
   197  	o.quantilesPool.Init()
   198  }
   199  
   200  func (o *options) SetDefaultCounterAggregationTypes(aggTypes Types) TypesOptions {
   201  	opts := *o
   202  	opts.defaultCounterAggregationTypes = aggTypes
   203  	opts.computeAllDerived()
   204  	return &opts
   205  }
   206  
   207  func (o *options) DefaultCounterAggregationTypes() Types {
   208  	return o.defaultCounterAggregationTypes
   209  }
   210  
   211  func (o *options) SetDefaultTimerAggregationTypes(aggTypes Types) TypesOptions {
   212  	opts := *o
   213  	opts.defaultTimerAggregationTypes = aggTypes
   214  	opts.computeAllDerived()
   215  	return &opts
   216  }
   217  
   218  func (o *options) DefaultTimerAggregationTypes() Types {
   219  	return o.defaultTimerAggregationTypes
   220  }
   221  
   222  func (o *options) SetDefaultGaugeAggregationTypes(aggTypes Types) TypesOptions {
   223  	opts := *o
   224  	opts.defaultGaugeAggregationTypes = aggTypes
   225  	opts.computeAllDerived()
   226  	return &opts
   227  }
   228  
   229  func (o *options) DefaultGaugeAggregationTypes() Types {
   230  	return o.defaultGaugeAggregationTypes
   231  }
   232  
   233  func (o *options) SetQuantileTypeStringFn(value QuantileTypeStringFn) TypesOptions {
   234  	opts := *o
   235  	opts.quantileTypeStringFn = value
   236  	opts.computeAllDerived()
   237  	return &opts
   238  }
   239  
   240  func (o *options) QuantileTypeStringFn() QuantileTypeStringFn {
   241  	return o.quantileTypeStringFn
   242  }
   243  
   244  func (o *options) SetCounterTypeStringTransformFn(value TypeStringTransformFn) TypesOptions {
   245  	opts := *o
   246  	opts.counterTypeStringTransformFn = value
   247  	opts.computeAllDerived()
   248  	return &opts
   249  }
   250  
   251  func (o *options) CounterTypeStringTransformFn() TypeStringTransformFn {
   252  	return o.counterTypeStringTransformFn
   253  }
   254  
   255  func (o *options) SetTimerTypeStringTransformFn(value TypeStringTransformFn) TypesOptions {
   256  	opts := *o
   257  	opts.timerTypeStringTransformFn = value
   258  	opts.computeAllDerived()
   259  	return &opts
   260  }
   261  
   262  func (o *options) TimerTypeStringTransformFn() TypeStringTransformFn {
   263  	return o.timerTypeStringTransformFn
   264  }
   265  
   266  func (o *options) SetGaugeTypeStringTransformFn(value TypeStringTransformFn) TypesOptions {
   267  	opts := *o
   268  	opts.gaugeTypeStringTransformFn = value
   269  	opts.computeAllDerived()
   270  	return &opts
   271  }
   272  
   273  func (o *options) GaugeTypeStringTransformFn() TypeStringTransformFn {
   274  	return o.gaugeTypeStringTransformFn
   275  }
   276  
   277  func (o *options) SetTypesPool(pool TypesPool) TypesOptions {
   278  	opts := *o
   279  	opts.aggTypesPool = pool
   280  	return &opts
   281  }
   282  
   283  func (o *options) TypesPool() TypesPool {
   284  	return o.aggTypesPool
   285  }
   286  
   287  func (o *options) SetQuantilesPool(pool pool.FloatsPool) TypesOptions {
   288  	opts := *o
   289  	opts.quantilesPool = pool
   290  	return &opts
   291  }
   292  
   293  func (o *options) QuantilesPool() pool.FloatsPool {
   294  	return o.quantilesPool
   295  }
   296  
   297  func (o *options) TypeStringForCounter(aggType Type) []byte {
   298  	return o.counterTypeStrings[aggType.ID()]
   299  }
   300  
   301  func (o *options) TypeStringForTimer(aggType Type) []byte {
   302  	return o.timerTypeStrings[aggType.ID()]
   303  }
   304  
   305  func (o *options) TypeStringForGauge(aggType Type) []byte {
   306  	return o.gaugeTypeStrings[aggType.ID()]
   307  }
   308  
   309  func (o *options) TypeForCounter(value []byte) Type {
   310  	return typeFor(value, o.counterTypeStrings)
   311  }
   312  
   313  func (o *options) TypeForTimer(value []byte) Type {
   314  	return typeFor(value, o.timerTypeStrings)
   315  }
   316  
   317  func (o *options) TypeForGauge(value []byte) Type {
   318  	return typeFor(value, o.gaugeTypeStrings)
   319  }
   320  
   321  func (o *options) Quantiles() []float64 {
   322  	return o.quantiles
   323  }
   324  
   325  func (o *options) IsContainedInDefaultAggregationTypes(at Type, mt metric.Type) bool {
   326  	var aggTypes Types
   327  	switch mt {
   328  	case metric.CounterType:
   329  		aggTypes = o.DefaultCounterAggregationTypes()
   330  	case metric.GaugeType:
   331  		aggTypes = o.DefaultGaugeAggregationTypes()
   332  	case metric.TimerType:
   333  		aggTypes = o.DefaultTimerAggregationTypes()
   334  	}
   335  	return aggTypes.Contains(at)
   336  }
   337  
   338  func (o *options) computeAllDerived() {
   339  	o.computeQuantiles()
   340  	o.computeCounterTypeStrings()
   341  	o.computeTimerTypeStrings()
   342  	o.computeGaugeTypeStrings()
   343  }
   344  
   345  func (o *options) computeQuantiles() {
   346  	o.quantiles, _ = o.DefaultTimerAggregationTypes().PooledQuantiles(o.QuantilesPool())
   347  }
   348  
   349  func (o *options) computeCounterTypeStrings() {
   350  	o.counterTypeStrings = o.computeTypeStrings(o.counterTypeStringTransformFn)
   351  }
   352  
   353  func (o *options) computeTimerTypeStrings() {
   354  	o.timerTypeStrings = o.computeTypeStrings(o.timerTypeStringTransformFn)
   355  }
   356  
   357  func (o *options) computeGaugeTypeStrings() {
   358  	o.gaugeTypeStrings = o.computeTypeStrings(o.gaugeTypeStringTransformFn)
   359  }
   360  
   361  func (o *options) computeTypeStrings(transformFn TypeStringTransformFn) [][]byte {
   362  	res := make([][]byte, maxTypeID+1)
   363  	for aggType := range ValidTypes {
   364  		var typeString []byte
   365  		if typeStr, exist := defaultTypeStringsMap[aggType]; exist {
   366  			typeString = typeStr
   367  		} else {
   368  			q, ok := aggType.Quantile()
   369  			if ok {
   370  				typeString = o.quantileTypeStringFn(q)
   371  			}
   372  		}
   373  		transformed := transformFn(typeString)
   374  		res[aggType.ID()] = transformed
   375  	}
   376  	return res
   377  }
   378  
   379  func typeFor(value []byte, typeStrings [][]byte) Type {
   380  	for id, typeString := range typeStrings {
   381  		if !bytes.Equal(value, typeString) {
   382  			continue
   383  		}
   384  		if t := Type(id); t.IsValid() {
   385  			return t
   386  		}
   387  	}
   388  	return UnknownType
   389  }
   390  
   391  // By default we use e.g. "p50", "p95", "p99" for the 50th/95th/99th percentile.
   392  func defaultQuantileTypeStringFn(quantile float64) []byte {
   393  	str := strconv.FormatFloat(quantile*100, 'f', -1, 64)
   394  	idx := strings.Index(str, ".")
   395  	if idx != -1 {
   396  		str = str[:idx] + str[idx+1:]
   397  	}
   398  	return []byte("p" + str)
   399  }
   400  
   401  // NoOpTransform returns the input byte slice as is.
   402  func NoOpTransform(b []byte) []byte { return b }
   403  
   404  // EmptyTransform transforms the input byte slice to an empty byte slice.
   405  func EmptyTransform(b []byte) []byte { return nil }
   406  
   407  // SuffixTransform transforms the input byte slice to a suffix by prepending
   408  // a dot at the beginning.
   409  func SuffixTransform(b []byte) []byte { return append([]byte("."), b...) }