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.
This commit is contained in:
Martin Holst Swende 2023-08-30 11:21:12 +02:00
parent 8e61797780
commit 5627ca12fb
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
9 changed files with 169 additions and 168 deletions

View file

@ -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"
)
@ -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)
@ -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)
@ -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 ""
}

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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.

View file

@ -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())
}

View file

@ -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) {
@ -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 ""
}

View file

@ -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))
}
}

View file

@ -10,22 +10,30 @@ test_gauge 23456
# TYPE test_gauge_float64 gauge
test_gauge_float64 34567.89
# TYPE geth_info gauge
geth_info {arch="amd64", commit="7caa2d8163ae3132c1c2d6978c76610caee2d949", os="linux", protocol_versions="64 65 66", version="1.10.18-unstable"} 1
# TYPE test_gauge_info gauge
test_gauge_info {arch="amd64", commit="7caa2d8163ae3132c1c2d6978c76610caee2d949", os="linux", protocol_versions="64 65 66", version="1.10.18-unstable"} 1
# TYPE test_histogram_count counter
test_histogram_count 0
test_histogram_count 3
# TYPE test_histogram summary
test_histogram {quantile="0.5"} 0
test_histogram {quantile="0.75"} 0
test_histogram {quantile="0.95"} 0
test_histogram {quantile="0.99"} 0
test_histogram {quantile="0.999"} 0
test_histogram {quantile="0.9999"} 0
test_histogram {quantile="0.5"} 2
test_histogram {quantile="0.75"} 3
test_histogram {quantile="0.95"} 3
test_histogram {quantile="0.99"} 3
test_histogram {quantile="0.999"} 3
test_histogram {quantile="0.9999"} 3
# TYPE test_meter gauge
test_meter 9999999
test_meter 0
# TYPE test_resetting_timer_count counter
test_resetting_timer_count 6
# TYPE test_resetting_timer summary
test_resetting_timer {quantile="0.50"} 12000000
test_resetting_timer {quantile="0.95"} 120000000
test_resetting_timer {quantile="0.99"} 120000000
# TYPE test_timer_count counter
test_timer_count 6
@ -38,11 +46,3 @@ test_timer {quantile="0.99"} 1.2e+08
test_timer {quantile="0.999"} 1.2e+08
test_timer {quantile="0.9999"} 1.2e+08
# TYPE test_resetting_timer_count counter
test_resetting_timer_count 6
# TYPE test_resetting_timer summary
test_resetting_timer {quantile="0.50"} 12000000
test_resetting_timer {quantile="0.95"} 120000000
test_resetting_timer {quantile="0.99"} 120000000