youtubebeat/vendor/github.com/elastic/beats/libbeat/monitoring/metrics.go

234 lines
6.2 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. 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 monitoring
import (
"encoding/json"
"expvar"
"math"
"strconv"
"sync"
"github.com/elastic/beats/libbeat/common/atomic"
)
// makeExpvar wraps a callback for registering a metrics with expvar.Publish.
type makeExpvar func() string
// Int is a 64 bit integer variable satisfying the Var interface.
type Int struct{ i atomic.Int64 }
// NewInt creates and registers a new integer variable.
//
// Note: If the registry is configured to publish variables to expvar, the
// variable will be available via expvars package as well, but can not be removed
// anymore.
func NewInt(r *Registry, name string, opts ...Option) *Int {
if r == nil {
r = Default
}
v := &Int{}
addVar(r, name, opts, v, makeExpvar(func() string {
return strconv.FormatInt(v.Get(), 10)
}))
return v
}
func (v *Int) Get() int64 { return v.i.Load() }
func (v *Int) Set(value int64) { v.i.Store(value) }
func (v *Int) Add(delta int64) { v.i.Add(delta) }
func (v *Int) Sub(delta int64) { v.i.Sub(delta) }
func (v *Int) Inc() { v.i.Inc() }
func (v *Int) Dec() { v.i.Dec() }
func (v *Int) Visit(_ Mode, vs Visitor) { vs.OnInt(v.Get()) }
// Uint is a 64bit unsigned integer variable satisfying the Var interface.
type Uint struct{ u atomic.Uint64 }
// NewUint creates and registers a new unsigned integer variable.
//
// Note: If the registry is configured to publish variables to expvar, the
// variable will be available via expvars package as well, but can not be removed
// anymore.
func NewUint(r *Registry, name string, opts ...Option) *Uint {
if r == nil {
r = Default
}
v := &Uint{}
addVar(r, name, opts, v, makeExpvar(func() string {
return strconv.FormatUint(v.Get(), 10)
}))
return v
}
func (v *Uint) Get() uint64 { return v.u.Load() }
func (v *Uint) Set(value uint64) { v.u.Store(value) }
func (v *Uint) Add(delta uint64) { v.u.Add(delta) }
func (v *Uint) Sub(delta uint64) { v.u.Sub(delta) }
func (v *Uint) Inc() { v.u.Inc() }
func (v *Uint) Dec() { v.u.Dec() }
func (v *Uint) Visit(_ Mode, vs Visitor) {
value := v.Get() & (^uint64(1 << 63))
vs.OnInt(int64(value))
}
// Float is a 64 bit float variable satisfying the Var interface.
type Float struct{ f atomic.Uint64 }
// NewFloat creates and registers a new float variable.
//
// Note: If the registry is configured to publish variables to expvar, the
// variable will be available via expvars package as well, but can not be removed
// anymore.
func NewFloat(r *Registry, name string, opts ...Option) *Float {
if r == nil {
r = Default
}
v := &Float{}
addVar(r, name, opts, v, makeExpvar(func() string {
return strconv.FormatFloat(v.Get(), 'g', -1, 64)
}))
return v
}
func (v *Float) Get() float64 { return math.Float64frombits(v.f.Load()) }
func (v *Float) Set(value float64) { v.f.Store(math.Float64bits(value)) }
func (v *Float) Sub(delta float64) { v.Add(-delta) }
func (v *Float) Visit(_ Mode, vs Visitor) { vs.OnFloat(v.Get()) }
func (v *Float) Add(delta float64) {
for {
cur := v.f.Load()
next := math.Float64bits(math.Float64frombits(cur) + delta)
if v.f.CAS(cur, next) {
return
}
}
}
// Bool is a Bool variable satisfying the Var interface.
type Bool struct{ f atomic.Bool }
// NewBool creates and registers a new bool variable.
//
// Note: If the registry is configured to publish variables to expvar, the
// variable will be available via expvars package as well, but can not be removed
// anymore.
func NewBool(r *Registry, name string, opts ...Option) *Bool {
if r == nil {
r = Default
}
v := &Bool{}
addVar(r, name, opts, v, makeExpvar(func() string {
return strconv.FormatBool(v.Get())
}))
return v
}
func (v *Bool) Get() bool { return v.f.Load() }
func (v *Bool) Set(value bool) { v.f.Store(value) }
func (v *Bool) Visit(_ Mode, vs Visitor) { vs.OnBool(v.Get()) }
// String is a string variable satisfying the Var interface.
type String struct {
mu sync.RWMutex
s string
}
// NewString creates and registers a new string variable.
//
// Note: If the registry is configured to publish variables to expvar, the
// variable will be available via expvars package as well, but can not be removed
// anymore.
func NewString(r *Registry, name string, opts ...Option) *String {
if r == nil {
r = Default
}
v := &String{}
addVar(r, name, opts, v, makeExpvar(func() string {
b, _ := json.Marshal(v.Get())
return string(b)
}))
return v
}
func (v *String) Visit(_ Mode, vs Visitor) {
vs.OnString(v.Get())
}
func (v *String) Get() string {
v.mu.RLock()
defer v.mu.RUnlock()
return v.s
}
func (v *String) Set(s string) {
v.mu.Lock()
defer v.mu.Unlock()
v.s = s
}
func (v *String) Clear() {
v.Set("")
}
func (v *String) Fail(err error) {
v.Set(err.Error())
}
type FuncVar func(Mode, Visitor)
func (f FuncVar) Visit(m Mode, vs Visitor) { f(m, vs) }
type Func struct {
f FuncVar
}
func NewFunc(r *Registry, name string, f func(Mode, Visitor), opts ...Option) *Func {
if r == nil {
r = Default
}
v := &Func{f}
addVar(r, name, opts, v, nil)
return v
}
func (f *Func) Visit(m Mode, vs Visitor) { f.f(m, vs) }
func (m makeExpvar) String() string { return m() }
func addVar(r *Registry, name string, opts []Option, v Var, ev expvar.Var) {
O := varOpts(r.opts, opts)
r.doAdd(name, v, O)
if O.publishExpvar && ev != nil {
expvar.Publish(fullName(r, name), ev)
}
}
func fullName(r *Registry, name string) string {
if r.name == "" {
return name
}
return r.name + "." + name
}