235 lines
6.2 KiB
Go
235 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
|
||
|
}
|