Skip to content

Commit 9045b79

Browse files
holimanfjl
andauthored
metrics, cmd/geth: change init-process of metrics (#30814)
This PR modifies how the metrics library handles `Enabled`: previously, the package `init` decided whether to serve real metrics or just dummy-types. This has several drawbacks: - During pkg init, we need to determine whether metrics are enabled or not. So we first hacked in a check if certain geth-specific commandline-flags were enabled. Then we added a similar check for geth-env-vars. Then we almost added a very elaborate check for toml-config-file, plus toml parsing. - Using "real" types and dummy types interchangeably means that everything is hidden behind interfaces. This has a performance penalty, and also it just adds a lot of code. This PR removes the interface stuff, uses concrete types, and allows for the setting of Enabled to happen later. It is still assumed that `metrics.Enable()` is invoked early on. The somewhat 'heavy' operations, such as ticking meters and exp-decay, now checks the enable-flag to prevent resource leak. The change may be large, but it's mostly pretty trivial, and from the last time I gutted the metrics, I ensured that we have fairly good test coverage. --------- Co-authored-by: Felix Lange <[email protected]>
1 parent 4ecf085 commit 9045b79

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+739
-1396
lines changed

cmd/geth/chaincmd.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import (
3838
"github.com/ethereum/go-ethereum/ethdb"
3939
"github.com/ethereum/go-ethereum/internal/era"
4040
"github.com/ethereum/go-ethereum/log"
41-
"github.com/ethereum/go-ethereum/metrics"
4241
"github.com/ethereum/go-ethereum/params"
4342
"github.com/urfave/cli/v2"
4443
)
@@ -282,14 +281,12 @@ func importChain(ctx *cli.Context) error {
282281
if ctx.Args().Len() < 1 {
283282
utils.Fatalf("This command requires an argument.")
284283
}
285-
// Start metrics export if enabled
286-
utils.SetupMetrics(ctx)
287-
// Start system runtime metrics collection
288-
go metrics.CollectProcessMetrics(3 * time.Second)
289-
290-
stack, _ := makeConfigNode(ctx)
284+
stack, cfg := makeConfigNode(ctx)
291285
defer stack.Close()
292286

287+
// Start metrics export if enabled
288+
utils.SetupMetrics(&cfg.Metrics)
289+
293290
chain, db := utils.MakeChain(ctx, stack, false)
294291
defer db.Close()
295292

cmd/geth/config.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ func makeFullNode(ctx *cli.Context) *node.Node {
192192
cfg.Eth.OverrideVerkle = &v
193193
}
194194

195+
// Start metrics export if enabled
196+
utils.SetupMetrics(&cfg.Metrics)
197+
195198
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
196199

197200
// Create gauge with geth system and build information
@@ -325,6 +328,27 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
325328
if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) {
326329
cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name)
327330
}
331+
// Sanity-check the commandline flags. It is fine if some unused fields is part
332+
// of the toml-config, but we expect the commandline to only contain relevant
333+
// arguments, otherwise it indicates an error.
334+
var (
335+
enableExport = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name)
336+
enableExportV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
337+
)
338+
if enableExport || enableExportV2 {
339+
v1FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) ||
340+
ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name)
341+
342+
v2FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) ||
343+
ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) ||
344+
ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name)
345+
346+
if enableExport && v2FlagIsSet {
347+
utils.Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2")
348+
} else if enableExportV2 && v1FlagIsSet {
349+
utils.Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1")
350+
}
351+
}
328352
}
329353

330354
func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {

cmd/geth/main.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import (
3434
"github.com/ethereum/go-ethereum/internal/debug"
3535
"github.com/ethereum/go-ethereum/internal/flags"
3636
"github.com/ethereum/go-ethereum/log"
37-
"github.com/ethereum/go-ethereum/metrics"
3837
"github.com/ethereum/go-ethereum/node"
3938
"go.uber.org/automaxprocs/maxprocs"
4039

@@ -325,12 +324,6 @@ func prepare(ctx *cli.Context) {
325324
ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096))
326325
}
327326
}
328-
329-
// Start metrics export if enabled
330-
utils.SetupMetrics(ctx)
331-
332-
// Start system runtime metrics collection
333-
go metrics.CollectProcessMetrics(3 * time.Second)
334327
}
335328

