diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go
index 4c3ede362e..a9b3fd8ed9 100644
--- a/cmd/prometheus/main.go
+++ b/cmd/prometheus/main.go
@@ -352,7 +352,7 @@ func main() {
a.Flag("config.auto-reload-interval", "Specifies the interval for checking and automatically reloading the Prometheus configuration file upon detecting changes.").
Default("30s").SetValue(&cfg.autoReloadInterval)
- a.Flag("web.listen-address", "Address to listen on for UI, API, and telemetry. Can be repeated.").
+ a.Flag("web.listen-address", "Address or UNIX domain socket path (prefixed with `unix://`) to listen on for UI, API, and telemetry. Can be repeated.").
Default("0.0.0.0:9090").StringsVar(&cfg.web.ListenAddresses)
a.Flag("auto-gomaxprocs", "Automatically set GOMAXPROCS to match Linux container CPU quota").
diff --git a/cmd/prometheus/main_test.go b/cmd/prometheus/main_test.go
index 0d0ab56eb4..f70b19c3d0 100644
--- a/cmd/prometheus/main_test.go
+++ b/cmd/prometheus/main_test.go
@@ -431,6 +431,50 @@ func TestAgentSuccessfulStartup(t *testing.T) {
require.Equal(t, 0, actualExitStatus)
}
+func TestSuccessfulStartupWithUnixSocket(t *testing.T) {
+ socket := "prometheus-test.sock"
+
+ prom := exec.Command(promPath, "-test.main", "--web.listen-address=unix://"+socket, "--config.file="+promConfig)
+ require.NoError(t, prom.Start())
+
+ actualExitStatus := 0
+ done := make(chan error, 1)
+
+ go func() { done <- prom.Wait() }()
+ select {
+ case err := <-done:
+ out, outerr := prom.Output()
+ t.Logf("prometheus should be still running: %v %v %v", err, out, outerr)
+ actualExitStatus = prom.ProcessState.ExitCode()
+ case <-time.After(startupTime):
+ prom.Process.Kill()
+ }
+ os.Remove(socket)
+ require.Equal(t, 0, actualExitStatus)
+}
+
+func TestSuccessfulStartupWithUnixSocketAndExternalUrl(t *testing.T) {
+ socket := "prometheus-test.sock"
+
+ prom := exec.Command(promPath, "-test.main", "--web.external-url=https://example.com", "--web.listen-address=unix://"+socket, "--config.file="+promConfig)
+ require.NoError(t, prom.Start())
+
+ actualExitStatus := 0
+ done := make(chan error, 1)
+
+ go func() { done <- prom.Wait() }()
+ select {
+ case err := <-done:
+ out, outerr := prom.Output()
+ t.Logf("prometheus should be still running: %v %v %v", err, out, outerr)
+ actualExitStatus = prom.ProcessState.ExitCode()
+ case <-time.After(startupTime):
+ prom.Process.Kill()
+ }
+ os.Remove(socket)
+ require.Equal(t, 0, actualExitStatus)
+}
+
func TestAgentFailedStartupWithServerFlag(t *testing.T) {
t.Parallel()
diff --git a/docs/command-line/prometheus.md b/docs/command-line/prometheus.md
index ebd6007f7b..8a69fc94af 100644
--- a/docs/command-line/prometheus.md
+++ b/docs/command-line/prometheus.md
@@ -16,7 +16,7 @@ The Prometheus monitoring server
| --version
| Show application version. | |
| --config.file
| Prometheus configuration file path. | `prometheus.yml` |
| --config.auto-reload-interval
| Specifies the interval for checking and automatically reloading the Prometheus configuration file upon detecting changes. | `30s` |
-| --web.listen-address
... | Address to listen on for UI, API, and telemetry. Can be repeated. | `0.0.0.0:9090` |
+| --web.listen-address
... | Address or UNIX domain socket path (prefixed with `unix://`) to listen on for UI, API, and telemetry. Can be repeated. | `0.0.0.0:9090` |
| --auto-gomaxprocs
| Automatically set GOMAXPROCS to match Linux container CPU quota | `true` |
| --auto-gomemlimit
| Automatically set GOMEMLIMIT to match Linux container or system memory limit | `true` |
| --auto-gomemlimit.ratio
| The ratio of reserved GOMEMLIMIT memory to the detected maximum container or system memory | `0.9` |
diff --git a/web/web.go b/web/web.go
index 84c4a2a529..55c3b54764 100644
--- a/web/web.go
+++ b/web/web.go
@@ -651,11 +651,20 @@ func (h *Handler) Listeners() ([]net.Listener, error) {
return listeners, nil
}
+// tcpOrUnixDomainSocket returns either TCP/IP or UNIX domain binding information.
+func tcpOrUnixDomainSocket(address string) (string, string) {
+ if strings.HasPrefix(address, "unix://") {
+ return "unix", strings.Replace(address, "unix://", "", 1)
+ }
+
+ return "tcp", address
+}
+
// Listener creates the TCP listener for web requests.
func (h *Handler) Listener(address string, sem chan struct{}) (net.Listener, error) {
h.logger.Info("Start listening for connections", "address", address)
- listener, err := net.Listen("tcp", address)
+ listener, err := net.Listen(tcpOrUnixDomainSocket(address))
if err != nil {
return listener, err
}