forked from bnb-chain/bsc
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
metrics, cmd/geth: informational metrics (prometheus, influxdb, opent…
…sb) (#24877) This chang creates a GaugeInfo metrics type for registering informational (textual) metrics, e.g. geth version number. It also improves the testing for backend-exporters, and uses a shared subpackage in 'internal' to provide sample datasets and ordered registry. Implements #21783 --------- Co-authored-by: Martin Holst Swende <martin@swende.se>
- Loading branch information
1 parent
5b15949
commit 53f3c2a
Showing
26 changed files
with
750 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package metrics | ||
|
||
import ( | ||
"encoding/json" | ||
"sync" | ||
) | ||
|
||
// GaugeInfos hold a GaugeInfoValue value that can be set arbitrarily. | ||
type GaugeInfo interface { | ||
Snapshot() GaugeInfo | ||
Update(GaugeInfoValue) | ||
Value() GaugeInfoValue | ||
} | ||
|
||
// GaugeInfoValue is a mappng of (string) keys to (string) values | ||
type GaugeInfoValue map[string]string | ||
|
||
func (val GaugeInfoValue) String() string { | ||
data, _ := json.Marshal(val) | ||
return string(data) | ||
} | ||
|
||
// GetOrRegisterGaugeInfo returns an existing GaugeInfo or constructs and registers a | ||
// new StandardGaugeInfo. | ||
func GetOrRegisterGaugeInfo(name string, r Registry) GaugeInfo { | ||
if nil == r { | ||
r = DefaultRegistry | ||
} | ||
return r.GetOrRegister(name, NewGaugeInfo()).(GaugeInfo) | ||
} | ||
|
||
// NewGaugeInfo constructs a new StandardGaugeInfo. | ||
func NewGaugeInfo() GaugeInfo { | ||
if !Enabled { | ||
return NilGaugeInfo{} | ||
} | ||
return &StandardGaugeInfo{ | ||
value: GaugeInfoValue{}, | ||
} | ||
} | ||
|
||
// NewRegisteredGaugeInfo constructs and registers a new StandardGaugeInfo. | ||
func NewRegisteredGaugeInfo(name string, r Registry) GaugeInfo { | ||
c := NewGaugeInfo() | ||
if nil == r { | ||
r = DefaultRegistry | ||
} | ||
r.Register(name, c) | ||
return c | ||
} | ||
|
||
// NewFunctionalGauge constructs a new FunctionalGauge. | ||
func NewFunctionalGaugeInfo(f func() GaugeInfoValue) GaugeInfo { | ||
if !Enabled { | ||
return NilGaugeInfo{} | ||
} | ||
return &FunctionalGaugeInfo{value: f} | ||
} | ||
|
||
// NewRegisteredFunctionalGauge constructs and registers a new StandardGauge. | ||
func NewRegisteredFunctionalGaugeInfo(name string, r Registry, f func() GaugeInfoValue) GaugeInfo { | ||
c := NewFunctionalGaugeInfo(f) | ||
if nil == r { | ||
r = DefaultRegistry | ||
} | ||
r.Register(name, c) | ||
return c | ||
} | ||
|
||
// GaugeInfoSnapshot is a read-only copy of another GaugeInfo. | ||
type GaugeInfoSnapshot GaugeInfoValue | ||
|
||
// Snapshot returns the snapshot. | ||
func (g GaugeInfoSnapshot) Snapshot() GaugeInfo { return g } | ||
|
||
// Update panics. | ||
func (GaugeInfoSnapshot) Update(GaugeInfoValue) { | ||
panic("Update called on a GaugeInfoSnapshot") | ||
} | ||
|
||
// Value returns the value at the time the snapshot was taken. | ||
func (g GaugeInfoSnapshot) Value() GaugeInfoValue { return GaugeInfoValue(g) } | ||
|
||
// NilGauge is a no-op Gauge. | ||
type NilGaugeInfo struct{} | ||
|
||
// Snapshot is a no-op. | ||
func (NilGaugeInfo) Snapshot() GaugeInfo { return NilGaugeInfo{} } | ||
|
||
// Update is a no-op. | ||
func (NilGaugeInfo) Update(v GaugeInfoValue) {} | ||
|
||
// Value is a no-op. | ||
func (NilGaugeInfo) Value() GaugeInfoValue { return GaugeInfoValue{} } | ||
|
||
// StandardGaugeInfo is the standard implementation of a GaugeInfo and uses | ||
// sync.Mutex to manage a single string value. | ||
type StandardGaugeInfo struct { | ||
mutex sync.Mutex | ||
value GaugeInfoValue | ||
} | ||
|
||
// Snapshot returns a read-only copy of the gauge. | ||
func (g *StandardGaugeInfo) Snapshot() GaugeInfo { | ||
return GaugeInfoSnapshot(g.Value()) | ||
} | ||
|
||
// Update updates the gauge's value. | ||
func (g *StandardGaugeInfo) Update(v GaugeInfoValue) { | ||
g.mutex.Lock() | ||
defer g.mutex.Unlock() | ||
g.value = v | ||
} | ||
|
||
// Value returns the gauge's current value. | ||
func (g *StandardGaugeInfo) Value() GaugeInfoValue { | ||
g.mutex.Lock() | ||
defer g.mutex.Unlock() | ||
return g.value | ||
} | ||
|
||
// FunctionalGaugeInfo returns value from given function | ||
type FunctionalGaugeInfo struct { | ||
value func() GaugeInfoValue | ||
} | ||
|
||
// Value returns the gauge's current value. | ||
func (g FunctionalGaugeInfo) Value() GaugeInfoValue { | ||
return g.value() | ||
} | ||
|
||
// Value returns the gauge's current value in JSON string format | ||
func (g FunctionalGaugeInfo) ValueJsonString() string { | ||
data, _ := json.Marshal(g.value()) | ||
return string(data) | ||
} | ||
|
||
// Snapshot returns the snapshot. | ||
func (g FunctionalGaugeInfo) Snapshot() GaugeInfo { return GaugeInfoSnapshot(g.Value()) } | ||
|
||
// Update panics. | ||
func (FunctionalGaugeInfo) Update(GaugeInfoValue) { | ||
panic("Update called on a FunctionalGaugeInfo") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package metrics | ||
|
||
import ( | ||
"strconv" | ||
"testing" | ||
) | ||
|
||
func TestGaugeInfoJsonString(t *testing.T) { | ||
g := NewGaugeInfo() | ||
g.Update(GaugeInfoValue{ | ||
"chain_id": "5", | ||
"anotherKey": "any_string_value", | ||
"third_key": "anything", | ||
}, | ||
) | ||
want := `{"anotherKey":"any_string_value","chain_id":"5","third_key":"anything"}` | ||
if have := g.Value().String(); have != want { | ||
t.Errorf("\nhave: %v\nwant: %v\n", have, want) | ||
} | ||
} | ||
|
||
func TestGaugeInfoSnapshot(t *testing.T) { | ||
g := NewGaugeInfo() | ||
g.Update(GaugeInfoValue{"value": "original"}) | ||
snapshot := g.Snapshot() // Snapshot @chainid 5 | ||
g.Update(GaugeInfoValue{"value": "updated"}) | ||
// The 'g' should be updated | ||
if have, want := g.Value().String(), `{"value":"updated"}`; have != want { | ||
t.Errorf("\nhave: %v\nwant: %v\n", have, want) | ||
} | ||
// Snapshot should be unupdated | ||
if have, want := snapshot.Value().String(), `{"value":"original"}`; have != want { | ||
t.Errorf("\nhave: %v\nwant: %v\n", have, want) | ||
} | ||
} | ||
|
||
func TestGetOrRegisterGaugeInfo(t *testing.T) { | ||
r := NewRegistry() | ||
NewRegisteredGaugeInfo("foo", r).Update( | ||
GaugeInfoValue{"chain_id": "5"}) | ||
g := GetOrRegisterGaugeInfo("foo", r) | ||
if have, want := g.Value().String(), `{"chain_id":"5"}`; have != want { | ||
t.Errorf("have\n%v\nwant\n%v\n", have, want) | ||
} | ||
} | ||
|
||
func TestFunctionalGaugeInfo(t *testing.T) { | ||
info := GaugeInfoValue{"chain_id": "0"} | ||
counter := 1 | ||
// A "functional" gauge invokes the method to obtain the value | ||
fg := NewFunctionalGaugeInfo(func() GaugeInfoValue { | ||
info["chain_id"] = strconv.Itoa(counter) | ||
counter++ | ||
return info | ||
}) | ||
fg.Value() | ||
fg.Value() | ||
if have, want := info["chain_id"], "2"; have != want { | ||
t.Errorf("have %v want %v", have, want) | ||
} | ||
} | ||
|
||
func TestGetOrRegisterFunctionalGaugeInfo(t *testing.T) { | ||
r := NewRegistry() | ||
NewRegisteredFunctionalGaugeInfo("foo", r, func() GaugeInfoValue { | ||
return GaugeInfoValue{ | ||
"chain_id": "5", | ||
} | ||
}) | ||
want := `{"chain_id":"5"}` | ||
have := GetOrRegisterGaugeInfo("foo", r).Value().String() | ||
if have != want { | ||
t.Errorf("have\n%v\nwant\n%v\n", have, want) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.