336329
// geth is the main entry point into the system if no special subcommand is run.

cmd/utils/flags.go

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,67 +1968,56 @@ func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, target common.H
19681968
log.Info("Registered full-sync tester", "hash", target)
19691969
}
19701970

1971-
func SetupMetrics(ctx *cli.Context) {
1972-
if metrics.Enabled {
1973-
log.Info("Enabling metrics collection")
1974-
1975-
var (
1976-
enableExport = ctx.Bool(MetricsEnableInfluxDBFlag.Name)
1977-
enableExportV2 = ctx.Bool(MetricsEnableInfluxDBV2Flag.Name)
1978-
)
1979-
1980-
if enableExport || enableExportV2 {
1981-
CheckExclusive(ctx, MetricsEnableInfluxDBFlag, MetricsEnableInfluxDBV2Flag)
1982-
1983-
v1FlagIsSet := ctx.IsSet(MetricsInfluxDBUsernameFlag.Name) ||
1984-
ctx.IsSet(MetricsInfluxDBPasswordFlag.Name)
1985-
1986-
v2FlagIsSet := ctx.IsSet(MetricsInfluxDBTokenFlag.Name) ||
1987-
ctx.IsSet(MetricsInfluxDBOrganizationFlag.Name) ||
1988-
ctx.IsSet(MetricsInfluxDBBucketFlag.Name)
1989-
1990-
if enableExport && v2FlagIsSet {
1991-
Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2")
1992-
} else if enableExportV2 && v1FlagIsSet {
1993-
Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1")
1994-
}
1995-
}
1996-
1997-
var (
1998-
endpoint = ctx.String(MetricsInfluxDBEndpointFlag.Name)
1999-
database = ctx.String(MetricsInfluxDBDatabaseFlag.Name)
2000-
username = ctx.String(MetricsInfluxDBUsernameFlag.Name)
2001-
password = ctx.String(MetricsInfluxDBPasswordFlag.Name)
2002-
2003-
token = ctx.String(MetricsInfluxDBTokenFlag.Name)
2004-
bucket = ctx.String(MetricsInfluxDBBucketFlag.Name)
2005-
organization = ctx.String(MetricsInfluxDBOrganizationFlag.Name)
2006-
)
2007-
2008-
if enableExport {
2009-
tagsMap := SplitTagsFlag(ctx.String(MetricsInfluxDBTagsFlag.Name))
2010-
2011-
log.Info("Enabling metrics export to InfluxDB")
2012-
2013-
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
2014-
} else if enableExportV2 {
2015-
tagsMap := SplitTagsFlag(ctx.String(MetricsInfluxDBTagsFlag.Name))
2016-
2017-
log.Info("Enabling metrics export to InfluxDB (v2)")
2018-
2019-
go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap)
2020-
}
1971+
// SetupMetrics configures the metrics system.
1972+
func SetupMetrics(cfg *metrics.Config) {
1973+
if !cfg.Enabled {
1974+
return
1975+
}
1976+
log.Info("Enabling metrics collection")
1977+
metrics.Enable()
20211978

2022-
if ctx.IsSet(MetricsHTTPFlag.Name) {
2023-
address := net.JoinHostPort(ctx.String(MetricsHTTPFlag.Name), fmt.Sprintf("%d", ctx.Int(MetricsPortFlag.Name)))
2024-
log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address)
2025-
exp.Setup(address)
2026-
} else if ctx.IsSet(MetricsPortFlag.Name) {
2027-
log.Warn(fmt.Sprintf("--%s specified without --%s, metrics server will not start.", MetricsPortFlag.Name, MetricsHTTPFlag.Name))
2028-
}
1979+
// InfluxDB exporter.
1980+
var (
1981+
enableExport = cfg.EnableInfluxDB
1982+
enableExportV2 = cfg.EnableInfluxDBV2
1983+
)
1984+
if cfg.EnableInfluxDB && cfg.EnableInfluxDBV2 {
1985+
Fatalf("Flags %v can't be used at the same time", strings.Join([]string{MetricsEnableInfluxDBFlag.Name, MetricsEnableInfluxDBV2Flag.Name}, ", "))
20291986
}
1987+
var (
1988+
endpoint = cfg.InfluxDBEndpoint
1989+
database = cfg.InfluxDBDatabase
1990+
username = cfg.InfluxDBUsername
1991+
password = cfg.InfluxDBPassword
1992+
1993+
token = cfg.InfluxDBToken
1994+
bucket = cfg.InfluxDBBucket
1995+
organization = cfg.InfluxDBOrganization
1996+
tagsMap = SplitTagsFlag(cfg.InfluxDBTags)
1997+
)
1998+
if enableExport {
1999+
log.Info("Enabling metrics export to InfluxDB")
2000+
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
2001+
} else if enableExportV2 {
2002+
tagsMap := SplitTagsFlag(cfg.InfluxDBTags)
2003+
log.Info("Enabling metrics export to InfluxDB (v2)")
2004+
go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap)
2005+
}
2006+
2007+
// Expvar exporter.
2008+
if cfg.HTTP != "" {
2009+
address := net.JoinHostPort(cfg.HTTP, fmt.Sprintf("%d", cfg.Port))
2010+
log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address)
2011+
exp.Setup(address)
2012+
} else if cfg.HTTP == "" && cfg.Port != 0 {
2013+
log.Warn(fmt.Sprintf("--%s specified without --%s, metrics server will not start.", MetricsPortFlag.Name, MetricsHTTPFlag.Name))
2014+
}
2015+
2016+
// Enable system metrics collection.
2017+
go metrics.CollectProcessMetrics(3 * time.Second)
20302018
}
20312019

