github.com/wfusion/gofusion@v1.1.14/common/infra/metrics/metrics.go (about) 1 package metrics 2 3 import ( 4 "math" 5 "strings" 6 "time" 7 8 "github.com/wfusion/gofusion/common/utils" 9 10 iradix "github.com/hashicorp/go-immutable-radix" 11 ) 12 13 type Label struct { 14 Name string 15 Value string 16 } 17 18 func (m *Metrics) SetGauge(key []string, val float32, opts ...utils.OptionExtender) { 19 m.SetGaugeWithLabels(key, val, nil, opts...) 20 } 21 22 func (m *Metrics) SetGaugeWithLabels(key []string, val float32, labels []Label, opts ...utils.OptionExtender) { 23 key, labels, ok := m.formatKeyAndLabels("gauge", key, labels) 24 if !ok { 25 return 26 } 27 m.sink.SetGaugeWithLabels(key, val, labels, opts...) 28 } 29 30 func (m *Metrics) SetPrecisionGauge(key []string, val float64, opts ...utils.OptionExtender) { 31 m.SetPrecisionGaugeWithLabels(key, val, nil, opts...) 32 } 33 34 func (m *Metrics) SetPrecisionGaugeWithLabels(key []string, val float64, labels []Label, opts ...utils.OptionExtender) { 35 key, labels, ok := m.formatKeyAndLabels("gauge", key, labels) 36 if !ok { 37 return 38 } 39 sink, ok := m.sink.(PrecisionGaugeMetricSink) 40 if !ok { 41 m.sink.SetGaugeWithLabels(key, float32(val), labels, opts...) 42 } else { 43 sink.SetPrecisionGaugeWithLabels(key, val, labels, opts...) 44 } 45 } 46 47 func (m *Metrics) EmitKey(key []string, val float32, opts ...utils.OptionExtender) { 48 if m.EnableTypePrefix { 49 key = insert(0, "kv", key) 50 } 51 if m.ServiceName != "" { 52 key = insert(0, m.ServiceName, key) 53 } 54 _, allowed := m.allowMetric(key, nil) 55 if !allowed { 56 return 57 } 58 m.sink.EmitKey(key, val, opts...) 59 } 60 61 func (m *Metrics) IncrCounter(key []string, val float32, opts ...utils.OptionExtender) { 62 m.IncrCounterWithLabels(key, val, nil, opts...) 63 } 64 65 func (m *Metrics) IncrCounterWithLabels(key []string, val float32, labels []Label, opts ...utils.OptionExtender) { 66 key, labels, ok := m.formatKeyAndLabels("counter", key, labels) 67 if !ok { 68 return 69 } 70 m.sink.IncrCounterWithLabels(key, val, labels, opts...) 71 } 72 73 func (m *Metrics) AddSample(key []string, val float32, opts ...utils.OptionExtender) { 74 m.AddSampleWithLabels(key, val, nil, opts...) 75 } 76 77 func (m *Metrics) AddSampleWithLabels(key []string, val float32, labels []Label, opts ...utils.OptionExtender) { 78 key, labels, ok := m.formatKeyAndLabels("sample", key, labels) 79 if !ok { 80 return 81 } 82 m.sink.AddSampleWithLabels(key, val, labels, opts...) 83 } 84 85 func (m *Metrics) AddPrecisionSample(key []string, val float64, opts ...utils.OptionExtender) { 86 m.AddPrecisionSampleWithLabels(key, val, nil, opts...) 87 } 88 89 func (m *Metrics) AddPrecisionSampleWithLabels(key []string, val float64, 90 labels []Label, opts ...utils.OptionExtender) { 91 key, labels, ok := m.formatKeyAndLabels("sample", key, labels) 92 if !ok { 93 return 94 } 95 if sink, ok := m.sink.(PrecisionSampleMetricSink); ok { 96 sink.AddPrecisionSampleWithLabels(key, val, labels, opts...) 97 } else { 98 m.sink.AddSampleWithLabels(key, float32(val), labels, opts...) 99 } 100 } 101 102 func (m *Metrics) MeasureSince(key []string, start time.Time, opts ...utils.OptionExtender) { 103 m.MeasureSinceWithLabels(key, start, nil, opts...) 104 } 105 106 func (m *Metrics) MeasureSinceWithLabels(key []string, start time.Time, labels []Label, opts ...utils.OptionExtender) { 107 key, labels, ok := m.formatKeyAndLabels("timer", key, labels) 108 if !ok { 109 return 110 } 111 opt := utils.ApplyOptions[Option](opts...) 112 sink, ok := m.sink.(PrecisionSampleMetricSink) 113 if m.TimerGranularity == 0 { 114 if opt.Precision && ok { 115 sink.AddPrecisionSampleWithLabels(key, math.MaxFloat64, labels, opts...) 116 } else { 117 m.sink.AddSampleWithLabels(key, math.MaxFloat32, labels, opts...) 118 } 119 } else { 120 now := time.Now() 121 elapsed := now.Sub(start) 122 if opt.Precision && ok { 123 msec := float64(elapsed.Nanoseconds()) / float64(m.TimerGranularity) 124 sink.AddPrecisionSampleWithLabels(key, msec, labels, opts...) 125 } else { 126 msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity) 127 m.sink.AddSampleWithLabels(key, msec, labels, opts...) 128 } 129 } 130 } 131 132 // UpdateFilter overwrites the existing filter with the given rules. 133 func (m *Metrics) UpdateFilter(allow, block []string) { 134 m.UpdateFilterAndLabels(allow, block, m.AllowedLabels, m.BlockedLabels) 135 } 136 137 // UpdateFilterAndLabels overwrites the existing filter with the given rules. 138 func (m *Metrics) UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) { 139 m.filterLock.Lock() 140 defer m.filterLock.Unlock() 141 142 m.AllowedPrefixes = allow 143 m.BlockedPrefixes = block 144 145 if allowedLabels == nil { 146 // Having a white list means we take only elements from it 147 m.allowedLabels = nil 148 } else { 149 m.allowedLabels = make(map[string]bool) 150 for _, v := range allowedLabels { 151 m.allowedLabels[v] = true 152 } 153 } 154 m.blockedLabels = make(map[string]bool) 155 for _, v := range blockedLabels { 156 m.blockedLabels[v] = true 157 } 158 m.AllowedLabels = allowedLabels 159 m.BlockedLabels = blockedLabels 160 161 m.filter = iradix.New() 162 for _, prefix := range m.AllowedPrefixes { 163 m.filter, _, _ = m.filter.Insert([]byte(prefix), true) 164 } 165 for _, prefix := range m.BlockedPrefixes { 166 m.filter, _, _ = m.filter.Insert([]byte(prefix), false) 167 } 168 } 169 170 func (m *Metrics) Shutdown() { 171 if ss, ok := m.sink.(ShutdownSink); ok { 172 ss.Shutdown() 173 } 174 } 175 176 func (m *Metrics) formatKeyAndLabels(typePrefix string, keySrc []string, labelsSrc []Label) ( 177 keyDst []string, labelsDst []Label, ok bool) { 178 keyDst = keySrc 179 if m.HostName != "" { 180 if m.EnableHostnameLabel { 181 labelsSrc = append(labelsSrc, Label{"fus_hostname", m.HostName}) 182 } else if m.EnableHostname { 183 keyDst = insert(0, m.HostName, keyDst) 184 } 185 } 186 if m.EnableTypePrefix { 187 keyDst = insert(0, typePrefix, keyDst) 188 } 189 if m.ServiceName != "" { 190 if m.EnableServiceLabel { 191 labelsSrc = append(labelsSrc, Label{"fus_service", m.ServiceName}) 192 } else { 193 keyDst = insert(0, m.ServiceName, keyDst) 194 } 195 } 196 if m.EnableClientIPLabel { 197 labelsSrc = append(labelsSrc, Label{"fus_service_ip", utils.ClientIP()}) 198 } 199 200 labelsDst, ok = m.allowMetric(keyDst, labelsSrc) 201 return 202 } 203 204 // labelIsAllowed return true if a should be included in metric 205 // the caller should lock m.filterLock while calling this method 206 func (m *Metrics) labelIsAllowed(label *Label) bool { 207 labelName := (*label).Name 208 if m.blockedLabels != nil { 209 _, ok := m.blockedLabels[labelName] 210 if ok { 211 // If present, let's remove this label 212 return false 213 } 214 } 215 if m.allowedLabels != nil { 216 _, ok := m.allowedLabels[labelName] 217 return ok 218 } 219 // Allow by default 220 return true 221 } 222 223 // filterLabels return only allowed labels 224 // the caller should lock m.filterLock while calling this method 225 func (m *Metrics) filterLabels(labels []Label) []Label { 226 if labels == nil { 227 return nil 228 } 229 toReturn := make([]Label, 0, len(labels)) 230 for _, label := range labels { 231 if m.labelIsAllowed(&label) { 232 toReturn = append(toReturn, label) 233 } 234 } 235 return toReturn 236 } 237 238 // Returns whether the metric should be allowed based on configured prefix filters 239 // Also return the applicable labels 240 func (m *Metrics) allowMetric(key []string, labels []Label) ([]Label, bool) { 241 m.filterLock.RLock() 242 defer m.filterLock.RUnlock() 243 244 if m.filter == nil || m.filter.Len() == 0 { 245 return m.filterLabels(labels), m.Config.FilterDefault 246 } 247 248 _, allowed, ok := m.filter.Root().LongestPrefix([]byte(strings.Join(key, "."))) 249 if !ok { 250 return m.filterLabels(labels), m.Config.FilterDefault 251 } 252 253 return m.filterLabels(labels), allowed.(bool) 254 } 255 256 // Creates a new slice with the provided string value as the first element 257 // and the provided slice values as the remaining values. 258 // Ordering of the values in the provided input slice is kept in tact in the output slice. 259 func insert(i int, v string, s []string) []string { 260 // Allocate new slice to avoid modifying the input slice 261 newS := make([]string, len(s)+1) 262 263 // Copy s[0, i-1] into newS 264 for j := 0; j < i; j++ { 265 newS[j] = s[j] 266 } 267 268 // Insert provided element at index i 269 newS[i] = v 270 271 // Copy s[i, len(s)-1] into newS starting at newS[i+1] 272 for j := i; j < len(s); j++ { 273 newS[j+1] = s[j] 274 } 275 276 return newS 277 }