mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
metrics/*,cmd/geth,core/blockchain: Implemented support for informational metrics
- Created GaugeInfo metrics type for registering informational metrics. - Updated all related metrics modules to support the new GaugeInfo type. - Registered chain/info GaugeInfo with the chain_id value. - Registered geth/info GaugeInfo with system and build parameters. Implements #21783
This commit is contained in:
parent
d4e345c7d4
commit
44a7ea23f5
16 changed files with 409 additions and 1 deletions
|
|
@ -22,6 +22,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
@ -35,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/eth/catalyst"
|
"github.com/ethereum/go-ethereum/eth/catalyst"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/internal/version"
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
|
|
@ -161,6 +164,24 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
|
||||||
}
|
}
|
||||||
applyMetricConfig(ctx, &cfg)
|
applyMetricConfig(ctx, &cfg)
|
||||||
|
|
||||||
|
// Create Info Gauge with geth system and build information
|
||||||
|
gethInfoGauge := metrics.NewRegisteredGaugeInfo("geth/info", nil)
|
||||||
|
protocolVersions := ""
|
||||||
|
for idx, val := range eth.ProtocolVersions {
|
||||||
|
protocolVersions += strconv.FormatUint(uint64(val), 10)
|
||||||
|
if idx < len(eth.ProtocolVersions)-1 {
|
||||||
|
protocolVersions += ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gethInfo := metrics.GaugeInfoValue{
|
||||||
|
metrics.NewGaugeInfoEntry("version", params.VersionWithMeta),
|
||||||
|
metrics.NewGaugeInfoEntry("arch", runtime.GOARCH),
|
||||||
|
metrics.NewGaugeInfoEntry("os", runtime.GOOS),
|
||||||
|
metrics.NewGaugeInfoEntry("commit", gitCommit),
|
||||||
|
metrics.NewGaugeInfoEntry("protocol_versions", protocolVersions),
|
||||||
|
}
|
||||||
|
gethInfoGauge.Update(gethInfo)
|
||||||
|
|
||||||
return stack, cfg
|
return stack, cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ var (
|
||||||
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
||||||
headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil)
|
headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil)
|
||||||
|
|
||||||
|
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
||||||
|
|
||||||
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
||||||
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
||||||
accountUpdateTimer = metrics.NewRegisteredTimer("chain/account/updates", nil)
|
accountUpdateTimer = metrics.NewRegisteredTimer("chain/account/updates", nil)
|
||||||
|
|
@ -322,6 +324,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
bc.currentFinalBlock.Store(nil)
|
bc.currentFinalBlock.Store(nil)
|
||||||
bc.currentSafeBlock.Store(nil)
|
bc.currentSafeBlock.Store(nil)
|
||||||
|
|
||||||
|
// Update chain info data metrics
|
||||||
|
chainInfoGauge.Update(
|
||||||
|
metrics.GaugeInfoValue{
|
||||||
|
{Key: "chain_id", Val: bc.chainConfig.ChainID.String()},
|
||||||
|
})
|
||||||
|
|
||||||
// If Geth is initialized with an external ancient store, re-initialize the
|
// If Geth is initialized with an external ancient store, re-initialize the
|
||||||
// missing chain indexes and chain flags. This procedure can survive crash
|
// missing chain indexes and chain flags. This procedure can survive crash
|
||||||
// and can be resumed in next restart since chain flags are updated in last step.
|
// and can be resumed in next restart since chain flags are updated in last step.
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,20 @@ func (exp *exp) getFloat(name string) *expvar.Float {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (exp *exp) getInfo(name string) *expvar.String {
|
||||||
|
var v *expvar.String
|
||||||
|
exp.expvarLock.Lock()
|
||||||
|
p := expvar.Get(name)
|
||||||
|
if p != nil {
|
||||||
|
v = p.(*expvar.String)
|
||||||
|
} else {
|
||||||
|
v = new(expvar.String)
|
||||||
|
expvar.Publish(name, v)
|
||||||
|
}
|
||||||
|
exp.expvarLock.Unlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func (exp *exp) publishCounter(name string, metric metrics.Counter) {
|
func (exp *exp) publishCounter(name string, metric metrics.Counter) {
|
||||||
v := exp.getInt(name)
|
v := exp.getInt(name)
|
||||||
v.Set(metric.Count())
|
v.Set(metric.Count())
|
||||||
|
|
@ -113,6 +127,10 @@ func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) {
|
||||||
exp.getFloat(name).Set(metric.Value())
|
exp.getFloat(name).Set(metric.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (exp *exp) publishGaugeInfo(name string, metric metrics.GaugeInfo) {
|
||||||
|
exp.getInfo(name).Set(fmt.Sprintf("%s", metric.Value()))
|
||||||
|
}
|
||||||
|
|
||||||
func (exp *exp) publishHistogram(name string, metric metrics.Histogram) {
|
func (exp *exp) publishHistogram(name string, metric metrics.Histogram) {
|
||||||
h := metric.Snapshot()
|
h := metric.Snapshot()
|
||||||
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
||||||
|
|
@ -178,6 +196,8 @@ func (exp *exp) syncToExpvar() {
|
||||||
exp.publishGauge(name, i)
|
exp.publishGauge(name, i)
|
||||||
case metrics.GaugeFloat64:
|
case metrics.GaugeFloat64:
|
||||||
exp.publishGaugeFloat64(name, i)
|
exp.publishGaugeFloat64(name, i)
|
||||||
|
case metrics.GaugeInfo:
|
||||||
|
exp.publishGaugeInfo(name, i)
|
||||||
case metrics.Histogram:
|
case metrics.Histogram:
|
||||||
exp.publishHistogram(name, i)
|
exp.publishHistogram(name, i)
|
||||||
case metrics.Meter:
|
case metrics.Meter:
|
||||||
|
|
|
||||||
175
metrics/gauge_info.go
Normal file
175
metrics/gauge_info.go
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GaugeInfos hold a GaugeInfoValue value that can be set arbitrarily.
|
||||||
|
type GaugeInfo interface {
|
||||||
|
Snapshot() GaugeInfo
|
||||||
|
Update(GaugeInfoValue)
|
||||||
|
Value() GaugeInfoValue
|
||||||
|
ValueJsonString() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GaugeInfoEntry struct {
|
||||||
|
Key string
|
||||||
|
Val string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GaugeInfoValue []GaugeInfoEntry
|
||||||
|
|
||||||
|
func NewGaugeInfoEntry(key string, val string) GaugeInfoEntry {
|
||||||
|
return GaugeInfoEntry{key, val}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) }
|
||||||
|
|
||||||
|
// Value returns the value at the time the snapshot was taken in JSON string format.
|
||||||
|
func (g GaugeInfoSnapshot) ValueJsonString() string {
|
||||||
|
return gaugeInfoValueToJsonString(g.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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{} }
|
||||||
|
|
||||||
|
// Value is a no-op.
|
||||||
|
func (NilGaugeInfo) ValueJsonString() string { return gaugeInfoValueToJsonString(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the gauge's current value in JSON string format.
|
||||||
|
func (g *StandardGaugeInfo) ValueJsonString() string {
|
||||||
|
g.mutex.Lock()
|
||||||
|
defer g.mutex.Unlock()
|
||||||
|
return gaugeInfoValueToJsonString(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 {
|
||||||
|
return gaugeInfoValueToJsonString(g.value())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom conversion to Json to avoid printing "Key" and "Val"
|
||||||
|
func gaugeInfoValueToJsonString(g GaugeInfoValue) string {
|
||||||
|
lastIdx := len(g) - 1
|
||||||
|
v := "{"
|
||||||
|
for idx, entry := range g {
|
||||||
|
v += "\"" + entry.Key + "\":\"" + entry.Val + "\""
|
||||||
|
if idx != lastIdx {
|
||||||
|
v += ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v += "}"
|
||||||
|
return v
|
||||||
|
}
|
||||||
129
metrics/gauge_info_test.go
Normal file
129
metrics/gauge_info_test.go
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkGuageInfo(b *testing.B) {
|
||||||
|
g := NewGaugeInfo()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
g.Update(GaugeInfoValue{
|
||||||
|
{"chain_id", string(rune(i))},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGaugeInfo(t *testing.T) {
|
||||||
|
g := NewGaugeInfo()
|
||||||
|
g.Update(GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expected := GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
}
|
||||||
|
for idx, v := range g.Value() {
|
||||||
|
if v.Key != expected[idx].Key || v.Val != expected[idx].Val {
|
||||||
|
t.Errorf("g.Value()[%v]: %v != %v\n", idx, v, expected[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGaugeInfoSnapshot(t *testing.T) {
|
||||||
|
g := NewGaugeInfo()
|
||||||
|
g.Update(GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
})
|
||||||
|
snapshot := g.Snapshot()
|
||||||
|
g.Update(GaugeInfoValue{
|
||||||
|
{"chain_id", "1"},
|
||||||
|
})
|
||||||
|
expected := GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
}
|
||||||
|
for idx, v := range snapshot.Value() {
|
||||||
|
if v.Key != expected[idx].Key || v.Val != expected[idx].Val {
|
||||||
|
t.Errorf("g.Value()[%v]: %v != %v\n", idx, v, expected[idx])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetOrRegisterGaugeInfo(t *testing.T) {
|
||||||
|
r := NewRegistry()
|
||||||
|
NewRegisteredGaugeInfo("foo", r).Update(GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
})
|
||||||
|
expected := GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
}
|
||||||
|
g := GetOrRegisterGaugeInfo("foo", r)
|
||||||
|
for idx, v := range g.Value() {
|
||||||
|
if v.Key != expected[idx].Key || v.Val != expected[idx].Val {
|
||||||
|
t.Fatal(g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFunctionalGaugeInfo(t *testing.T) {
|
||||||
|
info := GaugeInfoValue{
|
||||||
|
{"chain_id", "0"},
|
||||||
|
}
|
||||||
|
counter := 1
|
||||||
|
fg := NewFunctionalGaugeInfo(func() GaugeInfoValue {
|
||||||
|
info[0].Val = strconv.Itoa(counter)
|
||||||
|
counter++
|
||||||
|
return info
|
||||||
|
})
|
||||||
|
fg.Value()
|
||||||
|
fg.Value()
|
||||||
|
if info[0].Val != "2" {
|
||||||
|
t.Error("info[0].Val != \"2\" -> ", info[0].Val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetOrRegisterFunctionalGaugeInfo(t *testing.T) {
|
||||||
|
r := NewRegistry()
|
||||||
|
NewRegisteredFunctionalGaugeInfo("foo", r, func() GaugeInfoValue {
|
||||||
|
return GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expected := GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
}
|
||||||
|
g := GetOrRegisterGaugeInfo("foo", r)
|
||||||
|
for idx, v := range g.Value() {
|
||||||
|
if v.Key != expected[idx].Key || v.Val != expected[idx].Val {
|
||||||
|
t.Fatal(g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGaugeInfoValueJsonString(t *testing.T) {
|
||||||
|
g := NewGaugeInfo()
|
||||||
|
g.Update(GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
{"anotherKey", "any_string_value"},
|
||||||
|
{"third_key", "anything"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expected := `{"chain_id":"5","anotherKey":"any_string_value","third_key":"anything"}`
|
||||||
|
got := g.ValueJsonString()
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("g.ValueToJsonString(): %s != %s\n", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleGetOrRegisterGaugeInfo() {
|
||||||
|
m := "chain/info"
|
||||||
|
g := GetOrRegisterGaugeInfo(m, nil)
|
||||||
|
g.Update(GaugeInfoValue{
|
||||||
|
{"chain_id", "5"},
|
||||||
|
{"random_value", "10"},
|
||||||
|
{"chain_data", "356"},
|
||||||
|
})
|
||||||
|
fmt.Println(g.Value()) // Output: [{chain_id 5} {random_value 10} {chain_data 356}]
|
||||||
|
}
|
||||||
|
|
@ -73,6 +73,8 @@ func graphite(c *GraphiteConfig) error {
|
||||||
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now)
|
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now)
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now)
|
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now)
|
||||||
|
case GaugeInfo:
|
||||||
|
fmt.Fprintf(w, "%s.%s.value %s %d\n", c.Prefix, name, metric.ValueJsonString(), now)
|
||||||
case Histogram:
|
case Histogram:
|
||||||
h := metric.Snapshot()
|
h := metric.Snapshot()
|
||||||
ps := h.Percentiles(c.Percentiles)
|
ps := h.Percentiles(c.Percentiles)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,13 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
|
||||||
"value": metric.Snapshot().Value(),
|
"value": metric.Snapshot().Value(),
|
||||||
}
|
}
|
||||||
return measurement, fields
|
return measurement, fields
|
||||||
|
case metrics.GaugeInfo:
|
||||||
|
ms := metric.Snapshot()
|
||||||
|
measurement := fmt.Sprintf("%s%s.gauge", namespace, name)
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"value": ms.ValueJsonString(),
|
||||||
|
}
|
||||||
|
return measurement, fields
|
||||||
case metrics.Histogram:
|
case metrics.Histogram:
|
||||||
ms := metric.Snapshot()
|
ms := metric.Snapshot()
|
||||||
if ms.Count() <= 0 {
|
if ms.Count() <= 0 {
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,10 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
measurement[Name] = name
|
measurement[Name] = name
|
||||||
measurement[Value] = m.Value()
|
measurement[Value] = m.Value()
|
||||||
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
||||||
|
case metrics.GaugeInfo:
|
||||||
|
measurement[Name] = name
|
||||||
|
measurement[Value] = m.Value()
|
||||||
|
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
||||||
case metrics.Histogram:
|
case metrics.Histogram:
|
||||||
if m.Count() > 0 {
|
if m.Count() > 0 {
|
||||||
gauges := make([]Measurement, histogramGaugeCount)
|
gauges := make([]Measurement, histogramGaugeCount)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) {
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
l.Printf("gauge %s\n", name)
|
l.Printf("gauge %s\n", name)
|
||||||
l.Printf(" value: %f\n", metric.Value())
|
l.Printf(" value: %f\n", metric.Value())
|
||||||
|
case GaugeInfo:
|
||||||
|
l.Printf("gauge %s\n", name)
|
||||||
|
l.Printf(" value: %s\n", metric.Value())
|
||||||
case Healthcheck:
|
case Healthcheck:
|
||||||
metric.Check()
|
metric.Check()
|
||||||
l.Printf("healthcheck %s\n", name)
|
l.Printf("healthcheck %s\n", name)
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,8 @@ func openTSDB(c *OpenTSDBConfig) error {
|
||||||
fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname)
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname)
|
||||||
|
case GaugeInfo:
|
||||||
|
fmt.Fprintf(w, "put %s.%s.value %d %s host=%s\n", c.Prefix, name, now, metric.ValueJsonString(), shortHostname)
|
||||||
case Histogram:
|
case Histogram:
|
||||||
h := metric.Snapshot()
|
h := metric.Snapshot()
|
||||||
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,10 @@ func (c *collector) addGaugeFloat64(name string, m metrics.GaugeFloat64) {
|
||||||
c.writeGaugeCounter(name, m.Value())
|
c.writeGaugeCounter(name, m.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *collector) addGaugeInfo(name string, m metrics.GaugeInfo) {
|
||||||
|
c.writeGaugeInfo(name, m.Value())
|
||||||
|
}
|
||||||
|
|
||||||
func (c *collector) addHistogram(name string, m metrics.Histogram) {
|
func (c *collector) addHistogram(name string, m metrics.Histogram) {
|
||||||
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
||||||
ps := m.Percentiles(pv)
|
ps := m.Percentiles(pv)
|
||||||
|
|
@ -102,6 +106,19 @@ func (c *collector) addResettingTimer(name string, m metrics.ResettingTimer) {
|
||||||
c.buff.WriteRune('\n')
|
c.buff.WriteRune('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *collector) writeGaugeInfo(name string, value metrics.GaugeInfoValue) {
|
||||||
|
name = mutateKey(name)
|
||||||
|
c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
|
||||||
|
c.buff.WriteString(fmt.Sprintf("%s {", name))
|
||||||
|
for idx, entry := range value {
|
||||||
|
c.buff.WriteString(fmt.Sprintf("%s=\"%s\"", entry.Key, entry.Val))
|
||||||
|
if idx != len(value)-1 {
|
||||||
|
c.buff.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.buff.WriteString("} 1 \n\n")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *collector) writeGaugeCounter(name string, value interface{}) {
|
func (c *collector) writeGaugeCounter(name string, value interface{}) {
|
||||||
name = mutateKey(name)
|
name = mutateKey(name)
|
||||||
c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
|
c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name))
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,16 @@ func TestCollector(t *testing.T) {
|
||||||
gaugeFloat64.Update(34567.89)
|
gaugeFloat64.Update(34567.89)
|
||||||
c.addGaugeFloat64("test/gauge_float64", gaugeFloat64)
|
c.addGaugeFloat64("test/gauge_float64", gaugeFloat64)
|
||||||
|
|
||||||
|
gaugeInfo := metrics.NewGaugeInfo()
|
||||||
|
gaugeInfo.Update(metrics.GaugeInfoValue{
|
||||||
|
metrics.NewGaugeInfoEntry("version", "1.10.18-unstable"),
|
||||||
|
metrics.NewGaugeInfoEntry("arch", "amd64"),
|
||||||
|
metrics.NewGaugeInfoEntry("os", "linux"),
|
||||||
|
metrics.NewGaugeInfoEntry("commit", "7caa2d8163ae3132c1c2d6978c76610caee2d949"),
|
||||||
|
metrics.NewGaugeInfoEntry("protocol_versions", "64 65 66"),
|
||||||
|
})
|
||||||
|
c.addGaugeInfo("geth/info", gaugeInfo)
|
||||||
|
|
||||||
histogram := metrics.NewHistogram(&metrics.NilSample{})
|
histogram := metrics.NewHistogram(&metrics.NilSample{})
|
||||||
c.addHistogram("test/histogram", histogram)
|
c.addHistogram("test/histogram", histogram)
|
||||||
|
|
||||||
|
|
@ -74,6 +84,9 @@ test_gauge 23456
|
||||||
# TYPE test_gauge_float64 gauge
|
# TYPE test_gauge_float64 gauge
|
||||||
test_gauge_float64 34567.89
|
test_gauge_float64 34567.89
|
||||||
|
|
||||||
|
# TYPE geth_info gauge
|
||||||
|
geth_info {version="1.10.18-unstable", arch="amd64", os="linux", commit="7caa2d8163ae3132c1c2d6978c76610caee2d949", protocol_versions="64 65 66"} 1
|
||||||
|
|
||||||
# TYPE test_histogram_count counter
|
# TYPE test_histogram_count counter
|
||||||
test_histogram_count 0
|
test_histogram_count 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ func Handler(reg metrics.Registry) http.Handler {
|
||||||
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())
|
||||||
|
case metrics.GaugeInfo:
|
||||||
|
c.addGaugeInfo(name, m.Snapshot())
|
||||||
case metrics.Histogram:
|
case metrics.Histogram:
|
||||||
c.addHistogram(name, m.Snapshot())
|
c.addHistogram(name, m.Snapshot())
|
||||||
case metrics.Meter:
|
case metrics.Meter:
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,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, 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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) {
|
||||||
w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Value()))
|
w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Value()))
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Value()))
|
w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Value()))
|
||||||
|
case GaugeInfo:
|
||||||
|
w.Info(fmt.Sprintf("gauge %s: value: %s", name, metric.Value()))
|
||||||
case Healthcheck:
|
case Healthcheck:
|
||||||
metric.Check()
|
metric.Check()
|
||||||
w.Info(fmt.Sprintf("healthcheck %s: error: %v", name, metric.Error()))
|
w.Info(fmt.Sprintf("healthcheck %s: error: %v", name, metric.Error()))
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ func WriteOnce(r Registry, w io.Writer) {
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
fmt.Fprintf(w, "gauge %s\n", namedMetric.name)
|
fmt.Fprintf(w, "gauge %s\n", namedMetric.name)
|
||||||
fmt.Fprintf(w, " value: %f\n", metric.Value())
|
fmt.Fprintf(w, " value: %f\n", metric.Value())
|
||||||
|
case GaugeInfo:
|
||||||
|
fmt.Fprintf(w, "gauge %s\n", namedMetric.name)
|
||||||
|
fmt.Fprintf(w, " value: %s\n", metric.ValueJsonString())
|
||||||
case Healthcheck:
|
case Healthcheck:
|
||||||
metric.Check()
|
metric.Check()
|
||||||
fmt.Fprintf(w, "healthcheck %s\n", namedMetric.name)
|
fmt.Fprintf(w, "healthcheck %s\n", namedMetric.name)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue