github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/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...) }