cmd/geth: allow configuring metrics HTTP server on separate endpoint (#21290)
Exposing /debug/metrics and /debug/metrics/prometheus was dependent on --pprof, which also exposes other HTTP APIs. This change makes it possible to run the metrics server on an independent endpoint without enabling pprof.
This commit is contained in:
		
							parent
							
								
									61270e5e1c
								
							
						
					
					
						commit
						490b380a04
					
				| @ -85,6 +85,8 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to | ||||
| 			utils.CacheGCFlag, | ||||
| 			utils.MetricsEnabledFlag, | ||||
| 			utils.MetricsEnabledExpensiveFlag, | ||||
| 			utils.MetricsHTTPFlag, | ||||
| 			utils.MetricsPortFlag, | ||||
| 			utils.MetricsEnableInfluxDBFlag, | ||||
| 			utils.MetricsInfluxDBEndpointFlag, | ||||
| 			utils.MetricsInfluxDBDatabaseFlag, | ||||
|  | ||||
| @ -199,6 +199,8 @@ var ( | ||||
| 	metricsFlags = []cli.Flag{ | ||||
| 		utils.MetricsEnabledFlag, | ||||
| 		utils.MetricsEnabledExpensiveFlag, | ||||
| 		utils.MetricsHTTPFlag, | ||||
| 		utils.MetricsPortFlag, | ||||
| 		utils.MetricsEnableInfluxDBFlag, | ||||
| 		utils.MetricsInfluxDBEndpointFlag, | ||||
| 		utils.MetricsInfluxDBDatabaseFlag, | ||||
|  | ||||
| @ -51,6 +51,7 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/les" | ||||
| 	"github.com/ethereum/go-ethereum/log" | ||||
| 	"github.com/ethereum/go-ethereum/metrics" | ||||
| 	"github.com/ethereum/go-ethereum/metrics/exp" | ||||
| 	"github.com/ethereum/go-ethereum/metrics/influxdb" | ||||
| 	"github.com/ethereum/go-ethereum/miner" | ||||
| 	"github.com/ethereum/go-ethereum/node" | ||||
| @ -689,6 +690,21 @@ var ( | ||||
| 		Name:  "metrics.expensive", | ||||
| 		Usage: "Enable expensive metrics collection and reporting", | ||||
| 	} | ||||
| 
 | ||||
| 	// MetricsHTTPFlag defines the endpoint for a stand-alone metrics HTTP endpoint.
 | ||||
| 	// Since the pprof service enables sensitive/vulnerable behavior, this allows a user
 | ||||
| 	// to enable a public-OK metrics endpoint without having to worry about ALSO exposing
 | ||||
| 	// other profiling behavior or information.
 | ||||
| 	MetricsHTTPFlag = cli.StringFlag{ | ||||
| 		Name:  "metrics.addr", | ||||
| 		Usage: "Enable stand-alone metrics HTTP server listening interface", | ||||
| 		Value: "127.0.0.1", | ||||
| 	} | ||||
| 	MetricsPortFlag = cli.IntFlag{ | ||||
| 		Name:  "metrics.port", | ||||
| 		Usage: "Metrics HTTP server listening port", | ||||
| 		Value: 6060, | ||||
| 	} | ||||
| 	MetricsEnableInfluxDBFlag = cli.BoolFlag{ | ||||
| 		Name:  "metrics.influxdb", | ||||
| 		Usage: "Enable metrics export/push to an external InfluxDB database", | ||||
| @ -1734,6 +1750,7 @@ func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []st | ||||
| func SetupMetrics(ctx *cli.Context) { | ||||
| 	if metrics.Enabled { | ||||
| 		log.Info("Enabling metrics collection") | ||||
| 
 | ||||
| 		var ( | ||||
| 			enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) | ||||
| 			endpoint     = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) | ||||
| @ -1749,6 +1766,12 @@ func SetupMetrics(ctx *cli.Context) { | ||||
| 
 | ||||
| 			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) | ||||
| 		} | ||||
| 
 | ||||
| 		if ctx.GlobalIsSet(MetricsHTTPFlag.Name) { | ||||
| 			address := fmt.Sprintf("%s:%d", ctx.GlobalString(MetricsHTTPFlag.Name), ctx.GlobalInt(MetricsPortFlag.Name)) | ||||
| 			log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) | ||||
| 			exp.Setup(address) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -195,15 +195,19 @@ func Setup(ctx *cli.Context) error { | ||||
| 		} | ||||
| 
 | ||||
| 		address := fmt.Sprintf("%s:%d", listenHost, port) | ||||
| 		StartPProf(address) | ||||
| 		// This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name.
 | ||||
| 		// It cannot be imported because it will cause a cyclical dependency.
 | ||||
| 		StartPProf(address, !ctx.GlobalIsSet("metrics.addr")) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func StartPProf(address string) { | ||||
| func StartPProf(address string, withMetrics bool) { | ||||
| 	// Hook go-metrics into expvar on any /debug/metrics request, load all vars
 | ||||
| 	// from the registry into expvar, and execute regular expvar handler.
 | ||||
| 	if withMetrics { | ||||
| 		exp.Exp(metrics.DefaultRegistry) | ||||
| 	} | ||||
| 	http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) | ||||
| 	log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) | ||||
| 	go func() { | ||||
|  | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/log" | ||||
| 	"github.com/ethereum/go-ethereum/metrics" | ||||
| 	"github.com/ethereum/go-ethereum/metrics/prometheus" | ||||
| ) | ||||
| @ -52,6 +53,20 @@ func ExpHandler(r metrics.Registry) http.Handler { | ||||
| 	return http.HandlerFunc(e.expHandler) | ||||
| } | ||||
| 
 | ||||
| // Setup starts a dedicated metrics server at the given address.
 | ||||
| // This function enables metrics reporting separate from pprof.
 | ||||
| func Setup(address string) { | ||||
| 	m := http.NewServeMux() | ||||
| 	m.Handle("/debug/metrics", ExpHandler(metrics.DefaultRegistry)) | ||||
| 	m.Handle("/debug/metrics/prometheus", prometheus.Handler(metrics.DefaultRegistry)) | ||||
| 	log.Info("Starting metrics server", "addr", fmt.Sprintf("http://%s/debug/metrics", address)) | ||||
| 	go func() { | ||||
| 		if err := http.ListenAndServe(address, m); err != nil { | ||||
| 			log.Error("Failure in running metrics server", "err", err) | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
| 
 | ||||
| func (exp *exp) getInt(name string) *expvar.Int { | ||||
| 	var v *expvar.Int | ||||
| 	exp.expvarLock.Lock() | ||||
|  | ||||
| @ -113,7 +113,7 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { | ||||
| 	} | ||||
| 
 | ||||
| 	if config.PprofAddress != "" { | ||||
| 		debug.StartPProf(config.PprofAddress) | ||||
| 		debug.StartPProf(config.PprofAddress, true) | ||||
| 	} | ||||
| 
 | ||||
| 	// Create the empty networking stack
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user