From 001f768b8bcafd640dd69f72503c708a89ebac1c Mon Sep 17 00:00:00 2001 From: "m.nabokikh" Date: Wed, 30 Oct 2019 02:49:19 +0400 Subject: [PATCH] Add ability to scrape and listen unix domain sockets Signed-off-by: m.nabokikh --- exporter.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/exporter.go b/exporter.go index 30629da70..4afa6fa89 100644 --- a/exporter.go +++ b/exporter.go @@ -1,14 +1,17 @@ package main import ( + "context" "crypto/tls" "flag" "fmt" "log" + "net" "net/http" "os" "os/signal" "strconv" + "strings" "syscall" "time" @@ -110,6 +113,42 @@ func createClientWithRetries(getClient func() (interface{}, error), retries uint return nil, err } +func parseUnixSocketAddress(listenAddress string) (string, string, error) { + listenAddressParts := strings.Split(listenAddress, ":") + listenAddressPartsLength := len(listenAddressParts) + + if listenAddressPartsLength > 3 || listenAddressPartsLength < 1 { + return "", "", fmt.Errorf("address for unix domain socket has wrong format") + } + + unixSocketPath := listenAddressParts[1] + requestPath := "" + if listenAddressPartsLength == 2 { + requestPath = listenAddressParts[2] + } + return unixSocketPath, requestPath, nil +} + +func startListeningOn(listenAddress string) error { + if !strings.HasPrefix(listenAddress, "unix:") { + return http.ListenAndServe(listenAddress, nil) + } + path, _, err := parseUnixSocketAddress(listenAddress) + if err != nil { + log.Fatalf("parsing unix domain socket listen address %s failed: %+v", listenAddress, err) + } + listener, err := net.ListenUnix("unix", &net.UnixAddr{Name: path, Net: "unix"}) + if err != nil { + log.Fatalf("binding to unix domain socket listen address %s failed: %+v", path, err) + } + + err = os.Chmod(path, 0777) + if err != nil { + log.Printf("changing access rules of unix domain socket %s failed: %+v", path, err) + } + return http.Serve(listener, nil) +} + var ( // Set during go build version string @@ -177,11 +216,25 @@ func main() { registry.MustRegister(buildInfoMetric) + transport := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: !*sslVerify}, + } + if strings.HasPrefix(*scrapeURI, "unix:") { + socketPath, requestPath, err := parseUnixSocketAddress(*scrapeURI) + if err != nil { + log.Fatalf("parsing unix domain socket scrape address %s failed: %+v", *scrapeURI, err) + } + + transport.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", socketPath) + } + newScrapeURI := "http://unix" + requestPath + scrapeURI = &newScrapeURI + } + httpClient := &http.Client{ - Timeout: timeout.Duration, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: !*sslVerify}, - }, + Timeout: timeout.Duration, + Transport: transport, } signalChan := make(chan os.Signal, 1) @@ -222,5 +275,5 @@ func main() { } }) log.Printf("NGINX Prometheus Exporter has successfully started") - log.Fatal(http.ListenAndServe(*listenAddr, nil)) + log.Fatal(startListeningOn(*listenAddr)) }