From be383497580e034c2c160691dfef40ee12a55993 Mon Sep 17 00:00:00 2001 From: 0xste <16362825+0xste@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:34:46 +0100 Subject: [PATCH 1/5] feat(issue-253): initial metrics implementation --- CONTRIBUTING.md | 2 +- README.md | 4 ++++ cli/flags.go | 7 +++++++ cli/main.go | 21 +++++++++++++++++++++ go.mod | 2 +- server/service.go | 28 +++++++++++++++++++++++++++- 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e640fe8c..f0b9073d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Please start by reading our [code of conduct](CODE_OF_CONDUCT.md). ## Set up -Install a few dev dependencies for `make lint`: https://github.com/flashbots/mev-boost/blob/go122/.github/workflows/lint.yml#L29-L37 +Install a few dev dependencies for `make lint`: https://github.com/flashbots/mev-boost/blob/develop/.github/workflows/lint.yml#L29-L37 Look at the [README for instructions to install the dependencies and build `mev-boost`](README.md#installing) diff --git a/README.md b/README.md index 41111059..77e3ed1f 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,10 @@ sequenceDiagram mev_boost-->>consensus: submitBlindedBlock response ``` +# Metrics + +Optionally the `-prometheus-port=9000` flag can be passed to expose prometheus metrics on specified port + # Maintainers - [@metachris](https://github.com/metachris) diff --git a/cli/flags.go b/cli/flags.go index c37cfcac..f976da48 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -34,6 +34,7 @@ var flags = []cli.Flag{ timeoutGetPayloadFlag, timeoutRegValFlag, maxRetriesFlag, + prometheusListenAddr, } var ( @@ -83,6 +84,12 @@ var ( Usage: "disables adding the version to every log entry", Category: LoggingCategory, } + prometheusListenAddr = &cli.IntFlag{ + Name: "prometheus-port", + Sources: cli.EnvVars("PROMETHEUS_PORT"), + Usage: "when set to a valid http port, will export runtime metrics to a prometheus server on that port", + Category: LoggingCategory, + } // Genesis Flags customGenesisForkFlag = &cli.StringFlag{ Name: "genesis-fork-version", diff --git a/cli/main.go b/cli/main.go index eaaa5b29..ef8e8737 100644 --- a/cli/main.go +++ b/cli/main.go @@ -5,6 +5,7 @@ import ( "errors" "flag" "fmt" + "math" "os" "strings" "time" @@ -13,6 +14,8 @@ import ( "github.com/flashbots/mev-boost/common" "github.com/flashbots/mev-boost/config" "github.com/flashbots/mev-boost/server" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" "github.com/sirupsen/logrus" "github.com/urfave/cli/v3" ) @@ -69,6 +72,13 @@ func start(_ context.Context, cmd *cli.Command) error { relays, monitors, minBid, relayCheck = setupRelays(cmd) listenAddr = cmd.String(addrFlag.Name) ) + prometheusRegistry := prometheus.NewRegistry() + if err := prometheusRegistry.Register(collectors.NewGoCollector()); err != nil { + log.WithError(err).Error("Failed to register metrics for GoCollector") + } + if err := prometheusRegistry.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})); err != nil { + log.WithError(err).Error("Failed to register ProcessCollector") + } opts := server.BoostServiceOpts{ Log: log, @@ -83,6 +93,8 @@ func start(_ context.Context, cmd *cli.Command) error { RequestTimeoutGetPayload: time.Duration(cmd.Int(timeoutGetPayloadFlag.Name)) * time.Millisecond, RequestTimeoutRegVal: time.Duration(cmd.Int(timeoutRegValFlag.Name)) * time.Millisecond, RequestMaxRetries: int(cmd.Int(maxRetriesFlag.Name)), + PrometheusListenAddr: int(cmd.Int(prometheusListenAddr.Name)), + PrometheusRegistry: prometheusRegistry, } service, err := server.NewBoostService(opts) if err != nil { @@ -93,6 +105,15 @@ func start(_ context.Context, cmd *cli.Command) error { log.Error("no relay passed the health-check!") } + if opts.PrometheusListenAddr > 0 && opts.PrometheusListenAddr <= math.MaxUint16 { + go func() { + log.Infof("Metric Server Listening on %d", opts.PrometheusListenAddr) + if err := service.StartMetricsServer(); err != nil { + log.WithError(err).Error("metrics server exited with error") + } + }() + } + log.Infof("Listening on %v", listenAddr) return service.StartHTTPServer() } diff --git a/go.mod b/go.mod index 2f75331b..e53f799e 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/holiman/uint256 v1.3.1 + github.com/prometheus/client_golang v1.16.0 github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 @@ -44,7 +45,6 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect diff --git a/server/service.go b/server/service.go index bdfc929e..e20bece8 100644 --- a/server/service.go +++ b/server/service.go @@ -27,6 +27,8 @@ import ( "github.com/flashbots/mev-boost/server/types" "github.com/google/uuid" "github.com/gorilla/mux" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" ) @@ -37,6 +39,7 @@ var ( errInvalidPubkey = errors.New("invalid pubkey") errNoSuccessfulRelayResponse = errors.New("no successful relay response") errServerAlreadyRunning = errors.New("server already running") + errNilPrometheusRegistry = errors.New("nil prometheus registry") ) var ( @@ -69,6 +72,8 @@ type BoostServiceOpts struct { RequestTimeoutGetPayload time.Duration RequestTimeoutRegVal time.Duration RequestMaxRetries int + PrometheusListenAddr int + PrometheusRegistry *prometheus.Registry } // BoostService - the mev-boost service @@ -93,6 +98,9 @@ type BoostService struct { slotUID *slotUID slotUIDLock sync.Mutex + + prometheusListenAddr int + prometheusRegistry *prometheus.Registry } // NewBoostService created a new BoostService @@ -130,7 +138,9 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) { Timeout: opts.RequestTimeoutRegVal, CheckRedirect: httpClientDisallowRedirects, }, - requestMaxRetries: opts.RequestMaxRetries, + requestMaxRetries: opts.RequestMaxRetries, + prometheusListenAddr: opts.PrometheusListenAddr, + prometheusRegistry: opts.PrometheusRegistry, }, nil } @@ -194,6 +204,22 @@ func (m *BoostService) StartHTTPServer() error { return err } +// StartMetricsServer starts the HTTP server for exporting open-metrics +func (m *BoostService) StartMetricsServer() error { + if m.prometheusRegistry == nil { + return errNilPrometheusRegistry + } + serveMux := http.NewServeMux() + serveMux.Handle("/metrics", promhttp.HandlerFor(m.prometheusRegistry, promhttp.HandlerOpts{ + ErrorLog: m.log, + EnableOpenMetrics: true, + })) + return http.ListenAndServe( + fmt.Sprintf(":%d", m.prometheusListenAddr), + serveMux, + ) +} + func (m *BoostService) startBidCacheCleanupTask() { for { time.Sleep(1 * time.Minute) From a3b36290dc45b5265367ed47fc5bee9d1ab62060 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 31 Jan 2025 13:30:56 -0600 Subject: [PATCH 2/5] Fix mistakes from merge --- go.mod | 7 ++++++- go.sum | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 42447037..2dfc39f3 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/holiman/uint256 v1.3.2 - github.com/prometheus/client_golang v1.16.0 + github.com/prometheus/client_golang v1.16.0 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 @@ -17,7 +17,9 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect @@ -28,8 +30,10 @@ require ( github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/goccy/go-yaml v1.11.3 // indirect github.com/gofrs/flock v0.8.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect @@ -38,6 +42,7 @@ require ( github.com/supranational/blst v0.3.13 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/protobuf v1.34.2 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index fa44e0fe..828fa9bb 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/attestantio/go-eth2-client v0.22.1-0.20250106164842-07b6ce39bb43 h1:l github.com/attestantio/go-eth2-client v0.22.1-0.20250106164842-07b6ce39bb43/go.mod h1:vy5jU/uDZ2+RcVzq5BfnG+bQ3/6uu9DGwCrGsPtjJ1A= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -56,6 +58,10 @@ github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -96,6 +102,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -110,6 +118,14 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= @@ -151,6 +167,7 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -175,6 +192,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From e4e6b62dd7578d96738865f2162492aa62c057dd Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 31 Jan 2025 13:33:28 -0600 Subject: [PATCH 3/5] Rename PrometheusListenAddr to PrometheusPort --- cli/flags.go | 4 ++-- cli/main.go | 6 +++--- server/service.go | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cli/flags.go b/cli/flags.go index f976da48..8ffc9623 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -34,7 +34,7 @@ var flags = []cli.Flag{ timeoutGetPayloadFlag, timeoutRegValFlag, maxRetriesFlag, - prometheusListenAddr, + prometheusPort, } var ( @@ -84,7 +84,7 @@ var ( Usage: "disables adding the version to every log entry", Category: LoggingCategory, } - prometheusListenAddr = &cli.IntFlag{ + prometheusPort = &cli.IntFlag{ Name: "prometheus-port", Sources: cli.EnvVars("PROMETHEUS_PORT"), Usage: "when set to a valid http port, will export runtime metrics to a prometheus server on that port", diff --git a/cli/main.go b/cli/main.go index f427eb46..eb5cc74d 100644 --- a/cli/main.go +++ b/cli/main.go @@ -93,7 +93,7 @@ func start(_ context.Context, cmd *cli.Command) error { RequestTimeoutGetPayload: time.Duration(cmd.Int(timeoutGetPayloadFlag.Name)) * time.Millisecond, RequestTimeoutRegVal: time.Duration(cmd.Int(timeoutRegValFlag.Name)) * time.Millisecond, RequestMaxRetries: int(cmd.Int(maxRetriesFlag.Name)), - PrometheusListenAddr: int(cmd.Int(prometheusListenAddr.Name)), + PrometheusPort: int(cmd.Int(prometheusPort.Name)), PrometheusRegistry: prometheusRegistry, } service, err := server.NewBoostService(opts) @@ -105,9 +105,9 @@ func start(_ context.Context, cmd *cli.Command) error { log.Error("no relay passed the health-check!") } - if opts.PrometheusListenAddr > 0 && opts.PrometheusListenAddr <= math.MaxUint16 { + if opts.PrometheusPort > 0 && opts.PrometheusPort <= math.MaxUint16 { go func() { - log.Infof("Metric Server Listening on %d", opts.PrometheusListenAddr) + log.Infof("Metric Server Listening on %d", opts.PrometheusPort) if err := service.StartMetricsServer(); err != nil { log.WithError(err).Error("metrics server exited with error") } diff --git a/server/service.go b/server/service.go index d8c0ca16..52081f30 100644 --- a/server/service.go +++ b/server/service.go @@ -72,7 +72,7 @@ type BoostServiceOpts struct { RequestTimeoutGetPayload time.Duration RequestTimeoutRegVal time.Duration RequestMaxRetries int - PrometheusListenAddr int + PrometheusPort int PrometheusRegistry *prometheus.Registry } @@ -99,8 +99,8 @@ type BoostService struct { slotUID *slotUID slotUIDLock sync.Mutex - prometheusListenAddr int - prometheusRegistry *prometheus.Registry + prometheusPort int + prometheusRegistry *prometheus.Registry } // NewBoostService created a new BoostService @@ -138,9 +138,9 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) { Timeout: opts.RequestTimeoutRegVal, CheckRedirect: httpClientDisallowRedirects, }, - requestMaxRetries: opts.RequestMaxRetries, - prometheusListenAddr: opts.PrometheusListenAddr, - prometheusRegistry: opts.PrometheusRegistry, + requestMaxRetries: opts.RequestMaxRetries, + prometheusPort: opts.PrometheusPort, + prometheusRegistry: opts.PrometheusRegistry, }, nil } @@ -215,7 +215,7 @@ func (m *BoostService) StartMetricsServer() error { EnableOpenMetrics: true, })) return http.ListenAndServe( - fmt.Sprintf(":%d", m.prometheusListenAddr), + fmt.Sprintf(":%d", m.prometheusPort), serveMux, ) } From e299c50391fd65051bca0df4ec17fd25ebf51e85 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 31 Jan 2025 13:39:41 -0600 Subject: [PATCH 4/5] Fix various nits --- README.md | 10 ++++++---- cli/main.go | 8 ++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 77e3ed1f..146a84b7 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,8 @@ Usage of mev-boost: add a 'service=...' tag to all log messages -loglevel string minimum loglevel: trace, debug, info, warn/warning, error, fatal, panic (default "info") + -prometheus-port int + when set to a valid http port, will export runtime metrics to a prometheus server on that port -mainnet use Mainnet (default true) -min-bid float @@ -313,6 +315,10 @@ Example for setting a minimum bid value of 0.06 ETH: -relay $YOUR_RELAY_CHOICE_C ``` +### Enabling metrics + +Optionally, the `-prometheus-port=` flag can be provided to expose prometheus metrics on specified port. + --- # API @@ -345,10 +351,6 @@ sequenceDiagram mev_boost-->>consensus: submitBlindedBlock response ``` -# Metrics - -Optionally the `-prometheus-port=9000` flag can be passed to expose prometheus metrics on specified port - # Maintainers - [@metachris](https://github.com/metachris) diff --git a/cli/main.go b/cli/main.go index eb5cc74d..045d1fca 100644 --- a/cli/main.go +++ b/cli/main.go @@ -74,10 +74,10 @@ func start(_ context.Context, cmd *cli.Command) error { ) prometheusRegistry := prometheus.NewRegistry() if err := prometheusRegistry.Register(collectors.NewGoCollector()); err != nil { - log.WithError(err).Error("Failed to register metrics for GoCollector") + log.WithError(err).Error("failed to register metrics for GoCollector") } if err := prometheusRegistry.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})); err != nil { - log.WithError(err).Error("Failed to register ProcessCollector") + log.WithError(err).Error("failed to register ProcessCollector") } opts := server.BoostServiceOpts{ @@ -107,7 +107,7 @@ func start(_ context.Context, cmd *cli.Command) error { if opts.PrometheusPort > 0 && opts.PrometheusPort <= math.MaxUint16 { go func() { - log.Infof("Metric Server Listening on %d", opts.PrometheusPort) + log.Infof("metrics server listening on %d", opts.PrometheusPort) if err := service.StartMetricsServer(); err != nil { log.WithError(err).Error("metrics server exited with error") } @@ -167,7 +167,7 @@ func setupRelays(cmd *cli.Command) (relayList, relayMonitorList, types.U256Str, log.WithError(err).Fatal("Failed sanitizing min bid") } if relayMinBidWei.BigInt().Sign() > 0 { - log.Infof("Min bid set to %v eth (%v wei)", cmd.Float(minBidFlag.Name), relayMinBidWei) + log.Infof("min bid set to %v eth (%v wei)", cmd.Float(minBidFlag.Name), relayMinBidWei) } return relays, monitors, *relayMinBidWei, cmd.Bool(relayCheckFlag.Name) } From dafa84c614c8b28b9427dd0332a9c18265b0e7f8 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 31 Jan 2025 14:20:29 -0600 Subject: [PATCH 5/5] Split into two flags & rename to "metrics" --- README.md | 8 +++++--- cli/flags.go | 18 +++++++++++++----- cli/main.go | 21 ++++++--------------- server/service.go | 30 +++++++++++++++--------------- 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 146a84b7..66324795 100644 --- a/README.md +++ b/README.md @@ -250,8 +250,10 @@ Usage of mev-boost: add a 'service=...' tag to all log messages -loglevel string minimum loglevel: trace, debug, info, warn/warning, error, fatal, panic (default "info") - -prometheus-port int - when set to a valid http port, will export runtime metrics to a prometheus server on that port + -metrics + enables a metrics server (default: false) + -metrics-addr string + listening address for the metrics server (default: "localhost:18551") -mainnet use Mainnet (default true) -min-bid float @@ -317,7 +319,7 @@ Example for setting a minimum bid value of 0.06 ETH: ### Enabling metrics -Optionally, the `-prometheus-port=` flag can be provided to expose prometheus metrics on specified port. +Optionally, the `-metrics` flag can be provided to expose a prometheus metrics server. The metrics server address/port can be changed with the `-metrics-addr` (e.g., `-metrics-addr localhost:9009`) flag. --- diff --git a/cli/flags.go b/cli/flags.go index 8ffc9623..e70fd448 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -34,7 +34,8 @@ var flags = []cli.Flag{ timeoutGetPayloadFlag, timeoutRegValFlag, maxRetriesFlag, - prometheusPort, + metricsFlag, + metricsAddrFlag, } var ( @@ -84,10 +85,17 @@ var ( Usage: "disables adding the version to every log entry", Category: LoggingCategory, } - prometheusPort = &cli.IntFlag{ - Name: "prometheus-port", - Sources: cli.EnvVars("PROMETHEUS_PORT"), - Usage: "when set to a valid http port, will export runtime metrics to a prometheus server on that port", + metricsFlag = &cli.BoolFlag{ + Name: "metrics", + Sources: cli.EnvVars("METRICS_ENABLED"), + Usage: "enables a metrics server", + Category: LoggingCategory, + } + metricsAddrFlag = &cli.StringFlag{ + Name: "metrics-addr", + Sources: cli.EnvVars("METRICS_ADDR"), + Value: "localhost:18551", + Usage: "listening address for the metrics server", Category: LoggingCategory, } // Genesis Flags diff --git a/cli/main.go b/cli/main.go index 045d1fca..efcfe88e 100644 --- a/cli/main.go +++ b/cli/main.go @@ -5,7 +5,6 @@ import ( "errors" "flag" "fmt" - "math" "os" "strings" "time" @@ -14,8 +13,6 @@ import ( "github.com/flashbots/mev-boost/common" "github.com/flashbots/mev-boost/config" "github.com/flashbots/mev-boost/server" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" "github.com/sirupsen/logrus" "github.com/urfave/cli/v3" ) @@ -71,14 +68,9 @@ func start(_ context.Context, cmd *cli.Command) error { genesisForkVersion, genesisTime = setupGenesis(cmd) relays, monitors, minBid, relayCheck = setupRelays(cmd) listenAddr = cmd.String(addrFlag.Name) + metricsEnabled = cmd.Bool(metricsFlag.Name) + metricsAddr = cmd.String(metricsAddrFlag.Name) ) - prometheusRegistry := prometheus.NewRegistry() - if err := prometheusRegistry.Register(collectors.NewGoCollector()); err != nil { - log.WithError(err).Error("failed to register metrics for GoCollector") - } - if err := prometheusRegistry.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})); err != nil { - log.WithError(err).Error("failed to register ProcessCollector") - } opts := server.BoostServiceOpts{ Log: log, @@ -93,8 +85,7 @@ func start(_ context.Context, cmd *cli.Command) error { RequestTimeoutGetPayload: time.Duration(cmd.Int(timeoutGetPayloadFlag.Name)) * time.Millisecond, RequestTimeoutRegVal: time.Duration(cmd.Int(timeoutRegValFlag.Name)) * time.Millisecond, RequestMaxRetries: int(cmd.Int(maxRetriesFlag.Name)), - PrometheusPort: int(cmd.Int(prometheusPort.Name)), - PrometheusRegistry: prometheusRegistry, + MetricsAddr: metricsAddr, } service, err := server.NewBoostService(opts) if err != nil { @@ -105,16 +96,16 @@ func start(_ context.Context, cmd *cli.Command) error { log.Error("no relay passed the health-check!") } - if opts.PrometheusPort > 0 && opts.PrometheusPort <= math.MaxUint16 { + if metricsEnabled { go func() { - log.Infof("metrics server listening on %d", opts.PrometheusPort) + log.Infof("metrics server listening on %v", opts.MetricsAddr) if err := service.StartMetricsServer(); err != nil { log.WithError(err).Error("metrics server exited with error") } }() } - log.Infof("Listening on %v", listenAddr) + log.Infof("listening on %v", listenAddr) return service.StartHTTPServer() } diff --git a/server/service.go b/server/service.go index 52081f30..de31602a 100644 --- a/server/service.go +++ b/server/service.go @@ -28,6 +28,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" ) @@ -39,7 +40,6 @@ var ( errInvalidPubkey = errors.New("invalid pubkey") errNoSuccessfulRelayResponse = errors.New("no successful relay response") errServerAlreadyRunning = errors.New("server already running") - errNilPrometheusRegistry = errors.New("nil prometheus registry") ) var ( @@ -72,8 +72,8 @@ type BoostServiceOpts struct { RequestTimeoutGetPayload time.Duration RequestTimeoutRegVal time.Duration RequestMaxRetries int - PrometheusPort int - PrometheusRegistry *prometheus.Registry + + MetricsAddr string } // BoostService - the mev-boost service @@ -99,8 +99,7 @@ type BoostService struct { slotUID *slotUID slotUIDLock sync.Mutex - prometheusPort int - prometheusRegistry *prometheus.Registry + metricsAddr string } // NewBoostService created a new BoostService @@ -138,9 +137,8 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) { Timeout: opts.RequestTimeoutRegVal, CheckRedirect: httpClientDisallowRedirects, }, - requestMaxRetries: opts.RequestMaxRetries, - prometheusPort: opts.PrometheusPort, - prometheusRegistry: opts.PrometheusRegistry, + requestMaxRetries: opts.RequestMaxRetries, + metricsAddr: opts.MetricsAddr, }, nil } @@ -206,18 +204,20 @@ func (m *BoostService) StartHTTPServer() error { // StartMetricsServer starts the HTTP server for exporting open-metrics func (m *BoostService) StartMetricsServer() error { - if m.prometheusRegistry == nil { - return errNilPrometheusRegistry + prometheusRegistry := prometheus.NewRegistry() + if err := prometheusRegistry.Register(collectors.NewGoCollector()); err != nil { + m.log.WithError(err).Error("failed to register metrics for GoCollector") + } + if err := prometheusRegistry.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})); err != nil { + m.log.WithError(err).Error("failed to register ProcessCollector") } + serveMux := http.NewServeMux() - serveMux.Handle("/metrics", promhttp.HandlerFor(m.prometheusRegistry, promhttp.HandlerOpts{ + serveMux.Handle("/metrics", promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{ ErrorLog: m.log, EnableOpenMetrics: true, })) - return http.ListenAndServe( - fmt.Sprintf(":%d", m.prometheusPort), - serveMux, - ) + return http.ListenAndServe(m.metricsAddr, serveMux) } func (m *BoostService) startBidCacheCleanupTask() {