metrics: fix gauge

This commit is contained in:
Martin Holst Swende 2024-11-26 20:50:01 +01:00
parent c1c47eea90
commit afaca63832
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
16 changed files with 78 additions and 107 deletions

View file

@ -116,7 +116,7 @@ type freezerTable struct {
headBytes int64 // Number of bytes written to the head file headBytes int64 // Number of bytes written to the head file
readMeter metrics.Meter // Meter for measuring the effective amount of data read readMeter metrics.Meter // Meter for measuring the effective amount of data read
writeMeter metrics.Meter // Meter for measuring the effective amount of data written writeMeter metrics.Meter // Meter for measuring the effective amount of data written
sizeGauge metrics.Gauge // Gauge for tracking the combined size of all freezer tables sizeGauge *metrics.Gauge // Gauge for tracking the combined size of all freezer tables
logger log.Logger // Logger with database path and table name embedded logger log.Logger // Logger with database path and table name embedded
lock sync.RWMutex // Mutex protecting the data file descriptors lock sync.RWMutex // Mutex protecting the data file descriptors
@ -124,13 +124,13 @@ type freezerTable struct {
// newFreezerTable opens the given path as a freezer table. // newFreezerTable opens the given path as a freezer table.
func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) { func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) {
return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly) return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NewGauge(), freezerTableSize, disableSnappy, readonly)
} }
// newTable opens a freezer table, creating the data and index files if they are // newTable opens a freezer table, creating the data and index files if they are
// non-existent. Both files are truncated to the shortest common length to ensure // non-existent. Both files are truncated to the shortest common length to ensure
// they don't go out of sync. // they don't go out of sync.
func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeGauge metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) { func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeGauge *metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) {
// Ensure the containing directory exists and open the indexEntry file // Ensure the containing directory exists and open the indexEntry file
if err := os.MkdirAll(path, 0755); err != nil { if err := os.MkdirAll(path, 0755); err != nil {
return nil, err return nil, err

View file

@ -67,16 +67,16 @@ type Database struct {
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction
writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction
diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database diskSizeGauge *metrics.Gauge // Gauge for tracking the size of all the levels in the database
diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read
diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written
memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction memCompGauge *metrics.Gauge // Gauge for tracking the number of memory compaction
level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 level0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in level0
nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level nonlevel0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in non0 level
seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt seekCompGauge *metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
manualMemAllocGauge metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC) manualMemAllocGauge *metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC)
levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels levelsGauge []*metrics.Gauge // Gauge for tracking the number of tables in levels
quitLock sync.Mutex // Mutex protecting the quit channel access quitLock sync.Mutex // Mutex protecting the quit channel access
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database quitChan chan chan error // Quit channel to stop the metrics collection before closing the database

View file

@ -63,16 +63,16 @@ type Database struct {
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction
writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction
diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database diskSizeGauge *metrics.Gauge // Gauge for tracking the size of all the levels in the database
diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read
diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written
memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction memCompGauge *metrics.Gauge // Gauge for tracking the number of memory compaction
level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 level0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in level0
nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level nonlevel0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in non0 level
seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt seekCompGauge *metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated manualMemAllocGauge *metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels levelsGauge []*metrics.Gauge // Gauge for tracking the number of tables in levels
quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database quitChan chan chan error // Quit channel to stop the metrics collection before closing the database

View file

@ -8,11 +8,11 @@ import (
var ( var (
debugMetrics struct { debugMetrics struct {
GCStats struct { GCStats struct {
LastGC Gauge LastGC *Gauge
NumGC Gauge NumGC *Gauge
Pause Histogram Pause Histogram
//PauseQuantiles Histogram //PauseQuantiles Histogram
PauseTotal Gauge PauseTotal *Gauge
} }
ReadGCStats Timer ReadGCStats Timer
} }

View file

@ -192,7 +192,7 @@ func (exp *exp) syncToExpvar() {
exp.publishCounter(name, i.Snapshot()) exp.publishCounter(name, i.Snapshot())
case *metrics.CounterFloat64: case *metrics.CounterFloat64:
exp.publishCounterFloat64(name, i.Snapshot()) exp.publishCounterFloat64(name, i.Snapshot())
case metrics.Gauge: case *metrics.Gauge:
exp.publishGauge(name, i.Snapshot()) exp.publishGauge(name, i.Snapshot())
case metrics.GaugeFloat64: case metrics.GaugeFloat64:
exp.publishGaugeFloat64(name, i.Snapshot()) exp.publishGaugeFloat64(name, i.Snapshot())

View file

@ -2,97 +2,69 @@ package metrics
import "sync/atomic" import "sync/atomic"
// GaugeSnapshot contains a readonly int64. // GaugeSnapshot is a read-only copy of a Gauge.
type GaugeSnapshot interface { type GaugeSnapshot int64
Value() int64
}
// Gauge holds an int64 value that can be set arbitrarily. // Value returns the value at the time the snapshot was taken.
type Gauge interface { func (g GaugeSnapshot) Value() int64 { return int64(g) }
Snapshot() GaugeSnapshot
Update(int64)
UpdateIfGt(int64)
Dec(int64)
Inc(int64)
}
// GetOrRegisterGauge returns an existing Gauge or constructs and registers a // GetOrRegisterGauge returns an existing Gauge or constructs and registers a
// new StandardGauge. // new Gauge.
func GetOrRegisterGauge(name string, r Registry) Gauge { func GetOrRegisterGauge(name string, r Registry) *Gauge {
if nil == r { if r == nil {
r = DefaultRegistry r = DefaultRegistry
} }
return r.GetOrRegister(name, NewGauge).(Gauge) return r.GetOrRegister(name, NewGauge).(*Gauge)
} }
// NewGauge constructs a new StandardGauge. // NewGauge constructs a new Gauge.
func NewGauge() Gauge { func NewGauge() *Gauge {
if !Enabled { return &Gauge{}
return NilGauge{}
}
return &StandardGauge{}
} }
// NewRegisteredGauge constructs and registers a new StandardGauge. // NewRegisteredGauge constructs and registers a new Gauge.
func NewRegisteredGauge(name string, r Registry) Gauge { func NewRegisteredGauge(name string, r Registry) *Gauge {
c := NewGauge() c := NewGauge()
if nil == r { if r == nil {
r = DefaultRegistry r = DefaultRegistry
} }
r.Register(name, c) r.Register(name, c)
return c return c
} }
// gaugeSnapshot is a read-only copy of another Gauge. // Gauge and uses the sync/atomic package to manage a single int64 value.
type gaugeSnapshot int64 type Gauge atomic.Int64
// Value returns the value at the time the snapshot was taken.
func (g gaugeSnapshot) Value() int64 { return int64(g) }
// NilGauge is a no-op Gauge.
type NilGauge struct{}
func (NilGauge) Snapshot() GaugeSnapshot { return (*emptySnapshot)(nil) }
func (NilGauge) Update(v int64) {}
func (NilGauge) UpdateIfGt(v int64) {}
func (NilGauge) Dec(i int64) {}
func (NilGauge) Inc(i int64) {}
// StandardGauge is the standard implementation of a Gauge and uses the
// sync/atomic package to manage a single int64 value.
type StandardGauge struct {
value atomic.Int64
}
// Snapshot returns a read-only copy of the gauge. // Snapshot returns a read-only copy of the gauge.
func (g *StandardGauge) Snapshot() GaugeSnapshot { func (g *Gauge) Snapshot() GaugeSnapshot {
return gaugeSnapshot(g.value.Load()) return GaugeSnapshot((*atomic.Int64)(g).Load())
} }
// Update updates the gauge's value. // Update updates the gauge's value.
func (g *StandardGauge) Update(v int64) { func (g *Gauge) Update(v int64) {
g.value.Store(v) (*atomic.Int64)(g).Store(v)
} }
// UpdateIfGt updates the gauge's value if v is larger then the current value. // UpdateIfGt updates the gauge's value if v is larger then the current value.
func (g *StandardGauge) UpdateIfGt(v int64) { func (g *Gauge) UpdateIfGt(v int64) {
value := (*atomic.Int64)(g)
for { for {
exist := g.value.Load() exist := value.Load()
if exist >= v { if exist >= v {
break break
} }
if g.value.CompareAndSwap(exist, v) { if value.CompareAndSwap(exist, v) {
break break
} }
} }
} }
// Dec decrements the gauge's current value by the given amount. // Dec decrements the gauge's current value by the given amount.
func (g *StandardGauge) Dec(i int64) { func (g *Gauge) Dec(i int64) {
g.value.Add(-i) (*atomic.Int64)(g).Add(-i)
} }
// Inc increments the gauge's current value by the given amount. // Inc increments the gauge's current value by the given amount.
func (g *StandardGauge) Inc(i int64) { func (g *Gauge) Inc(i int64) {
g.value.Add(i) (*atomic.Int64)(g).Add(i)
} }

View file

@ -69,7 +69,7 @@ func graphite(c *GraphiteConfig) error {
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Snapshot().Count(), now) fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Snapshot().Count(), now)
case *CounterFloat64: case *CounterFloat64:
fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Snapshot().Count(), now) fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Snapshot().Count(), now)
case Gauge: case *Gauge:
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Snapshot().Value(), now) fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Snapshot().Value(), now)
case GaugeFloat64: case GaugeFloat64:
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Snapshot().Value(), now) fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Snapshot().Value(), now)

