| // Licensed to Apache Software Foundation (ASF) under one or more contributor |
| // license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright |
| // ownership. Apache Software Foundation (ASF) licenses this file to you under |
| // the Apache License, Version 2.0 (the "License"); you may |
| // not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| package metrics |
| |
| func newMeterOpts() *Opts { |
| return &Opts{labels: make(map[string]string)} |
| } |
| |
| func (b *Opts) GetLabels() map[string]string { |
| return b.labels |
| } |
| |
| type counterImpl struct { |
| name string |
| val float64 |
| labels map[string]string |
| |
| getFunc func() float64 |
| addFunc func(float64) |
| } |
| |
| func newDefaultCounter(name string, opt ...Opt) *counterImpl { |
| result := &counterImpl{name: name, val: 0} |
| opts := newMeterOpts() |
| for _, o := range opt { |
| o(opts) |
| } |
| result.labels = opts.GetLabels() |
| |
| result.getFunc = func() float64 { |
| return result.val |
| } |
| result.addFunc = func(f float64) { |
| result.val += f |
| } |
| return result |
| } |
| |
| func (c *counterImpl) Name() string { |
| return c.name |
| } |
| |
| func (c *counterImpl) Get() float64 { |
| return c.getFunc() |
| } |
| |
| func (c *counterImpl) Labels() map[string]string { |
| return c.labels |
| } |
| |
| func (c *counterImpl) Inc(val float64) { |
| c.addFunc(val) |
| } |
| |
| func (c *counterImpl) ChangeFunctions(add func(v float64), get func() float64) { |
| c.addFunc = add |
| c.getFunc = get |
| } |
| |
| type gaugeImpl struct { |
| name string |
| labels map[string]string |
| getter func() float64 |
| } |
| |
| func newDefaultGauge(name string, getter func() float64, opt ...Opt) *gaugeImpl { |
| result := &gaugeImpl{name: name, getter: getter} |
| opts := newMeterOpts() |
| for _, o := range opt { |
| o(opts) |
| } |
| result.labels = opts.GetLabels() |
| return result |
| } |
| |
| func (g *gaugeImpl) Name() string { |
| return g.name |
| } |
| |
| func (g *gaugeImpl) Labels() map[string]string { |
| return g.labels |
| } |
| |
| func (g *gaugeImpl) Get() float64 { |
| return g.getter() |
| } |
| |
| func (g *gaugeImpl) Getter() func() float64 { |
| return g.getter |
| } |
| |
| type histogramImpl struct { |
| name string |
| labels map[string]string |
| |
| buckets []*histogramBucket |
| |
| observeFunc func(float64) |
| observeWithCountFunc func(float64, int64) |
| } |
| |
| type histogramBucket struct { |
| bucket float64 |
| val *int64 |
| } |
| |
| func newDefaultHistogram(name string, minVal float64, steps []float64, opt ...Opt) *histogramImpl { |
| result := &histogramImpl{name: name} |
| opts := newMeterOpts() |
| for _, o := range opt { |
| o(opts) |
| } |
| result.labels = opts.GetLabels() |
| |
| result.initBuckets(minVal, steps) |
| |
| result.observeFunc = func(f float64) { |
| b := result.findBucket(f) |
| if b != nil { |
| *b.val++ |
| } |
| } |
| result.observeWithCountFunc = func(f float64, c int64) { |
| b := result.findBucket(f) |
| if b != nil { |
| *b.val += c |
| } |
| } |
| return result |
| } |
| |
| func (h *histogramImpl) Observe(val float64) { |
| h.observeFunc(val) |
| } |
| |
| func (h *histogramImpl) ObserveWithCount(val float64, c int64) { |
| h.observeWithCountFunc(val, c) |
| } |
| |
| func (h *histogramImpl) findBucket(v float64) *histogramBucket { |
| var low, high = 0, len(h.buckets) - 1 |
| |
| for low <= high { |
| var mid = (low + high) / 2 |
| if h.buckets[mid].bucket < v { |
| low = mid + 1 |
| } else if h.buckets[mid].bucket > v { |
| high = mid - 1 |
| } else { |
| return h.buckets[mid] |
| } |
| } |
| |
| low-- |
| |
| if low < len(h.buckets) && low >= 0 { |
| return h.buckets[low] |
| } |
| return nil |
| } |
| |
| func (h *histogramImpl) initBuckets(minVal float64, steps []float64) { |
| n := len(steps) |
| for i := 1; i < n; i++ { |
| key := steps[i] |
| j := i - 1 |
| if steps[j] == key { |
| panic("duplicate steps found") |
| } |
| for j >= 0 && steps[j] > key { |
| steps[j+1] = steps[j] |
| j-- |
| } |
| steps[j+1] = key |
| } |
| if steps[0] != minVal { |
| steps = append([]float64{minVal}, steps...) |
| } |
| |
| buckets := make([]*histogramBucket, len(steps)) |
| for i, step := range steps { |
| buckets[i] = &histogramBucket{bucket: step, val: new(int64)} |
| } |
| h.buckets = buckets |
| } |
| |
| func (h *histogramImpl) Name() string { |
| return h.name |
| } |
| |
| func (h *histogramImpl) Labels() map[string]string { |
| return h.labels |
| } |
| |
| func (h *histogramImpl) Buckets() []interface{} { |
| result := make([]interface{}, len(h.buckets)) |
| for i, b := range h.buckets { |
| result[i] = b |
| } |
| return result |
| } |
| |
| func (h *histogramImpl) ChangeFunctions(observe func(v float64), observeWithCount func(v float64, c int64)) { |
| h.observeFunc = observe |
| h.observeWithCountFunc = observeWithCount |
| } |
| |
| func (h *histogramBucket) Bucket() float64 { |
| return h.bucket |
| } |
| |
| func (h *histogramBucket) Value() *int64 { |
| return h.val |
| } |