2020+
// SplitTagsFlag parses a comma-separated list of k=v metrics tags.
20322021
func SplitTagsFlag(tagsFlag string) map[string]string {
20332022
tags := strings.Split(tagsFlag, ",")
20342023
tagsMap := map[string]string{}

core/rawdb/freezer_table.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,24 @@ type freezerTable struct {
113113
headId uint32 // number of the currently active head file
114114
tailId uint32 // number of the earliest file
115115

116-
headBytes int64 // Number of bytes written to the head file
117-
readMeter metrics.Meter // Meter for measuring the effective amount of data read
118-
writeMeter metrics.Meter // Meter for measuring the effective amount of data written
119-
sizeGauge metrics.Gauge // Gauge for tracking the combined size of all freezer tables
116+
headBytes int64 // Number of bytes written to the head file
117+
readMeter *metrics.Meter // Meter for measuring the effective amount of data read
118+
writeMeter *metrics.Meter // Meter for measuring the effective amount of data written
119+
sizeGauge *metrics.Gauge // Gauge for tracking the combined size of all freezer tables
120120

121121
logger log.Logger // Logger with database path and table name embedded
122122
lock sync.RWMutex // Mutex protecting the data file descriptors
123123
}
124124

125125
// newFreezerTable opens the given path as a freezer table.
126126
func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) {
127-
return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly)
127+
return newTable(path, name, metrics.NewInactiveMeter(), metrics.NewInactiveMeter(), metrics.NewGauge(), freezerTableSize, disableSnappy, readonly)
128128
}
129129

