diff --git a/go.mod b/go.mod index b099200..17b30c5 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/Lusitaniae/phpfpm_exporter go 1.16 require ( + github.com/kanocz/fcgi_client v0.0.0-20210113082628-fff85c8adfb7 github.com/prometheus/client_golang v1.10.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.27.0 - github.com/tomasen/fcgi_client v0.0.0-20180423082037-2bb3d819fd19 gopkg.in/alecthomas/kingpin.v2 v2.2.6 ) diff --git a/go.sum b/go.sum index a6553d8..6821c96 100644 --- a/go.sum +++ b/go.sum @@ -210,6 +210,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kanocz/fcgi_client v0.0.0-20210113082628-fff85c8adfb7 h1:W0fAsQ7bC1db4k9O2X6yZvatz/0c/ISyxhmNnc6arZA= +github.com/kanocz/fcgi_client v0.0.0-20210113082628-fff85c8adfb7/go.mod h1:dHpIS7C6YjFguh5vo9QBVEojDoL3vh3v6oEho2HtNyA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -331,8 +333,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomasen/fcgi_client v0.0.0-20180423082037-2bb3d819fd19 h1:ZCmSnT6CLGhfoQ2lPEhL4nsJstKDCw1F1RfN8/smTCU= -github.com/tomasen/fcgi_client v0.0.0-20180423082037-2bb3d819fd19/go.mod h1:SXTY+QvI+KTTKXQdg0zZ7nx0u94QWh8ZAwBQYsW9cqk= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/phpfpm_exporter.go b/phpfpm_exporter.go index 964ecbf..e3e66ee 100644 --- a/phpfpm_exporter.go +++ b/phpfpm_exporter.go @@ -28,12 +28,12 @@ import ( "path/filepath" + fcgiclient "github.com/kanocz/fcgi_client" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" client_model "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "github.com/prometheus/common/version" - "github.com/tomasen/fcgi_client" "gopkg.in/alecthomas/kingpin.v2" ) @@ -147,19 +147,23 @@ func CollectStatusFromReader(reader io.Reader, socketPath string, ch chan<- prom return nil } -func CollectStatusFromSocket(path *SocketPath, statusPath string, ch chan<- prometheus.Metric) error { +func CollectStatusFromSocket(path *SocketPath, statusPath string, connectTimeout time.Duration, operationTimeout time.Duration, ch chan<- prometheus.Metric) error { env := make(map[string]string) env["SCRIPT_FILENAME"] = statusPath env["SCRIPT_NAME"] = statusPath env["REQUEST_METHOD"] = "GET" - fcgi, err := fcgiclient.Dial(path.Network, path.Address) + fcgi, err := fcgiclient.DialTimeout(path.Network, path.Address, connectTimeout) if err != nil { return err } defer fcgi.Close() + if operationTimeout > 0 { + fcgi.SetTimeout(operationTimeout) + } + resp, err := fcgi.Get(env) if err != nil { return err @@ -168,17 +172,21 @@ func CollectStatusFromSocket(path *SocketPath, statusPath string, ch chan<- prom return CollectStatusFromReader(resp.Body, path.FormatStr(), ch) } -func CollectMetricsFromScript(socketPaths []*SocketPath, scriptPaths []string) ([]*client_model.MetricFamily, error) { +func CollectMetricsFromScript(socketPaths []*SocketPath, connectTimeout time.Duration, operationTimeout time.Duration, scriptPaths []string) ([]*client_model.MetricFamily, error) { var result []*client_model.MetricFamily for _, socketPath := range socketPaths { for _, scriptPath := range scriptPaths { - fcgi, err := fcgiclient.Dial(socketPath.Network, socketPath.Address) + fcgi, err := fcgiclient.DialTimeout(socketPath.Network, socketPath.Address, connectTimeout) if err != nil { return result, err } defer fcgi.Close() + if operationTimeout > 0 { + fcgi.SetTimeout(operationTimeout) + } + env := make(map[string]string) env["DOCUMENT_ROOT"] = path.Dir(scriptPath) env["SCRIPT_FILENAME"] = scriptPath @@ -219,14 +227,18 @@ func CollectMetricsFromScript(socketPaths []*SocketPath, scriptPaths []string) ( } type PhpfpmExporter struct { - socketPaths []*SocketPath - statusPath string + socketPaths []*SocketPath + connectTimeout time.Duration + operationTimeout time.Duration + statusPath string } -func NewPhpfpmExporter(socketPaths []*SocketPath, statusPath string) (*PhpfpmExporter, error) { +func NewPhpfpmExporter(socketPaths []*SocketPath, connectTimeout time.Duration, operationTimeout time.Duration, statusPath string) (*PhpfpmExporter, error) { return &PhpfpmExporter{ - socketPaths: socketPaths, - statusPath: statusPath, + socketPaths: socketPaths, + connectTimeout: connectTimeout, + operationTimeout: operationTimeout, + statusPath: statusPath, }, nil } @@ -242,7 +254,7 @@ func (e *PhpfpmExporter) Describe(ch chan<- *prometheus.Desc) { func (e *PhpfpmExporter) Collect(ch chan<- prometheus.Metric) { for _, socketPath := range e.socketPaths { - err := CollectStatusFromSocket(socketPath, e.statusPath, ch) + err := CollectStatusFromSocket(socketPath, e.statusPath, e.connectTimeout, e.operationTimeout, ch) if err == nil { ch <- prometheus.MustNewConstMetric( phpfpmUpDesc, @@ -282,13 +294,15 @@ func NewSocketPath(socketPath string) *SocketPath { func main() { var ( - listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9253").String() - metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() - socketPaths = kingpin.Flag("phpfpm.socket-paths", "Paths of the PHP-FPM sockets.").Strings() - socketDirectories = kingpin.Flag("phpfpm.socket-directories", "Path(s) of the directory where PHP-FPM sockets are located.").Strings() - statusPath = kingpin.Flag("phpfpm.status-path", "Path which has been configured in PHP-FPM to show status page.").Default("/status").String() - scriptCollectorPaths = kingpin.Flag("phpfpm.script-collector-paths", "Paths of the PHP file whose output needs to be collected.").Strings() - showVersion = kingpin.Flag("version", "Print version information.").Bool() + listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9253").String() + metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() + socketPaths = kingpin.Flag("phpfpm.socket-paths", "Paths of the PHP-FPM sockets.").Strings() + socketDirectories = kingpin.Flag("phpfpm.socket-directories", "Path(s) of the directory where PHP-FPM sockets are located.").Strings() + statusPath = kingpin.Flag("phpfpm.status-path", "Path which has been configured in PHP-FPM to show status page.").Default("/status").String() + scriptCollectorPaths = kingpin.Flag("phpfpm.script-collector-paths", "Paths of the PHP file whose output needs to be collected.").Strings() + socketConnectionTimeout = kingpin.Flag("phpfpm.connection-timeout", "Connection timeout for PHP-FPM sockets.").Duration() + socketOperationTimeout = kingpin.Flag("phpfpm.operation-timeout", "Read/write operation timeout for PHP-FPM sockets.").Duration() + showVersion = kingpin.Flag("version", "Print version information.").Bool() ) kingpin.CommandLine.HelpFlag.Short('h') @@ -313,7 +327,7 @@ func main() { os.Exit(0) } - exporter, err := NewPhpfpmExporter(sockets, *statusPath) + exporter, err := NewPhpfpmExporter(sockets, *socketConnectionTimeout, *socketOperationTimeout, *statusPath) if err != nil { panic(err) } @@ -324,7 +338,7 @@ func main() { gatherer = prometheus.Gatherers{ prometheus.DefaultGatherer, prometheus.GathererFunc(func() ([]*client_model.MetricFamily, error) { - return CollectMetricsFromScript(sockets, *scriptCollectorPaths) + return CollectMetricsFromScript(sockets, *socketConnectionTimeout, *socketOperationTimeout, *scriptCollectorPaths) }), } }