Created
June 25, 2021 14:14
-
-
Save nicolasb827/1bbf150581f44f715db8ae15190a36b8 to your computer and use it in GitHub Desktop.
phpfpm.py to retrieve php-fpm json status without nginx/http configuration for collectd. requires that pm.status = /status and cgi-fgci and sed are installed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
import subprocess | |
import json | |
COLLECTD_ENABLED = True | |
try: | |
if COLLECTD_ENABLED: | |
import collectd | |
except ImportError: | |
# We're not running in CollectD, set this to False so we can make some changes | |
# accordingly for testing/development. | |
COLLECTD_ENABLED = False | |
import re | |
# default config | |
URLS = [] | |
# gauge: store as is | |
# derive: store the change over time | |
TYPES = { | |
'start since': 'gauge', | |
'accepted conn': 'derive', | |
'listen queue': 'gauge', | |
'max listen queue': 'gauge', | |
'listen queue len': 'gauge', | |
'idle processes': 'gauge', | |
'active processes': 'gauge', | |
'total processes': 'gauge', | |
'max active processes': 'gauge', | |
'max children reached': 'gauge', | |
'slow requests': 'requests', | |
'requests': 'requests', | |
'request duration': 'gauge', | |
'content length': 'gauge', | |
'last request cpu': 'gauge', | |
'last request memory': 'gauge', | |
} | |
def configure_callback(conf): | |
global URLS | |
for node in conf.children: | |
key = node.key.lower() | |
value = node.values[0] | |
if key == 'url': | |
URLS.append(value) | |
else: | |
collectd.warning('phpfpm plugin: Unknown config key: %s.' % key) | |
def dispatch(pool, metric, value, metric_type, process=None): | |
instance = pool | |
if process is not None: | |
instance += '.process-{}'.format(process) | |
metric = metric.replace(' ', '_') | |
if COLLECTD_ENABLED: | |
vl = collectd.Values(plugin='phpfpm', plugin_instance=instance, | |
type=metric_type, type_instance=metric) | |
vl.dispatch(values=[value]) | |
else: | |
print 'dispatch: phpfpm.{}.{}.{} value: {}'.format( | |
instance, metric_type, metric, value) | |
def read_callback(): | |
global URLS | |
for url in URLS: | |
pipe1 = subprocess.Popen(["/usr/bin/cgi-fcgi", "-bind", "-connect", url], env={ "QUERY_STRING": "json&full", "REQUEST_METHOD": "GET", "SCRIPT_FILENAME": "/status", "SCRIPT_NAME": "/status", "REQUEST_URI":"/status", "GATEWAY_INTERFACE": "CGI/1.1" }, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | |
pipe2 = subprocess.Popen(["/usr/bin/sed", "-E", "1,/^.$/ d"], stdin=pipe1.stdout, stdout=subprocess.PIPE) | |
pipe1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits. | |
data = json.loads(pipe2.communicate()[0]) | |
# read master metrics | |
pool = data['pool'] | |
for metric in [m for m in data.keys() if m in TYPES]: | |
dispatch(pool, metric, data[metric], TYPES[metric]) | |
# read each prcess metrics | |
if 'processes' in data.keys(): | |
i = 0 | |
for process in data['processes']: | |
for metric in [m for m in process.keys() if m in TYPES]: | |
dispatch(pool, metric, | |
process[metric], TYPES[metric], process=i) | |
i += 1 | |
if COLLECTD_ENABLED: | |
collectd.register_read(read_callback) | |
collectd.register_config(configure_callback) | |
if __name__ == "__main__" and not COLLECTD_ENABLED: | |
from pprint import pprint as pp | |
print "Running in test mode, invoke with" | |
print sys.argv[0] + " URL" | |
URLS.append(sys.argv[1]) | |
print "\n\nURLS:" | |
pp(URLS) | |
read_callback() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment