Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

metrics, cmd/geth: informational metrics (prometheus, influxdb, opentsb) #24877

Merged
merged 3 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
metrics/prometheus: refactor tests
This change moves the initialization of an ordered registry to a shared
subpackage in 'internal', and makes it so both influx and prometheus
use the same testdata.
  • Loading branch information
holiman committed Aug 30, 2023
commit 5627ca12fb2fb854b712c2499c64c926a90fc5df
51 changes: 12 additions & 39 deletions metrics/influxdb/influxdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ import (
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"time"

"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/internal"
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
)

Expand All @@ -35,28 +36,8 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}

func setupSampleRegistry(t *testing.T) metrics.Registry {
t.Helper()
r := metrics.NewOrderedRegistry()
metrics.NewRegisteredGaugeInfo("info", r).Update(metrics.GaugeInfoValue{
"version": "1.10.18-unstable",
"arch": "amd64",
"os": "linux",
"commit": "7caa2d8163ae3132c1c2d6978c76610caee2d949",
"protocol_versions": "64 65 66",
})
metrics.NewRegisteredGaugeFloat64("pi", r).Update(3.14)
metrics.NewRegisteredCounter("months", r).Inc(12)
metrics.NewRegisteredCounterFloat64("tau", r).Inc(1.57)
metrics.NewRegisteredMeter("elite", r).Mark(1337)
metrics.NewRegisteredTimer("second", r).Update(time.Second)
metrics.NewRegisteredCounterFloat64("tau", r).Inc(1.57)
metrics.NewRegisteredCounterFloat64("tau", r).Inc(1.57)
return r
}

func TestExampleV1(t *testing.T) {
r := setupSampleRegistry(t)
r := internal.ExampleMetrics()
var have, want string
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
haveB, _ := io.ReadAll(r.Body)
Expand All @@ -83,12 +64,12 @@ func TestExampleV1(t *testing.T) {
}
if have != want {
t.Errorf("\nhave:\n%v\nwant:\n%v\n", have, want)
t.Logf("have vs want:\n %v", findFirstDiffPos(have, want))
t.Logf("have vs want:\n%v", findFirstDiffPos(have, want))
}
}

