PHP-FPM

Dashboard

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-1597146687727.png

PHP-FPM Dashboard host or guest mashine.

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

grafana->graphite->collectd

Collector Configuration Details

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

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

/opt/collectd/python/phpfpmstatus.py

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.host = '127.0.0.1'
        self.port = '5708'
        self.uri = 'phpfpmstatus'

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

    def send(self, name, key, val):
        val = collectd.Values(
            plugin=self.plugin_name,
            plugin_instance=name,
            type='gauge',
            type_instance=key,
            values=[val])
        val.dispatch()
        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:
                            statuses[n['state']]=1
                    else:
                            statuses[n['state']]+=1
                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':
                self.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.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])
                    else:
                        raise ValueError('%s plugin: Unknown node %s sub-key: %s' % (self.plugin_name, nodename, data.key))
            else:
                raise ValueError('%s plugin: Unknown config key: %s' % (self.plugin_name, node.key))
        self.init()
        collectd.register_read(self.read, self.interval)

app_phpfpmstatus = phpfpmstatus()
collectd.register_config(app_phpfpmstatus.configure_callback)

###/etc/php/7.0/fpm/pool.d/www.conf

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

###/etc/nginx/conf.d/collectd.conf

server {
    listen 127.0.0.1:5708 ;
    access_log off;
    error_log /dev/null crit;
    allow 127.0.0.1;
    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;
    }
}