From 80ecd27ddfcae2c1e60c5803bc516c26b27dad13 Mon Sep 17 00:00:00 2001 From: Rob Holland Date: Thu, 7 Jul 2022 21:17:18 +0100 Subject: [PATCH] Add --metrics-port flag. (#87) * Add --metrics-port flag. Metrics listeners on a random port is unlikely to be useful. * Bind to frontend IP for metrics so they can be scraped. --- cmd/temporalite/main.go | 36 +++++++++++++++++++++-------------- internal/liteconfig/config.go | 31 ++++++++++++++++++------------ options.go | 9 +++++++++ 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/cmd/temporalite/main.go b/cmd/temporalite/main.go index 2da2fa0d..f643568c 100644 --- a/cmd/temporalite/main.go +++ b/cmd/temporalite/main.go @@ -35,17 +35,18 @@ var ( ) const ( - ephemeralFlag = "ephemeral" - dbPathFlag = "filename" - portFlag = "port" - uiPortFlag = "ui-port" - headlessFlag = "headless" - ipFlag = "ip" - logFormatFlag = "log-format" - logLevelFlag = "log-level" - namespaceFlag = "namespace" - pragmaFlag = "sqlite-pragma" - configFlag = "config" + ephemeralFlag = "ephemeral" + dbPathFlag = "filename" + portFlag = "port" + metricsPortFlag = "metrics-port" + uiPortFlag = "ui-port" + headlessFlag = "headless" + ipFlag = "ip" + logFormatFlag = "log-format" + logLevelFlag = "log-level" + namespaceFlag = "namespace" + pragmaFlag = "sqlite-pragma" + configFlag = "config" ) func init() { @@ -93,6 +94,11 @@ func buildCLI() *cli.App { Usage: "port for the temporal-frontend GRPC service", Value: liteconfig.DefaultFrontendPort, }, + &cli.IntFlag{ + Name: metricsPortFlag, + Usage: "port for the metrics listener", + Value: liteconfig.DefaultMetricsPort, + }, &cli.IntFlag{ Name: uiPortFlag, Usage: "port for the temporal web UI", @@ -171,9 +177,10 @@ func buildCLI() *cli.App { }, Action: func(c *cli.Context) error { var ( - ip = c.String(ipFlag) - serverPort = c.Int(portFlag) - uiPort = serverPort + 1000 + ip = c.String(ipFlag) + serverPort = c.Int(portFlag) + metricsPort = c.Int(metricsPortFlag) + uiPort = serverPort + 1000 ) if c.IsSet(uiPortFlag) { @@ -196,6 +203,7 @@ func buildCLI() *cli.App { opts := []temporalite.ServerOption{ temporalite.WithDynamicPorts(), temporalite.WithFrontendPort(serverPort), + temporalite.WithMetricsPort(metricsPort), temporalite.WithFrontendIP(ip), temporalite.WithDatabaseFilePath(c.String(dbPathFlag)), temporalite.WithNamespaces(c.StringSlice(namespaceFlag)...), diff --git a/internal/liteconfig/config.go b/internal/liteconfig/config.go index d7c932fa..42753ffd 100644 --- a/internal/liteconfig/config.go +++ b/internal/liteconfig/config.go @@ -24,6 +24,7 @@ const ( broadcastAddress = "127.0.0.1" PersistenceStoreName = "sqlite-default" DefaultFrontendPort = 7233 + DefaultMetricsPort = 0 ) // UIServer abstracts the github.com/temporalio/ui-server project to @@ -48,6 +49,7 @@ type Config struct { Ephemeral bool DatabaseFilePath string FrontendPort int + MetricsPort int DynamicPorts bool Namespaces []string SQLitePragmas map[string]string @@ -83,6 +85,7 @@ func NewDefaultConfig() (*Config, error) { Ephemeral: false, DatabaseFilePath: filepath.Join(userConfigDir, "temporalite/db/default.db"), FrontendPort: 0, + MetricsPort: 0, UIServer: noopUIServer{}, DynamicPorts: false, Namespaces: nil, @@ -122,18 +125,22 @@ func Convert(cfg *Config) *config.Config { sqliteConfig.ConnectAttributes["_"+k] = v } - var metricsPort, pprofPort int + var pprofPort int if cfg.DynamicPorts { if cfg.FrontendPort == 0 { cfg.FrontendPort = cfg.portProvider.mustGetFreePort() } - metricsPort = cfg.portProvider.mustGetFreePort() + if cfg.MetricsPort == 0 { + cfg.MetricsPort = cfg.portProvider.mustGetFreePort() + } pprofPort = cfg.portProvider.mustGetFreePort() } else { if cfg.FrontendPort == 0 { cfg.FrontendPort = DefaultFrontendPort } - metricsPort = cfg.FrontendPort + 200 + if cfg.MetricsPort == 0 { + cfg.MetricsPort = cfg.FrontendPort + 200 + } pprofPort = cfg.FrontendPort + 201 } @@ -144,7 +151,7 @@ func Convert(cfg *Config) *config.Config { } baseConfig.Global.Metrics = &metrics.Config{ Prometheus: &metrics.PrometheusConfig{ - ListenAddress: fmt.Sprintf("%s:%d", broadcastAddress, metricsPort), + ListenAddress: fmt.Sprintf("%s:%d", cfg.FrontendIP, cfg.MetricsPort), HandlerPath: "/metrics", }, } @@ -207,28 +214,28 @@ func Convert(cfg *Config) *config.Config { return baseConfig } -func (o *Config) mustGetService(frontendPortOffset int) config.Service { +func (cfg *Config) mustGetService(frontendPortOffset int) config.Service { svc := config.Service{ RPC: config.RPC{ - GRPCPort: o.FrontendPort + frontendPortOffset, - MembershipPort: o.FrontendPort + 100 + frontendPortOffset, + GRPCPort: cfg.FrontendPort + frontendPortOffset, + MembershipPort: cfg.FrontendPort + 100 + frontendPortOffset, BindOnLocalHost: true, BindOnIP: "", }, } // Assign any open port when configured to use dynamic ports - if o.DynamicPorts { + if cfg.DynamicPorts { if frontendPortOffset != 0 { - svc.RPC.GRPCPort = o.portProvider.mustGetFreePort() + svc.RPC.GRPCPort = cfg.portProvider.mustGetFreePort() } - svc.RPC.MembershipPort = o.portProvider.mustGetFreePort() + svc.RPC.MembershipPort = cfg.portProvider.mustGetFreePort() } // Optionally bind frontend to IPv4 address - if frontendPortOffset == 0 && o.FrontendIP != "" { + if frontendPortOffset == 0 && cfg.FrontendIP != "" { svc.RPC.BindOnLocalHost = false - svc.RPC.BindOnIP = o.FrontendIP + svc.RPC.BindOnIP = cfg.FrontendIP } return svc diff --git a/options.go b/options.go index 3cdd6c99..0526daaf 100644 --- a/options.go +++ b/options.go @@ -57,6 +57,15 @@ func WithFrontendPort(port int) ServerOption { }) } +// WithMetricsPort sets the listening port for metrics. +// +// When unspecified, the port will be system-chosen. +func WithMetricsPort(port int) ServerOption { + return newApplyFuncContainer(func(cfg *liteconfig.Config) { + cfg.MetricsPort = port + }) +} + // WithFrontendIP binds the temporal-frontend GRPC service to a specific IP (eg. `0.0.0.0`) // Check net.ParseIP for supported syntax; only IPv4 is supported. //