func TestExampleV2(t *testing.T) {
r := setupSampleRegistry(t)
r := internal.ExampleMetrics()
var have, want string
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
haveB, _ := io.ReadAll(r.Body)
Expand Down Expand Up @@ -120,22 +101,14 @@ func TestExampleV2(t *testing.T) {
}

func findFirstDiffPos(a, b string) string {
x, y := []byte(a), []byte(b)
var res []byte
for i, ch := range x {
if i > len(y) {
res = append(res, ch)
res = append(res, fmt.Sprintf("<-- diff: %#x vs EOF", ch)...)
break
yy := strings.Split(b, "\n")
for i, x := range strings.Split(a, "\n") {
if i >= len(yy) {
return fmt.Sprintf("have:%d: %s\nwant:%d: <EOF>", i, x, i)
}
if ch != y[i] {
res = append(res, fmt.Sprintf("<-- diff: %#x (%c) vs %#x (%c)", ch, ch, y[i], y[i])...)
break
if y := yy[i]; x != y {
return fmt.Sprintf("have:%d: %s\nwant:%d: %s", i, x, i, y)
}
res = append(res, ch)
}
if len(res) > 100 {
res = res[len(res)-100:]
}
return string(res)
return ""
}
15 changes: 9 additions & 6 deletions metrics/influxdb/testdata/influxdbv1.want
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
goth.elite.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
goth.info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
goth.months.count value=12i 978307200000000000
goth.pi.gauge value=3.14 978307200000000000
goth.second.timer count=1i,m1=0,m15=0,m5=0,max=1000000000i,mean=1000000000,meanrate=0,min=1000000000i,p50=1000000000,p75=1000000000,p95=1000000000,p99=1000000000,p999=1000000000,p9999=1000000000,stddev=0,variance=0 978307200000000000
goth.tau.count value=1.57 978307200000000000
goth.test/counter.count value=12345 978307200000000000
goth.test/counter_float64.count value=54321.98 978307200000000000
goth.test/gauge.gauge value=23456i 978307200000000000
goth.test/gauge_float64.gauge value=34567.89 978307200000000000
goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000
goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12000000i,p95=120000000i,p99=120000000i 978307200000000000
goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000
15 changes: 9 additions & 6 deletions metrics/influxdb/testdata/influxdbv2.want
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
goth.elite.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
goth.info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
goth.months.count value=12i 978307200000000000
goth.pi.gauge value=3.14 978307200000000000
goth.second.timer count=1i,m1=0,m15=0,m5=0,max=1000000000i,mean=1000000000,meanrate=0,min=1000000000i,p50=1000000000,p75=1000000000,p95=1000000000,p99=1000000000,p999=1000000000,p9999=1000000000,stddev=0,variance=0 978307200000000000
goth.tau.count value=1.57 978307200000000000
goth.test/counter.count value=12345 978307200000000000
goth.test/counter_float64.count value=54321.98 978307200000000000
goth.test/gauge.gauge value=23456i 978307200000000000
goth.test/gauge_float64.gauge value=34567.89 978307200000000000
goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000
goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12000000i,p95=120000000i,p99=120000000i 978307200000000000
goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000
64 changes: 64 additions & 0 deletions metrics/internal/sampledata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package internal

import (
"time"

"github.com/ethereum/go-ethereum/metrics"
)

// ExampleMetrics returns an ordered registry populated with a sample of metrics.
func ExampleMetrics() metrics.Registry {
var registry = metrics.NewOrderedRegistry()

metrics.NewRegisteredCounterFloat64("test/counter", registry).Inc(12345)
metrics.NewRegisteredCounterFloat64("test/counter_float64", registry).Inc(54321.98)
metrics.NewRegisteredGauge("test/gauge", registry).Update(23456)
metrics.NewRegisteredGaugeFloat64("test/gauge_float64", registry).Update(34567.89)
metrics.NewRegisteredGaugeInfo("test/gauge_info", registry).Update(
metrics.GaugeInfoValue{
"version": "1.10.18-unstable",
"arch": "amd64",
"os": "linux",
"commit": "7caa2d8163ae3132c1c2d6978c76610caee2d949",
"protocol_versions": "64 65 66",
})
metrics.NewRegisteredHistogram("test/histogram", registry, metrics.NewSampleSnapshot(3, []int64{1, 2, 3}))
registry.Register("test/meter", metrics.NewInactiveMeter())
{
timer := metrics.NewRegisteredResettingTimer("test/resetting_timer", registry)
timer.Update(10 * time.Millisecond)
timer.Update(11 * time.Millisecond)
timer.Update(12 * time.Millisecond)
timer.Update(120 * time.Millisecond)
timer.Update(13 * time.Millisecond)
timer.Update(14 * time.Millisecond)
}
{
timer := metrics.NewRegisteredTimer("test/timer", registry)
timer.Update(20 * time.Millisecond)
timer.Update(21 * time.Millisecond)
timer.Update(22 * time.Millisecond)
timer.Update(120 * time.Millisecond)
timer.Update(23 * time.Millisecond)
timer.Update(24 * time.Millisecond)
timer.Stop()
}
registry.Register("test/empty_resetting_timer", metrics.NewResettingTimer().Snapshot())
return registry
}
10 changes: 10 additions & 0 deletions metrics/meter.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ func NewMeter() Meter {
return m
}

// NewInactiveMeter returns a meter but does not start any goroutines. This
// method is mainly intended for testing.
func NewInactiveMeter() Meter {
if !Enabled {
return NilMeter{}
}
m := newStandardMeter()
return m
}

// NewMeterForced constructs a new StandardMeter and launches a goroutine no matter
// the global switch is enabled or not.
// Be sure to call Stop() once the meter is of no use to allow for garbage collection.
Expand Down
28 changes: 28 additions & 0 deletions metrics/prometheus/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ func newCollector() *collector {
}
}

// Add adds the metric i to the collector. This method returns an error if the
// metric type is not supported/known.
func (c *collector) Add(name string, i any) error {
switch m := i.(type) {
case metrics.Counter:
c.addCounter(name, m.Snapshot())
case metrics.CounterFloat64:
c.addCounterFloat64(name, m.Snapshot())
case metrics.Gauge:
c.addGauge(name, m.Snapshot())
case metrics.GaugeFloat64:
c.addGaugeFloat64(name, m.Snapshot())
case metrics.GaugeInfo:
c.addGaugeInfo(name, m.Snapshot())
case metrics.Histogram:
c.addHistogram(name, m.Snapshot())
case metrics.Meter:
c.addMeter(name, m.Snapshot())
case metrics.Timer:
c.addTimer(name, m.Snapshot())
case metrics.ResettingTimer:
c.addResettingTimer(name, m.Snapshot())
default:
return fmt.Errorf("unknown prometheus metric type %T", i)
}
return nil
}

func (c *collector) addCounter(name string, m metrics.Counter) {
c.writeGaugeCounter(name, m.Count())
}
Expand Down
96 changes: 18 additions & 78 deletions metrics/prometheus/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ package prometheus
import (
"fmt"
"os"
"strings"
"testing"
"time"

"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/internal"
)

func TestMain(m *testing.M) {
Expand All @@ -31,95 +32,34 @@ func TestMain(m *testing.M) {
}

func TestCollector(t *testing.T) {
c := newCollector()

counter := metrics.NewCounter()
counter.Inc(12345)
c.addCounter("test/counter", counter)

counterfloat64 := metrics.NewCounterFloat64()
counterfloat64.Inc(54321.98)
c.addCounterFloat64("test/counter_float64", counterfloat64)

gauge := metrics.NewGauge()
gauge.Update(23456)
c.addGauge("test/gauge", gauge)

gaugeFloat64 := metrics.NewGaugeFloat64()
gaugeFloat64.Update(34567.89)
c.addGaugeFloat64("test/gauge_float64", gaugeFloat64)

gaugeInfo := metrics.NewGaugeInfo()
gaugeInfo.Update(metrics.GaugeInfoValue{
"version": "1.10.18-unstable",
"arch": "amd64",
"os": "linux",
"commit": "7caa2d8163ae3132c1c2d6978c76610caee2d949",
"protocol_versions": "64 65 66",
var (
c = newCollector()
want string
)
internal.ExampleMetrics().Each(func(name string, i interface{}) {
c.Add(name, i)
})
c.addGaugeInfo("geth/info", gaugeInfo)

histogram := metrics.NewHistogram(&metrics.NilSample{})
c.addHistogram("test/histogram", histogram)

meter := metrics.NewMeter()
defer meter.Stop()
meter.Mark(9999999)
c.addMeter("test/meter", meter)

timer := metrics.NewTimer()
defer timer.Stop()
timer.Update(20 * time.Millisecond)
timer.Update(21 * time.Millisecond)
timer.Update(22 * time.Millisecond)
timer.Update(120 * time.Millisecond)
timer.Update(23 * time.Millisecond)
timer.Update(24 * time.Millisecond)
c.addTimer("test/timer", timer)

resettingTimer := metrics.NewResettingTimer()
resettingTimer.Update(10 * time.Millisecond)
resettingTimer.Update(11 * time.Millisecond)
resettingTimer.Update(12 * time.Millisecond)
resettingTimer.Update(120 * time.Millisecond)
resettingTimer.Update(13 * time.Millisecond)
resettingTimer.Update(14 * time.Millisecond)
c.addResettingTimer("test/resetting_timer", resettingTimer.Snapshot())

emptyResettingTimer := metrics.NewResettingTimer().Snapshot()
c.addResettingTimer("test/empty_resetting_timer", emptyResettingTimer)

var want string
if wantB, err := os.ReadFile("./testdata/prometheus.want"); err != nil {
t.Fatal(err)
} else {
want = string(wantB)
}
have := c.buff.String()
if have != want {
if have := c.buff.String(); have != want {
t.Logf("have\n%v", have)
t.Logf("have vs want:\n %v", findFirstDiffPos(have, want))
t.Fatal("unexpected collector output")
t.Logf("have vs want:\n%v", findFirstDiffPos(have, want))
t.Fatalf("unexpected collector output")
}
}

func findFirstDiffPos(a, b string) string {
x, y := []byte(a), []byte(b)
var res []byte
for i, ch := range x {
if i > len(y) {
res = append(res, ch)
res = append(res, fmt.Sprintf("<-- diff: %#x vs EOF", ch)...)
break
yy := strings.Split(b, "\n")
for i, x := range strings.Split(a, "\n") {
if i >= len(yy) {
return fmt.Sprintf("a:%d: %s\nb:%d: <EOF>", i, x, i)
}
if ch != y[i] {
res = append(res, fmt.Sprintf("<-- diff: %#x (%c) vs %#x (%c)", ch, ch, y[i], y[i])...)
break
if y := yy[i]; x != y {
return fmt.Sprintf("a:%d: %s\nb:%d: %s", i, x, i, y)
}
res = append(res, ch)
}
if len(res) > 100 {
res = res[len(res)-100:]
}
return string(res)
return ""
}
22 changes: 1 addition & 21 deletions metrics/prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,7 @@ func Handler(reg metrics.Registry) http.Handler {

for _, name := range names {
i := reg.Get(name)

switch m := i.(type) {
case metrics.Counter:
c.addCounter(name, m.Snapshot())
case metrics.CounterFloat64:
c.addCounterFloat64(name, m.Snapshot())
case metrics.Gauge:
c.addGauge(name, m.Snapshot())
case metrics.GaugeFloat64:
c.addGaugeFloat64(name, m.Snapshot())
case metrics.GaugeInfo:
c.addGaugeInfo(name, m.Snapshot())
case metrics.Histogram:
c.addHistogram(name, m.Snapshot())
case metrics.Meter:
c.addMeter(name, m.Snapshot())
case metrics.Timer:
c.addTimer(name, m.Snapshot())
case metrics.ResettingTimer:
c.addResettingTimer(name, m.Snapshot())
default:
if err := c.Add(name, i); err != nil {
log.Warn("Unknown Prometheus metric type", "type", fmt.Sprintf("%T", i))
}
}
Expand Down
Loading