Documentation
¶
Overview ¶
Package phpfpm is a Go library for talking to PHP-FPM.
It covers the four things a caller needs in order to reason about a running PHP-FPM installation: parsing the effective configuration, discovering running masters and their pools, scraping live status over FastCGI, and controlling the master (validate, reload).
It exists as its own module because two consumers need it and neither should depend on the other: fpm-exporter reads, and fpm-tune both reads and writes. The code began life inside fpm-exporter's internal/phpfpm, where it could not be imported.
Two conventions run through the package:
Nothing here owns a logger. Entry points that need one take a *slog.Logger. A library with a package-level logger cannot be embedded twice with different destinations, and it makes tests order-dependent.
Reload, never restart. Reload sends SIGUSR2, which has the master re-read its configuration and cycle workers gracefully. Callers changing pm.* settings should pair it with Validate first — an invalid drop-in that reaches a reload takes the pool down.
Index ¶
- Constants
- func MasterPID(pidFile string) (int, error)
- func ParseAddress(addr string, path string) (scheme, address, scriptPath string, err error)
- func Reload(pid int) error
- func ReloadAndWait(ctx context.Context, pid int, settle time.Duration, log *slog.Logger) error
- func RemoveOpcacheScript()
- func Validate(ctx context.Context, binary, configPath string) error
- type Discovered
- type EffectiveConfig
- type Info
- type Memory
- type OpcacheStatus
- type Pool
- type PoolOutcome
- type PoolProcess
- type Result
- type Stats
- type Target
Constants ¶
const DefaultTimeout = 3 * time.Second
DefaultTimeout bounds a FastCGI dial when a Target does not set one.
Variables ¶
This section is empty.
Functions ¶
func MasterPID ¶
MasterPID reads a php-fpm master's pid from its pid file.
Discover finds masters by scanning the process table, which is the right tool when you do not know what is running. When you already know which pool you are reloading, the pid file is the authoritative answer and does not require permission to read another user's /proc entry.
func ParseAddress ¶
func Reload ¶
Reload asks a running master to re-read its configuration.
SIGUSR2 is a graceful reload: the master re-reads the config and cycles its workers, letting each finish the request it is serving. It is deliberately not a restart — a restart drops in-flight requests, and on a host serving many sites that is a visible outage for a change that was meant to be routine.
Callers changing pool settings should Validate first. Reload does not check the configuration it is asking the master to adopt.
func ReloadAndWait ¶
ReloadAndWait reloads a master and waits for it to come back.
A reload that kills the master is the failure this exists to detect: Reload itself returns nil as soon as the signal is delivered, which is well before the master has re-read anything. Callers that are about to rely on the new configuration — or that need to know whether to roll back — need the confirmation rather than the delivery.
Liveness is checked with signal 0, which tests for the process without delivering anything.
func RemoveOpcacheScript ¶
func RemoveOpcacheScript()
RemoveOpcacheScript deletes the generated status script. Safe to call when no script was ever written.
func Validate ¶
Validate checks a configuration with `php-fpm -t` without applying it.
This is the guard that makes writing pool configuration survivable. PHP-FPM re-reads its configuration on reload, and a syntax error or an impossible value does not fail gracefully — the master refuses to come back and every pool it served goes down. Validating first turns that outage into a returned error.
The configPath is the master config, not the drop-in: `-t` walks the include tree, so a broken fragment is caught through its parent.
Types ¶
type Discovered ¶
type Discovered struct {
Name string
ConfigPath string
StatusPath string
Binary string
Socket string
StatusSocket string
CliBinary string
}
Discovered is one pool found by scanning the process table.
func Discover ¶
func Discover(log *slog.Logger) ([]Discovered, error)
Discover scans the process table for PHP-FPM masters and returns the pools they serve.
It parses each master's effective configuration, which means executing the discovered binary — see trustedPath for why that is gated on ownership.
log may be nil.
type EffectiveConfig ¶
func ParseConfig ¶
func ParseConfig(FPMBinaryPath string, FPMConfigPath string) (*EffectiveConfig, error)
ParseFPMConfig runs `php-fpm -tt` and parses its report of the effective configuration. Results are cached per binary+config pair.
type Info ¶
type Info struct {
Version string
Extensions []string
Opcache *OpcacheStatus
}
type OpcacheStatus ¶
type OpcacheStatus struct {
Enabled bool `json:"opcache_enabled"`
MemoryUsage Memory `json:"memory_usage"`
Statistics Stats `json:"opcache_statistics"`
}
func GetOpcacheStatus ¶
func GetOpcacheStatus(ctx context.Context, target Target) (*OpcacheStatus, error)
type Pool ¶
type Pool struct {
Address string `json:"address"`
Path string `json:"path"`
Name string `json:"pool"`
ProcessManager string `json:"process manager"`
StartTime int64 `json:"start time"`
StartSince int64 `json:"start since"`
AcceptedConnections int64 `json:"accepted conn"`
ListenQueue int64 `json:"listen queue"`
MaxListenQueue int64 `json:"max listen queue"`
ListenQueueLength int64 `json:"listen queue len"`
IdleProcesses int64 `json:"idle processes"`
ActiveProcesses int64 `json:"active processes"`
TotalProcesses int64 `json:"total processes"`
MaxActiveProcesses int64 `json:"max active processes"`
MaxChildrenReached int64 `json:"max children reached"`
SlowRequests int64 `json:"slow requests"`
MemoryPeak int64 `json:"memory peak"`
Processes []PoolProcess `json:"processes"`
ProcessesCpu *float64 `json:"processes_cpu"`
ProcessesMemory *float64 `json:"processes_memory"`
Config map[string]string `json:"config,omitempty"`
OpcacheStatus OpcacheStatus `json:"opcache_status,omitempty"`
PhpInfo Info `json:"php_info,omitempty"`
}
type PoolOutcome ¶
type PoolOutcome struct {
// Name is the pool's configured or discovered name, used to label a
// failure. A successful scrape prefers the name PHP-FPM itself reports.
Name string
Socket string
Result *Result
Err error
}
PoolOutcome is what happened to one configured pool during a scrape: either a Result, or the error that prevented one. Failures are values rather than log lines so the collector can emit up=0 for a pool that did not answer -- a pool that silently vanishes from the output is indistinguishable from a pool that was removed from the configuration.
func Scrape ¶
Scrape reads one pool's status page. Its client and response body close at the end of this call rather than at the end of a whole batch.
log may be nil.
func ScrapeAll ¶
ScrapeAll scrapes every target. It returns one outcome per target, in the order given, and an error only when nothing at all could be collected.
It took fpm-exporter's whole *config.Config before this package was extracted. A library takes the work it is asked to do; deciding which pools exist belongs to the caller.
log may be nil.
type PoolProcess ¶
type PoolProcess struct {
PID int `json:"pid"`
State string `json:"state"`
StartTime int64 `json:"start time"`
StartSince int64 `json:"start since"`
Requests int64 `json:"requests"`
RequestDuration int64 `json:"request duration"`
RequestMethod string `json:"request method"`
RequestURI string `json:"request uri"`
ContentLength int64 `json:"content length"`
User string `json:"user"`
Script string `json:"script"`
LastRequestCPU float64 `json:"last request cpu"`
LastRequestMemory float64 `json:"last request memory"`
CurrentRSS int64 `json:"current_rss"`
}
type Stats ¶
type Stats struct {
NumCachedScripts uint64 `json:"num_cached_scripts"`
Hits uint64 `json:"hits"`
Misses uint64 `json:"misses"`
BlacklistMisses uint64 `json:"blacklist_misses"`
OomRestarts uint64 `json:"oom_restarts"`
HashRestarts uint64 `json:"hash_restarts"`
ManualRestarts uint64 `json:"manual_restarts"`
HitRate float64 `json:"opcache_hit_rate"`
}
type Target ¶
type Target struct {
// Name identifies the pool in results when the pool itself could not be
// reached. A successful scrape uses the name PHP-FPM reports; this is the
// fallback so a failing pool is still labelled with something meaningful.
Name string `mapstructure:"name"`
// Socket is the pool's FastCGI address ("unix:///run/php-fpm.sock",
// "tcp://127.0.0.1:9000", or a bare path).
Socket string `mapstructure:"socket"`
// StatusSocket is where the status page is served, when it differs from
// Socket. Empty means Socket.
StatusSocket string `mapstructure:"status_socket"`
StatusPath string `mapstructure:"status_path"`
StatusPathEnabled bool `mapstructure:"status_path_enabled"`
// ConfigPath and Binary let ParseConfig recover the effective configuration
// for this pool. Both come from the master's command line during Discover.
ConfigPath string `mapstructure:"config_path"`
Binary string `mapstructure:"binary"`
CliBinary string `mapstructure:"cli_binary"`
// Timeout bounds the FastCGI dial for this pool. Zero means DefaultTimeout.
Timeout time.Duration `mapstructure:"timeout"`
}
Target describes how to reach one PHP-FPM pool.
It replaces the FPMPoolConfig this package used to take from fpm-exporter's internal config. A library cannot depend on one application's configuration type — the second consumer has a different one, and neither should have to adopt the other's.
The mapstructure tags are kept so a viper-based caller can decode straight into this type rather than maintaining a parallel struct and a copy function.
func TargetFromDiscovered ¶
func TargetFromDiscovered(d Discovered) Target
TargetFromDiscovered builds a scrape target from a discovered pool.