View file

@ -20,7 +20,6 @@ package metrics
var ( var (
_ SampleSnapshot = (*emptySnapshot)(nil) _ SampleSnapshot = (*emptySnapshot)(nil)
_ HistogramSnapshot = (*emptySnapshot)(nil) _ HistogramSnapshot = (*emptySnapshot)(nil)
_ GaugeSnapshot = (*emptySnapshot)(nil)
_ MeterSnapshot = (*emptySnapshot)(nil) _ MeterSnapshot = (*emptySnapshot)(nil)
_ TimerSnapshot = (*emptySnapshot)(nil) _ TimerSnapshot = (*emptySnapshot)(nil)
) )

View file

@ -20,7 +20,7 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
"value": metric.Snapshot().Count(), "value": metric.Snapshot().Count(),
} }
return measurement, fields return measurement, fields
case metrics.Gauge: case *metrics.Gauge:
measurement := fmt.Sprintf("%s%s.gauge", namespace, name) measurement := fmt.Sprintf("%s%s.gauge", namespace, name)
fields := map[string]interface{}{ fields := map[string]interface{}{
"value": metric.Snapshot().Value(), "value": metric.Snapshot().Value(),

View file

@ -27,7 +27,7 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) {
case *CounterFloat64: case *CounterFloat64:
l.Printf("counter %s\n", name) l.Printf("counter %s\n", name)
l.Printf(" count: %f\n", metric.Snapshot().Count()) l.Printf(" count: %f\n", metric.Snapshot().Count())
case Gauge: case *Gauge:
l.Printf("gauge %s\n", name) l.Printf("gauge %s\n", name)
l.Printf(" value: %9d\n", metric.Snapshot().Value()) l.Printf(" value: %9d\n", metric.Snapshot().Value())
case GaugeFloat64: case GaugeFloat64:

View file

@ -68,7 +68,7 @@ func (c *OpenTSDBConfig) writeRegistry(w io.Writer, now int64, shortHostname str
fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname) fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname)
case *CounterFloat64: case *CounterFloat64:
fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname) fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname)
case Gauge: case *Gauge:
fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname) fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname)
case GaugeFloat64: case GaugeFloat64:
fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname) fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname)

