2018-02-19 01:11:23 +00:00
|
|
|
// Copyright © 2018 Enrico Stahn <enrico.stahn@gmail.com>
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2018-02-24 23:08:12 +00:00
|
|
|
// Package phpfpm provides convenient access to PHP-FPM pool data
|
2018-02-17 12:42:58 +00:00
|
|
|
package phpfpm
|
|
|
|
|
|
|
|
import (
|
2020-11-21 11:14:15 +00:00
|
|
|
"fmt"
|
2020-11-22 00:15:40 +00:00
|
|
|
"sync"
|
|
|
|
|
2018-02-17 12:42:58 +00:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
namespace = "phpfpm"
|
|
|
|
)
|
|
|
|
|
2018-02-19 00:45:35 +00:00
|
|
|
// Exporter configures and exposes PHP-FPM metrics to Prometheus.
|
2018-02-17 12:42:58 +00:00
|
|
|
type Exporter struct {
|
|
|
|
mutex sync.Mutex
|
2018-02-24 13:36:13 +00:00
|
|
|
PoolManager PoolManager
|
2018-02-17 12:42:58 +00:00
|
|
|
|
2018-02-28 11:22:35 +00:00
|
|
|
CountProcessState bool
|
2018-02-24 13:36:13 +00:00
|
|
|
|
|
|
|
up *prometheus.Desc
|
|
|
|
scrapeFailues *prometheus.Desc
|
|
|
|
startSince *prometheus.Desc
|
|
|
|
acceptedConnections *prometheus.Desc
|
|
|
|
listenQueue *prometheus.Desc
|
|
|
|
maxListenQueue *prometheus.Desc
|
|
|
|
listenQueueLength *prometheus.Desc
|
|
|
|
idleProcesses *prometheus.Desc
|
|
|
|
activeProcesses *prometheus.Desc
|
|
|
|
totalProcesses *prometheus.Desc
|
|
|
|
maxActiveProcesses *prometheus.Desc
|
|
|
|
maxChildrenReached *prometheus.Desc
|
|
|
|
slowRequests *prometheus.Desc
|
|
|
|
processRequests *prometheus.Desc
|
|
|
|
processLastRequestMemory *prometheus.Desc
|
|
|
|
processLastRequestCPU *prometheus.Desc
|
2018-02-28 23:54:12 +00:00
|
|
|
processRequestDuration *prometheus.Desc
|
2018-02-27 08:31:31 +00:00
|
|
|
processState *prometheus.Desc
|
2018-02-17 12:42:58 +00:00
|
|
|
}
|
|
|
|
|
2018-02-19 00:45:35 +00:00
|
|
|
// NewExporter creates a new Exporter for a PoolManager and configures the necessary metrics.
|
2018-02-17 12:42:58 +00:00
|
|
|
func NewExporter(pm PoolManager) *Exporter {
|
|
|
|
return &Exporter{
|
|
|
|
PoolManager: pm,
|
|
|
|
|
2018-02-28 11:22:35 +00:00
|
|
|
CountProcessState: false,
|
2018-02-24 13:36:13 +00:00
|
|
|
|
2018-02-22 04:41:27 +00:00
|
|
|
up: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "up"),
|
|
|
|
"Could PHP-FPM be reached?",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-22 04:41:27 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
scrapeFailues: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "scrape_failures"),
|
|
|
|
"The number of failures scraping from PHP-FPM.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-22 04:41:27 +00:00
|
|
|
nil),
|
|
|
|
|
2018-02-17 12:42:58 +00:00
|
|
|
startSince: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "start_since"),
|
|
|
|
"The number of seconds since FPM has started.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
acceptedConnections: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "accepted_connections"),
|
|
|
|
"The number of requests accepted by the pool.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
listenQueue: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "listen_queue"),
|
|
|
|
"The number of requests in the queue of pending connections.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
maxListenQueue: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "max_listen_queue"),
|
|
|
|
"The maximum number of requests in the queue of pending connections since FPM has started.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
listenQueueLength: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "listen_queue_length"),
|
|
|
|
"The size of the socket queue of pending connections.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
idleProcesses: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "idle_processes"),
|
2018-02-27 08:31:31 +00:00
|
|
|
"The number of idle processes.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
activeProcesses: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "active_processes"),
|
2018-02-27 08:31:31 +00:00
|
|
|
"The number of active processes.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
totalProcesses: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "total_processes"),
|
2018-02-27 08:31:31 +00:00
|
|
|
"The number of idle + active processes.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
maxActiveProcesses: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "max_active_processes"),
|
|
|
|
"The maximum number of active processes since FPM has started.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
maxChildrenReached: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "max_children_reached"),
|
|
|
|
"The number of times, the process limit has been reached, when pm tries to start more children (works only for pm 'dynamic' and 'ondemand').",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
slowRequests: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "slow_requests"),
|
|
|
|
"The number of requests that exceeded your 'request_slowlog_timeout' value.",
|
2020-03-10 12:58:27 +00:00
|
|
|
[]string{"pool", "scrape_uri"},
|
2018-02-17 12:42:58 +00:00
|
|
|
nil),
|
2018-02-24 13:36:13 +00:00
|
|
|
|
|
|
|
processRequests: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "process_requests"),
|
2018-02-28 23:54:12 +00:00
|
|
|
"The number of requests the process has served.",
|
2020-11-21 11:14:15 +00:00
|
|
|
[]string{"pool", "child", "scrape_uri"},
|
2018-02-24 13:36:13 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
processLastRequestMemory: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "process_last_request_memory"),
|
2018-02-28 23:54:12 +00:00
|
|
|
"The max amount of memory the last request consumed.",
|
2020-11-21 11:14:15 +00:00
|
|
|
[]string{"pool", "child", "scrape_uri"},
|
2018-02-24 13:36:13 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
processLastRequestCPU: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "process_last_request_cpu"),
|
2018-02-28 23:54:12 +00:00
|
|
|
"The %cpu the last request consumed.",
|
2020-11-21 11:14:15 +00:00
|
|
|
[]string{"pool", "child", "scrape_uri"},
|
2018-02-28 23:54:12 +00:00
|
|
|
nil),
|
|
|
|
|
|
|
|
processRequestDuration: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "process_request_duration"),
|
|
|
|
"The duration in microseconds of the requests.",
|
2020-11-21 11:14:15 +00:00
|
|
|
[]string{"pool", "child", "scrape_uri"},
|
2018-02-24 13:36:13 +00:00
|
|
|
nil),
|
2018-02-27 08:31:31 +00:00
|
|
|
|
|
|
|
processState: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "", "process_state"),
|
2018-02-28 23:54:12 +00:00
|
|
|
"The state of the process (Idle, Running, ...).",
|
2020-11-21 11:14:15 +00:00
|
|
|
[]string{"pool", "child", "state", "scrape_uri"},
|
2018-02-27 08:31:31 +00:00
|
|
|
nil),
|
2018-02-17 12:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-19 00:45:35 +00:00
|
|
|
// Collect updates the Pools and sends the collected metrics to Prometheus
|
2018-02-17 12:42:58 +00:00
|
|
|
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|
|
|
e.mutex.Lock()
|
|
|
|
defer e.mutex.Unlock()
|
|
|
|
|
2020-03-04 05:34:23 +00:00
|
|
|
if err := e.PoolManager.Update(); err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
2018-02-17 12:42:58 +00:00
|
|
|
|
2018-02-19 00:45:35 +00:00
|
|
|
for _, pool := range e.PoolManager.Pools {
|
2020-03-10 12:58:27 +00:00
|
|
|
ch <- prometheus.MustNewConstMetric(e.scrapeFailues, prometheus.CounterValue, float64(pool.ScrapeFailures), pool.Name, pool.Address)
|
2018-02-22 04:41:27 +00:00
|
|
|
|
|
|
|
if pool.ScrapeError != nil {
|
2020-03-10 12:58:27 +00:00
|
|
|
ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 0, pool.Name, pool.Address)
|
2018-02-24 13:39:06 +00:00
|
|
|
log.Errorf("Error scraping PHP-FPM: %v", pool.ScrapeError)
|
2018-02-22 04:41:27 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-02-28 01:12:10 +00:00
|
|
|
active, idle, total := CountProcessState(pool.Processes)
|
2018-02-28 11:22:35 +00:00
|
|
|
if !e.CountProcessState && (active != pool.ActiveProcesses || idle != pool.IdleProcesses) {
|
2022-02-17 23:17:34 +00:00
|
|
|
log.Error("Inconsistent active and idle processes reported. Set `--phpfpm.fix-process-count` to have this calculated by php-fpm_exporter instead.")
|
2018-02-24 13:36:13 +00:00
|
|
|
}
|
|
|
|
|
2018-02-28 11:22:35 +00:00
|
|
|
if !e.CountProcessState {
|
2018-02-27 08:31:31 +00:00
|
|
|
active = pool.ActiveProcesses
|
|
|
|
idle = pool.IdleProcesses
|
|
|
|
total = pool.TotalProcesses
|
2018-02-24 13:36:13 +00:00
|
|
|
}
|
|
|
|
|
2020-03-10 12:58:27 +00:00
|
|
|
ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 1, pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.startSince, prometheus.CounterValue, float64(pool.StartSince), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.acceptedConnections, prometheus.CounterValue, float64(pool.AcceptedConnections), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.listenQueue, prometheus.GaugeValue, float64(pool.ListenQueue), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.maxListenQueue, prometheus.CounterValue, float64(pool.MaxListenQueue), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.listenQueueLength, prometheus.GaugeValue, float64(pool.ListenQueueLength), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.idleProcesses, prometheus.GaugeValue, float64(idle), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.activeProcesses, prometheus.GaugeValue, float64(active), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.totalProcesses, prometheus.GaugeValue, float64(total), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.maxActiveProcesses, prometheus.CounterValue, float64(pool.MaxActiveProcesses), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.maxChildrenReached, prometheus.CounterValue, float64(pool.MaxChildrenReached), pool.Name, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.slowRequests, prometheus.CounterValue, float64(pool.SlowRequests), pool.Name, pool.Address)
|
2018-02-24 13:36:13 +00:00
|
|
|
|
2020-11-21 11:14:15 +00:00
|
|
|
for childNumber, process := range pool.Processes {
|
|
|
|
childName := fmt.Sprintf("%d", childNumber)
|
2022-02-08 21:59:15 +00:00
|
|
|
|
2021-09-02 01:32:57 +00:00
|
|
|
states := map[string]int{
|
|
|
|
PoolProcessRequestIdle: 0,
|
|
|
|
PoolProcessRequestRunning: 0,
|
|
|
|
PoolProcessRequestFinishing: 0,
|
|
|
|
PoolProcessRequestReadingHeaders: 0,
|
|
|
|
PoolProcessRequestInfo: 0,
|
|
|
|
PoolProcessRequestEnding: 0,
|
|
|
|
}
|
|
|
|
states[process.State]++
|
|
|
|
|
|
|
|
for stateName, inState := range states {
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.processState, prometheus.GaugeValue, float64(inState), pool.Name, childName, stateName, pool.Address)
|
|
|
|
}
|
2020-11-21 11:14:15 +00:00
|
|
|
ch <- prometheus.MustNewConstMetric(e.processRequests, prometheus.CounterValue, float64(process.Requests), pool.Name, childName, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.processLastRequestMemory, prometheus.GaugeValue, float64(process.LastRequestMemory), pool.Name, childName, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.processLastRequestCPU, prometheus.GaugeValue, process.LastRequestCPU, pool.Name, childName, pool.Address)
|
|
|
|
ch <- prometheus.MustNewConstMetric(e.processRequestDuration, prometheus.GaugeValue, float64(process.RequestDuration), pool.Name, childName, pool.Address)
|
2018-02-24 13:36:13 +00:00
|
|
|
}
|
2018-02-17 12:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-19 00:45:35 +00:00
|
|
|
// Describe exposes the metric description to Prometheus
|
2018-02-17 12:42:58 +00:00
|
|
|
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
2018-03-01 00:07:51 +00:00
|
|
|
ch <- e.up
|
2018-02-17 12:42:58 +00:00
|
|
|
ch <- e.startSince
|
|
|
|
ch <- e.acceptedConnections
|
|
|
|
ch <- e.listenQueue
|
|
|
|
ch <- e.maxListenQueue
|
|
|
|
ch <- e.listenQueueLength
|
|
|
|
ch <- e.idleProcesses
|
|
|
|
ch <- e.activeProcesses
|
|
|
|
ch <- e.totalProcesses
|
|
|
|
ch <- e.maxActiveProcesses
|
|
|
|
ch <- e.maxChildrenReached
|
|
|
|
ch <- e.slowRequests
|
2018-03-01 00:07:51 +00:00
|
|
|
ch <- e.processState
|
|
|
|
ch <- e.processRequests
|
|
|
|
ch <- e.processLastRequestMemory
|
|
|
|
ch <- e.processLastRequestCPU
|
|
|
|
ch <- e.processRequestDuration
|
2018-02-17 12:42:58 +00:00
|
|
|
}
|