feat(scripts/develop): enable prometheus metrics by default (#24389)

- Adds `--prometheus-port` flag to develop.sh (default: 2114). Passes `--prometheus-enable=true` and `--prometheus-address=0.0.0.0:2114` to dev coderd.
- Show Prometheus URL in dev banner + group by service

> 🤖
This commit is contained in:
Cian Johnston
2026-04-17 13:06:10 +01:00
committed by GitHub
parent 4ba74dcdc8
commit a23a38c1f3
2 changed files with 156 additions and 20 deletions
+80 -12
View File
@@ -42,6 +42,9 @@ const (
defaultAPIPort = "3000"
defaultWebPort = "8080"
defaultProxyPort = "3010"
// defaultPrometheusPort avoids 2112 (agent prometheus) and
// 2113 (agent debug) already bound inside Coder workspaces.
defaultPrometheusPort = "2114"
defaultAccessURL = "http://127.0.0.1:%d"
defaultPassword = "SomeSecurePassword!"
defaultStarterTemplate = "docker"
@@ -77,6 +80,13 @@ func main() {
Description: "Workspace proxy port.",
Value: serpent.Int64Of(&cfg.proxyPort),
},
{
Flag: "prometheus-port",
Env: "CODER_DEV_PROMETHEUS_PORT",
Default: defaultPrometheusPort,
Description: "Prometheus metrics port. Set to 0 to disable.",
Value: serpent.Int64Of(&cfg.prometheusPort),
},
{
Flag: "agpl",
Env: "CODER_BUILD_AGPL",
@@ -163,6 +173,7 @@ type devConfig struct {
apiPort int64
webPort int64
proxyPort int64
prometheusPort int64
agpl bool
accessURL string
password string
@@ -206,6 +217,9 @@ func (c *devConfig) validate() error {
return xerrors.Errorf("%s must be between 1 and 65535", p.name)
}
}
if c.prometheusPort < 0 || c.prometheusPort > 65535 {
return xerrors.Errorf("--prometheus-port must be 0 (disabled) or between 1 and 65535")
}
if c.apiPort == c.webPort {
return xerrors.Errorf("--port %d conflicts with frontend dev server", c.webPort)
}
@@ -215,6 +229,17 @@ func (c *devConfig) validate() error {
if c.useProxy && c.webPort == c.proxyPort {
return xerrors.Errorf("--web-port %d conflicts with --proxy-port", c.webPort)
}
if c.prometheusPort != 0 {
if c.prometheusPort == c.apiPort {
return xerrors.Errorf("--prometheus-port %d conflicts with API server", c.prometheusPort)
}
if c.prometheusPort == c.webPort {
return xerrors.Errorf("--prometheus-port %d conflicts with frontend dev server", c.prometheusPort)
}
if c.useProxy && c.prometheusPort == c.proxyPort {
return xerrors.Errorf("--prometheus-port %d conflicts with workspace proxy", c.prometheusPort)
}
}
return nil
}
@@ -481,6 +506,9 @@ func preflight(ctx context.Context, logger slog.Logger, cfg *devConfig) error {
if cfg.useProxy && isPortBusy(ctx, cfg.proxyPort) {
return xerrors.Errorf("port %d is already in use (proxy)", cfg.proxyPort)
}
if cfg.prometheusPort != 0 && isPortBusy(ctx, cfg.prometheusPort) {
return xerrors.Errorf("port %d is already in use (prometheus)", cfg.prometheusPort)
}
return nil
}
@@ -513,6 +541,14 @@ func startServer(cfg *devConfig, group *procGroup) error {
"--dangerous-allow-cors-requests=true",
"--enable-terraform-debug-mode",
}
if cfg.prometheusPort != 0 {
serverArgs = append(serverArgs,
"--prometheus-enable",
"--prometheus-address", fmt.Sprintf("0.0.0.0:%d", cfg.prometheusPort),
"--prometheus-collect-agent-stats",
"--prometheus-collect-db-metrics",
)
}
serverArgs = append(serverArgs, cfg.serverExtraArgs...)
if cfg.debug {
@@ -885,28 +921,60 @@ func printBanner(ctx context.Context, logger slog.Logger, cfg *devConfig) {
}
var b strings.Builder
w := 64
line := func(content string) {
_, _ = fmt.Fprintf(&b, "║ %-*s ║\n", w, content)
line := func(content ...string) {
for _, c := range content {
_, _ = fmt.Fprintf(&b, "║ %-*s ║\n", w, c)
}
}
indent := func(s string) string {
return " " + s
}
divider := "╔" + strings.Repeat("═", w+2) + "╗"
bottom := "╚" + strings.Repeat("═", w+2) + "╝"
_, _ = fmt.Fprintln(&b)
_, _ = fmt.Fprintln(&b, divider)
line("")
line(" Coder is now running in development mode.")
line("")
line(
"",
indent("Coder is now running in development mode."),
"",
"API:",
)
for _, h := range ifaces {
line(fmt.Sprintf("API: http://%s:%d", h, cfg.apiPort))
line(fmt.Sprintf("Web UI: http://%s:%d", h, cfg.webPort))
line(indent(fmt.Sprintf("http://%s:%d", h, cfg.apiPort)))
}
line(
"",
"Web UI:",
)
for _, h := range ifaces {
line(indent(fmt.Sprintf("http://%s:%d", h, cfg.webPort)))
}
if cfg.useProxy {
line(fmt.Sprintf("Proxy: http://%s:%d", h, cfg.proxyPort))
line(
"",
"Proxy:",
)
for _, h := range ifaces {
line(indent(fmt.Sprintf("http://%s:%d", h, cfg.proxyPort)))
}
}
line("")
line("Use ./scripts/coder-dev.sh to talk to this instance!")
line(fmt.Sprintf(" alias cdr=%s/scripts/coder-dev.sh", cfg.projectRoot))
line("")
if cfg.prometheusPort != 0 {
line(
"",
"Metrics:",
)
for _, h := range ifaces {
line(indent(fmt.Sprintf("http://%s:%d", h, cfg.prometheusPort)))
}
}
line(
"",
"Use ./scripts/coder-dev.sh to talk to this instance!",
fmt.Sprintf(" alias cdr=%s/scripts/coder-dev.sh", cfg.projectRoot),
"",
)
_, _ = fmt.Fprintln(&b, bottom)
logger.Info(ctx, b.String())
}
+68
View File
@@ -174,6 +174,7 @@ func TestDevConfigValidate(t *testing.T) {
apiPort: 3000,
webPort: 8080,
proxyPort: 3010,
prometheusPort: 2114,
password: defaultPassword,
}
}
@@ -283,6 +284,73 @@ func TestDevConfigValidate(t *testing.T) {
cfg.proxyPort = 9000
assert.NoError(t, cfg.validate())
})
t.Run("PrometheusPortConflictWithAPI", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 3000
err := cfg.validate()
require.Error(t, err)
assert.Contains(t, err.Error(), "--prometheus-port 3000 conflicts with")
})
t.Run("PrometheusPortConflictWithWeb", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 8080
err := cfg.validate()
require.Error(t, err)
assert.Contains(t, err.Error(), "--prometheus-port 8080 conflicts with")
})
t.Run("PrometheusPortConflictWithProxy", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 3010
cfg.useProxy = true
err := cfg.validate()
require.Error(t, err)
assert.Contains(t, err.Error(), "--prometheus-port 3010 conflicts with")
})
t.Run("PrometheusPortZeroDisabled", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 0
assert.NoError(t, cfg.validate())
})
t.Run("PrometheusPortValid", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 9090
assert.NoError(t, cfg.validate())
})
t.Run("PrometheusPortTooHigh", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 70000
err := cfg.validate()
require.Error(t, err)
assert.Contains(t, err.Error(), "--prometheus-port must be 0 (disabled) or between 1 and 65535")
})
t.Run("PrometheusPortNegative", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = -1
err := cfg.validate()
require.Error(t, err)
assert.Contains(t, err.Error(), "--prometheus-port must be 0 (disabled) or between 1 and 65535")
})
t.Run("PrometheusProxyProxyConflictIgnoredWithoutProxy", func(t *testing.T) {
t.Parallel()
cfg := base()
cfg.prometheusPort = 3010
assert.NoError(t, cfg.validate())
})
}
func TestDevConfigResolveEnv(t *testing.T) {