View file

@ -55,7 +55,7 @@ func (c *collector) Add(name string, i any) error {
c.addCounter(name, m.Snapshot()) c.addCounter(name, m.Snapshot())
case *metrics.CounterFloat64: case *metrics.CounterFloat64:
c.addCounterFloat64(name, m.Snapshot()) c.addCounterFloat64(name, m.Snapshot())
case metrics.Gauge: case *metrics.Gauge:
c.addGauge(name, m.Snapshot()) c.addGauge(name, m.Snapshot())
case metrics.GaugeFloat64: case metrics.GaugeFloat64:
c.addGaugeFloat64(name, m.Snapshot()) c.addGaugeFloat64(name, m.Snapshot())

View file

@ -153,7 +153,7 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
values["count"] = metric.Snapshot().Count() values["count"] = metric.Snapshot().Count()
case *CounterFloat64: case *CounterFloat64:
values["count"] = metric.Snapshot().Count() values["count"] = metric.Snapshot().Count()
case Gauge: case *Gauge:
values["value"] = metric.Snapshot().Value() values["value"] = metric.Snapshot().Value()
case GaugeFloat64: case GaugeFloat64:
values["value"] = metric.Snapshot().Value() values["value"] = metric.Snapshot().Value()
@ -214,7 +214,7 @@ func (r *StandardRegistry) Unregister(name string) {
func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) { func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) {
switch i.(type) { switch i.(type) {
case *Counter, *CounterFloat64, Gauge, GaugeFloat64, GaugeInfo, Healthcheck, Histogram, Meter, Timer, ResettingTimer: case *Counter, *CounterFloat64, *Gauge, GaugeFloat64, GaugeInfo, Healthcheck, Histogram, Meter, Timer, ResettingTimer:
default: default:
return nil, false, false return nil, false, false
} }

View file

@ -19,7 +19,7 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) {
w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Snapshot().Count())) w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Snapshot().Count()))
case *CounterFloat64: case *CounterFloat64:
w.Info(fmt.Sprintf("counter %s: count: %f", name, metric.Snapshot().Count())) w.Info(fmt.Sprintf("counter %s: count: %f", name, metric.Snapshot().Count()))
case Gauge: case *Gauge:
w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Snapshot().Value())) w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Snapshot().Value()))
case GaugeFloat64: case GaugeFloat64:
w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Snapshot().Value())) w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Snapshot().Value()))