130130
// newTable opens a freezer table, creating the data and index files if they are
131131
// non-existent. Both files are truncated to the shortest common length to ensure
132132
// they don't go out of sync.
133-
func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeGauge metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) {
133+
func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, sizeGauge *metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) {
134134
// Ensure the containing directory exists and open the indexEntry file
135135
if err := os.MkdirAll(path, 0755); err != nil {
136136
return nil, err

core/state/trie_prefetcher.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,21 @@ type triePrefetcher struct {
4747
term chan struct{} // Channel to signal interruption
4848
noreads bool // Whether to ignore state-read-only prefetch requests
4949

50-
deliveryMissMeter metrics.Meter
51-
52-
accountLoadReadMeter metrics.Meter
53-
accountLoadWriteMeter metrics.Meter
54-
accountDupReadMeter metrics.Meter
55-
accountDupWriteMeter metrics.Meter
56-
accountDupCrossMeter metrics.Meter
57-
accountWasteMeter metrics.Meter
58-
59-
storageLoadReadMeter metrics.Meter
60-
storageLoadWriteMeter metrics.Meter
61-
storageDupReadMeter metrics.Meter
62-
storageDupWriteMeter metrics.Meter
63-
storageDupCrossMeter metrics.Meter
64-
storageWasteMeter metrics.Meter
50+
deliveryMissMeter *metrics.Meter
51+
52+
accountLoadReadMeter *metrics.Meter
53+
accountLoadWriteMeter *metrics.Meter
54+
accountDupReadMeter *metrics.Meter
55+
accountDupWriteMeter *metrics.Meter
56+
accountDupCrossMeter *metrics.Meter
57+
accountWasteMeter *metrics.Meter
58+
59+
storageLoadReadMeter *metrics.Meter
60+
storageLoadWriteMeter *metrics.Meter
61+
storageDupReadMeter *metrics.Meter
62+
storageDupWriteMeter *metrics.Meter
63+
storageDupCrossMeter *metrics.Meter
64+
storageWasteMeter *metrics.Meter
6565
}
6666

6767
func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
@@ -111,7 +111,7 @@ func (p *triePrefetcher) terminate(async bool) {
111111

112112
// report aggregates the pre-fetching and usage metrics and reports them.
113113
func (p *triePrefetcher) report() {
114-
if !metrics.Enabled {
114+
if !metrics.Enabled() {
115115
return
116116
}
117117
for _, fetcher := range p.fetchers {

core/txpool/txpool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver {
126126
return ErrAlreadyReserved
127127
}
128128
p.reservations[addr] = subpool
129-
if metrics.Enabled {
129+
if metrics.Enabled() {
130130
m := fmt.Sprintf("%s/%d", reservationsGaugeName, id)
131131
metrics.GetOrRegisterGauge(m, nil).Inc(1)
132132
}
@@ -143,7 +143,7 @@ func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver {
143143
return errors.New("address not owned")
144144
}
145145
delete(p.reservations, addr)
146-
if metrics.Enabled {
146+
if metrics.Enabled() {
147147
m := fmt.Sprintf("%s/%d", reservationsGaugeName, id)
148148
metrics.GetOrRegisterGauge(m, nil).Dec(1)
149149
}

eth/downloader/queue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt, recei
882882
// to access the queue, so they already need a lock anyway.
883883
func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header,
884884
taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest,
885-
reqTimer metrics.Timer, resInMeter metrics.Meter, resDropMeter metrics.Meter,
885+
reqTimer *metrics.Timer, resInMeter, resDropMeter *metrics.Meter,
886886
results int, validate func(index int, header *types.Header) error,
887887
reconstruct func(index int, result *fetchResult)) (int, error) {
888888
// Short circuit if the data was never requested

eth/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error
366366
defer h.decHandlers()
367367

368368
if err := h.peers.registerSnapExtension(peer); err != nil {
369-
if metrics.Enabled {
369+
if metrics.Enabled() {
370370
if peer.Inbound() {
371371
snap.IngressRegistrationErrorMeter.Mark(1)
372372
} else {

eth/protocols/eth/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func handleMessage(backend Backend, peer *Peer) error {
190190
var handlers = eth68
191191

192192
// Track the amount of time it takes to serve the request and run the handler
193-
if metrics.Enabled {
193+
if metrics.Enabled() {
194194
h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code)
195195
defer func(start time.Time) {
196196
sampler := func() metrics.Sample {

0 commit comments

Comments
 (0)