Dashboard of status, statistic and messages from fpm daemon
Last updated: a year ago

Start with Grafana Cloud and the new FREE tier. Includes 10K series Prometheus or Graphite Metrics and 50gb Loki Logs

Downloads: 172

Reviews: 0

  • PHP-FPM-1597146687727.png

PHP-FPM Dashboard host or guest mashine.

  • Error log messages
  • Process
  • Worker states
  • Requests
  • Connections accepted


Collector Configuration Details

<Plugin python>
    ModulePath "/opt/collectd/python"
    Import "phpfpmstatus"
    <Module phpfpmstatus>
#       Verbose True
        Interval 60
        <Node "www-data">
            Proto http
            Host ""
            Port 5708
            Uri "phpfpmstatus"

<Plugin "Tail">
        <File "/var/log/php/www.errors.log">
                Instance "php_errors"
                # PHP Parse error
                        Regex " PHP Parse error:"
                        DSType "CounterInc"
                        Type "counter"
                        Instance "parse_error"
                # PHP Fatal error
                        Regex " PHP Fatal error:"
                        DSType "CounterInc"
                        Type "counter"
                        Instance "fatal_error"
                # PHP Warning
                        Regex " PHP Warning:"
                        DSType "CounterInc"
                        Type "counter"
                        Instance "warning"
                # PHP Notice:
                        Regex " PHP Notice:"
                        DSType "CounterInc"
                        Type "counter"
                        Instance "notice"


import collectd

import urllib2, re, json

class phpfpmstatus(object):

    def __init__(self):
        self.plugin_name = 'phpfpmstatus'
        self.interval = 60
        self.verbose_logging = False
        self.nodes = {}
        self.proto = 'http' = ''
        self.port = '5708'
        self.uri = 'phpfpmstatus'

    def log_verbose(self, msg):
        if not self.verbose_logging:
            return'%s plugin [verbose]: %s' % (self.plugin_name, msg))

    def send(self, name, key, val):
        val = collectd.Values(
        self.log_verbose('Sending %s.%s: %s' % (name, key, val))

    def init(self):
    for key, val in self.nodes.items():
            location = '%s://%s:%s/%s?full&json' % (val['proto'], val['host'], val['port'], val['uri'])
            self.nodes[key]['request'] = urllib2.Request(location)
            self.log_verbose('configured with location=%s' % location)

    def read(self):
    for node, val in self.nodes.items():
            result = urllib2.urlopen(val['request'])
            if ( result.getcode() == 200 ):
                data = json.load( result )
                self.send(node, 'accepted conn', data['accepted conn'])
                self.send(node, 'active processes', data['active processes'])
                self.send(node, 'idle processes', data['idle processes'])
                self.send(node, 'listen queue', data['listen queue'])
                self.send(node, 'max active processes', data['max active processes'])
                self.send(node, 'max children reached', data['max children reached'])
                self.send(node, 'max listen queue', data['max listen queue'])
                self.send(node, 'slow requests', data['slow requests'])
                self.send(node, 'total processes', data['total processes'])
                statuses = {}
                for n in data['processes']:
                    if n['state'] not in statuses:
                for k,v in statuses.items():
                    self.send(node, 'state_%s' % (k), v)

    def configure_callback(self, conf):
        for node in conf.children:
            vals = [str(v) for v in node.values]
            if node.key == 'Verbose':
                self.verbose_logging = (vals[0].lower() == 'true')
            elif node.key == 'Interval':
                self.interval = float(vals[0])
            elif node.key == 'Proto':
                self.proto = str(vals[0])
            elif node.key == 'Host':
       = str(vals[0])
            elif node.key == 'Port':
                self.port = int(float(vals[0]))
            elif node.key == 'Uri':
                self.uri = str(vals[0])
            elif node.key == 'Node':
                nodename = str(vals[0])
                self.nodes[nodename] = {}
                self.nodes[nodename]['proto'] = self.proto
                self.nodes[nodename]['host'] =
                self.nodes[nodename]['port'] = self.port
                self.nodes[nodename]['uri'] = self.uri
                for data in node.children:
                    vals = [str(v) for v in data.values]
                    if data.key == 'Proto':
                        self.nodes[nodename]['proto'] = str(vals[0])
                    elif data.key == 'Host':
                        self.nodes[nodename]['host'] = str(vals[0])
                    elif data.key == 'Port':
                        self.nodes[nodename]['port'] = int(float(vals[0]))
                    elif data.key == 'Uri':
                        self.nodes[nodename]['uri'] = str(vals[0])
                        raise ValueError('%s plugin: Unknown node %s sub-key: %s' % (self.plugin_name, nodename, data.key))
                raise ValueError('%s plugin: Unknown config key: %s' % (self.plugin_name, node.key))
        collectd.register_read(, self.interval)

app_phpfpmstatus = phpfpmstatus()


pm.status_path = /phpfpmstatus
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php/$pool.errors.log


server {
    listen ;
    access_log off;
    error_log /dev/null crit;
    deny all;
    location ~ ^/phpfpmstatus {
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;