dubbo.apache.org/dubbo-go/v3@v3.1.1/metrics/util/aggregate/aggregator.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package aggregate 19 20 import ( 21 "math" 22 "sync" 23 "time" 24 ) 25 26 // TimeWindowAggregator wrappers sliding window to aggregate data. 27 // 28 // It is concurrent-safe. 29 // It uses custom struct aggregator to aggregate data. 30 // The window is divided into several panes, and each pane's value is an aggregator instance. 31 type TimeWindowAggregator struct { 32 window *slidingWindow 33 mux sync.RWMutex 34 } 35 36 func NewTimeWindowAggregator(paneCount int, timeWindowSeconds int64) *TimeWindowAggregator { 37 return &TimeWindowAggregator{ 38 window: newSlidingWindow(paneCount, timeWindowSeconds*1000), 39 } 40 } 41 42 type Result struct { 43 Total float64 44 Min float64 45 Max float64 46 Avg float64 47 Count uint64 48 Last float64 49 } 50 51 func NewResult() *Result { 52 return &Result{ 53 Min: math.MaxFloat64, 54 Max: math.SmallestNonzeroFloat64, 55 Last: math.NaN(), 56 } 57 } 58 59 func (r *Result) Update(v float64) { 60 r.Min = math.Min(r.Min, v) 61 r.Max = math.Max(r.Max, v) 62 r.Last = v 63 r.Total += v 64 r.Count++ 65 } 66 67 func (r *Result) Merge(o *Result) { 68 r.Min = math.Min(r.Min, o.Min) 69 r.Max = math.Max(r.Max, o.Max) 70 r.Total += o.Total 71 r.Count += o.Count 72 r.Last = o.Last 73 } 74 75 func (r *Result) Get() *Result { 76 if r.Count > 0 { 77 r.Avg = r.Total / float64(r.Count) 78 } 79 return r 80 } 81 82 // Result returns the aggregate result of the sliding window by aggregating all panes. 83 func (t *TimeWindowAggregator) Result() *Result { 84 t.mux.RLock() 85 defer t.mux.RUnlock() 86 res := NewResult() 87 for _, v := range t.window.values(time.Now().UnixMilli()) { 88 res.Merge(v.(*Result)) // Last not as expect, but agg result has no Last value 89 } 90 return res.Get() 91 } 92 93 // Add adds a value to the sliding window's current pane. 94 func (t *TimeWindowAggregator) Add(v float64) { 95 t.mux.Lock() 96 defer t.mux.Unlock() 97 98 t.window.currentPane(time.Now().UnixMilli(), t.newEmptyValue).value.(*Result).Update(v) 99 } 100 101 func (t *TimeWindowAggregator) newEmptyValue() interface{} { 102 return NewResult() 103 }