View file

@ -32,7 +32,7 @@ func WriteOnce(r Registry, w io.Writer) {
case *CounterFloat64: case *CounterFloat64:
fmt.Fprintf(w, "counter %s\n", namedMetric.name) fmt.Fprintf(w, "counter %s\n", namedMetric.name)
fmt.Fprintf(w, " count: %f\n", metric.Snapshot().Count()) fmt.Fprintf(w, " count: %f\n", metric.Snapshot().Count())
case Gauge: case *Gauge:
fmt.Fprintf(w, "gauge %s\n", namedMetric.name) fmt.Fprintf(w, "gauge %s\n", namedMetric.name)
fmt.Fprintf(w, " value: %9d\n", metric.Snapshot().Value()) fmt.Fprintf(w, " value: %9d\n", metric.Snapshot().Value())
case GaugeFloat64: case GaugeFloat64:

View file

@ -37,9 +37,9 @@ const (
) )
var ( var (
activePeerGauge metrics.Gauge = metrics.NilGauge{} activePeerGauge = metrics.NewGauge()
activeInboundPeerGauge metrics.Gauge = metrics.NilGauge{} activeInboundPeerGauge = metrics.NewGauge()
activeOutboundPeerGauge metrics.Gauge = metrics.NilGauge{} activeOutboundPeerGauge = metrics.NewGauge()
ingressTrafficMeter = metrics.NewRegisteredMeter("p2p/ingress", nil) ingressTrafficMeter = metrics.NewRegisteredMeter("p2p/ingress", nil)
egressTrafficMeter = metrics.NewRegisteredMeter("p2p/egress", nil) egressTrafficMeter = metrics.NewRegisteredMeter("p2p/egress", nil)