Skip to content

Commit

Permalink
Add plugin for varnishd
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Kelley authored and Jonathan Kelley committed Jun 19, 2018
1 parent 3d28c14 commit 6f319ce
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 2 deletions.
12 changes: 11 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ NewRelic platform. Currently supported backend systems are:
- Redis
- Riak
- uWSGI
- Varnishd

Base Requirements
-----------------
Expand Down Expand Up @@ -254,9 +255,13 @@ UWSGI Installation Notes
------------------------
The UWSGI plugin can communicate either over UNIX domain sockets using the path configuration variable or TCP/IP using the host and port variables. Do not include both.

Make sure you have `enabled stats server
Make sure you have `enabled stats server
<http://uwsgi-docs.readthedocs.org/en/latest/StatsServer.html>`_ in your uwsgi config.

Varnishd Installation Notes
------------------------
The Varnishd plugin uses the local ``varnishstat`` command to get information about your instance. Use the ``instance`` configuration variable to define your local varnish instance. The ``newrelic_instance`` can be used to set the NewRelic instance name, else the Varnish instance name is used. Your varnishstat command will be called from your system path, but can be overriden with `varnishstat`` configuration variable.

Configuration Example
---------------------

Expand Down Expand Up @@ -407,6 +412,11 @@ Configuration Example
port: 8098
#verify_ssl_cert: true

varnishd:
instance: varnish1
newrelic_instance: my_varnish_server
varnishstat: /usr/local/bin/varnishstat

Daemon:
user: newrelic
pidfile: /var/run/newrelic/newrelic-plugin-agent.pid
Expand Down
5 changes: 5 additions & 0 deletions etc/newrelic/newrelic-plugin-agent.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ Application:
# port: 1717
# path: /path/to/unix/socket

#varnishd:
# instance: local_varnishd_instance
# newrelic_instance: newrelic_instance_title
# varnishstat: /optional/alternative/path

Daemon:
user: newrelic
pidfile: /var/run/newrelic/newrelic-plugin-agent.pid
Expand Down
3 changes: 2 additions & 1 deletion newrelic_plugin_agent/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@
'rabbitmq': 'newrelic_plugin_agent.plugins.rabbitmq.RabbitMQ',
'redis': 'newrelic_plugin_agent.plugins.redis.Redis',
'riak': 'newrelic_plugin_agent.plugins.riak.Riak',
'uwsgi': 'newrelic_plugin_agent.plugins.uwsgi.uWSGI'}
'uwsgi': 'newrelic_plugin_agent.plugins.uwsgi.uWSGI',
'varnishd': 'newrelic_plugin_agent.plugins.varnishd.Varnishd'}
109 changes: 109 additions & 0 deletions newrelic_plugin_agent/plugins/varnishd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
varnishd 4.0
"""
import logging
import platform
import subprocess
import json

from newrelic_plugin_agent.plugins import base

LOGGER = logging.getLogger(__name__)


class Varnishd(base.Plugin):

GUID = 'com.meetme.newrelic_varnishd_agent'

KEYS = ['client_req',
'backend_fail',
'cache_miss',
'cache_hit',
'threads',
'threads_created',
'threads_failed',
'threads_limited',
'sess_drop',
'sess_conn',
'sess_fail',
'n_lru_nuked',
'esi_errors',
'n_expired']

def add_datapoints(self, stats):
"""Add all of the data points for a node
:param dict stats: all of the nodes
"""
instance_name = self.config.get('instance', platform.node())
newrelic_name = self.config.get('newrelic_instance', instance_name)
base_name = 'Varnish/%s' % newrelic_name
self.add_derive_value('%s/Requests/received' % base_name, 'client_req',
stats['client_req'])
self.add_derive_value('%s/Backend/failures' % base_name, 'backend_fail',
stats['backend_fail'])
self.add_derive_value('%s/Cache/misses' % base_name, 'cache_miss',
stats['cache_miss'])
self.add_derive_value('%s/Cache/hits' % base_name, 'cache_hit',
stats['cache_hit'])
self.add_derive_value('%s/Threads/total' % base_name, 'threads',
stats['threads'])
self.add_derive_value('%s/Threads/created' % base_name, 'threads_created',
stats['threads_created'])
self.add_derive_value('%s/Threads/failed' % base_name, 'threads_failed',
stats['threads_failed'])
self.add_derive_value('%s/Threads/limited' % base_name, 'threads_limited',
stats['threads_limited'])
self.add_derive_value('%s/Sessions/accepted' % base_name, 'sess_conn',
stats['sess_conn'])
self.add_derive_value('%s/Sessions/failed' % base_name, 'sess_fail',
stats['sess_fail'])
self.add_derive_value('%s/Sessions/dropped' % base_name, 'sess_drop',
stats['sess_drop'])
self.add_derive_value('%s/LRU/nuked' % base_name, 'n_lru_nuked',
stats['n_lru_nuked'])
self.add_derive_value('%s/esi/errors' % base_name, 'esi_errors',
stats['esi_errors'])
self.add_derive_value('%s/Objects/expired' % base_name, 'n_expired',
stats['n_expired'])

def fetch_data(self):
"""Fetch the data from varnish stats command
:rtype: dict
"""
instance = self.config.get('instance', platform.node())
varnishstat = self.config.get('varnishstat', 'varnishstat')
try:
p = subprocess.Popen(
[varnishstat, "-1", "-j", "-n", instance], stdout=subprocess.PIPE)
stdout, err = p.communicate()
return json.loads(stdout)
except Exception as error:
LOGGER.error('Subprocess error: %r', error)
return {}

def parse_metrics(self, data):
"""
filters the appropriate metric types from metric KEYS
:rtype: dict
"""
parsed_data = {}
try:
for metricname in self.KEYS:
jsonmetric = "MAIN." + metricname
metric = data[jsonmetric]['value']
parsed_data[metricname] = metric
except Exception as error:
LOGGER.error('Metrics parsing error: %r', error)
return parsed_data

def poll(self):
"""Poll subprocess for stats data"""
self.initialize()
data = self.fetch_data()
parsed_data = self.parse_metrics(data)
if parsed_data:
self.add_datapoints(parsed_data)
self.finish()

0 comments on commit 6f319ce

Please sign in to comment.