Skip to content

Commit

Permalink
[FEATURES] Added metric_prefix option
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrien Delle Cave committed Jul 10, 2018
1 parent 2ef367d commit fa37b6f
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 108 deletions.
2 changes: 1 addition & 1 deletion bin/covenant
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ __license__ = """
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
__version__ = '0.0.6.34'
__version__ = '0.0.6.36'

# TODO: load Python logging configuration (using standard logging.config)

Expand Down
117 changes: 61 additions & 56 deletions covenant/classes/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from covenant.classes.exceptions import CovenantTaskError, CovenantTargetFailed
from covenant.classes.filters import CovenantNoResult
from sonicprobe import helpers

LOG = logging.getLogger('covenant.collect')

Expand Down Expand Up @@ -85,6 +86,51 @@ def set_labels_metric(self, labels, metricvalue):
e)
raise

def _build_labels_metrics(self):
nb_labels = len(self.labels)
nb_values = 0
labels = {}

for label in self.labels:
if label.removed() \
or not label.labelvalues:
continue

xlen = len(label.labelvalues)
if xlen > nb_values:
nb_values = xlen
r = []
for labelvalue in label.labelvalues:
if nb_labels == 1:
self.set_labels_metric({labelvalue.labelname: labelvalue.labelvalue},
labelvalue.get())
else:
r.append(labelvalue)

if nb_labels > 1:
labels[label.labelname] = r

if nb_labels > 1:
for n in range(0, nb_values):
r = {}
v = None
for labelname in self.metric._labelnames:
if len(labels[labelname]) <= n:
ref = labels[labelname][-1]
else:
ref = labels[labelname][n]

r[labelname] = ref.labelvalue
metricvalue = ref.get()
if metricvalue is not None:
v = metricvalue
self.set_labels_metric(r, v)

if nb_values == 0:
self.remove(True)

del labels

def _get_value_from_tasks(self, data):
if isinstance(data, CovenantTargetFailed):
if self.on_fail['remove']:
Expand Down Expand Up @@ -138,64 +184,23 @@ def __call__(self, data):
elif self.value_tasks:
data = self._get_value_from_tasks(data)

if self.removed():
return
try:
if self.removed():
return

data = self._sanitize_value(data)
data = self._sanitize_value(data)

if self.removed():
return
if self.removed():
return

if not self.labels:
try:
if self.labels:
self._build_labels_metrics()
elif helpers.is_scalar(data):
getattr(self.metric, self.method)(data)
except Exception, e:
LOG.exception("metric: %r, data: %r, error: %r", self.name, data, e)
raise
else:
LOG.warning("unable to fetch a valid metricvalue. (metric: %r, data: %r)", self.name, data)
except Exception, e:
LOG.exception("metric: %r, data: %r, error: %r", self.name, data, e)
raise
finally:
del data
return

has_label = False
nb_labels = len(self.labels)
nb_values = 0
labels = {}

for label in self.labels:
if label.removed() \
or not label.labelvalues:
continue

has_label = True
xlen = len(label.labelvalues)
if xlen > nb_values:
nb_values = xlen
r = []
for labelvalue in label.labelvalues:
if nb_labels == 1:
self.set_labels_metric({labelvalue.labelname: labelvalue.labelvalue},
labelvalue.get())
else:
r.append((labelvalue.labelvalue, labelvalue.get()))

if nb_labels > 1:
labels[label.labelname] = r

if nb_labels > 1:
for n in range(0, nb_values):
r = {}
v = None
for labelname in self.metric._labelnames:
if len(labels[labelname]) <= n:
ref = labels[labelname][-1]
else:
ref = labels[labelname][n]

r[labelname] = ref[0]
if ref[1] is not None:
v = ref[1]
self.set_labels_metric(r, v)

if not has_label:
self.remove(True)

del labels, data
56 changes: 31 additions & 25 deletions covenant/classes/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,21 @@ def __init__(self,
config,
collects,
registry,
labels = None,
label_tasks = None,
value_tasks = None,
on_fail = None,
on_noresult = None,
credentials = None):
labels = None,
label_tasks = None,
value_tasks = None,
on_fail = None,
on_noresult = None,
metric_prefix = None,
credentials = None):
self.name = name or ''
self.__config = copy.copy(config)
self.collects = []
self.registry = registry
self.labels = []
self.label_tasks = []
self.value_tasks = []
self.metric_prefix = metric_prefix
self.__credentials = copy.copy(credentials)

if labels:
Expand Down Expand Up @@ -106,6 +108,17 @@ def credentials(self):
def credentials(self, credentials):
return self

@classmethod
def _config_on(cls, option, config, default):
if option not in config:
return default

r = None
if config[option]:
r = config[option]

return r

@classmethod
def _sanitize_task_args(cls, args):
r = copy.copy(args)
Expand Down Expand Up @@ -183,15 +196,8 @@ def load_labels(self, labels, label_tasks = [], value_tasks = [], on_fail = None
if label['value_tasks']:
vtasks = self.load_tasks(label['value_tasks'])

if 'on_fail' in label:
on_fail = None
if label['on_fail']:
on_fail = label['on_fail']

if 'on_noresult' in label:
on_noresult = None
if label['on_noresult']:
on_noresult = label['on_noresult']
on_fail = self._config_on('on_fail', label, on_fail)
on_noresult = self._config_on('on_noresult', label, on_noresult)

labelnames.add(name)
clabels.append(CovenantLabels(
Expand All @@ -215,6 +221,13 @@ def load_collects(self, collects):

metric = METRICTYPES[xtype]
method = get_metric_type_default_func(xtype)
name = value.get('name') or key

if 'metric_prefix' in value:
if value['metric_prefix']:
name = "%s_%s" % (value['metric_prefix'], name)
elif self.metric_prefix:
name = "%s_%s" % (self.metric_prefix, name)

if 'method' in value:
method = value['method'].strip('_')
Expand All @@ -226,7 +239,7 @@ def load_collects(self, collects):
raise ValueError("unknown method %r for %r in %r"
% (method, value['type'], key))

kwds = {'name': value.get('name') or key,
kwds = {'name': name,
'documentation': value.pop('documentation'),
'registry': self.registry}

Expand All @@ -253,15 +266,8 @@ def load_collects(self, collects):
if value['value_tasks']:
vtasks = self.load_tasks(value['value_tasks'])

if 'on_fail' in value:
on_fail = None
if value['on_fail']:
on_fail = value['on_fail']

if 'on_noresult' in value:
on_noresult = None
if value['on_noresult']:
on_noresult = value['on_noresult']
on_fail = self._config_on('on_fail', value, on_fail)
on_noresult = self._config_on('on_noresult', value, on_noresult)

self.collects.append(CovenantCollect(
name = value.get('name') or key,
Expand Down
42 changes: 31 additions & 11 deletions covenant/plugins/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,52 @@

LOG = logging.getLogger('covenant.plugins.http')

_ALLOWED_METHODS = ('delete',
'get',
'head',
'patch',
'post',
'put')


class CovenantHttpPlugin(CovenantPlugBase):
PLUGIN_NAME = 'http'

def do_metrics(self, obj):
for target in self.targets:
(auth, data, req) = (None, None, None)
cfg = target.config
timeout = cfg.get('timeout', 10)
ssl_verify = cfg.get('ssl_verify', True)
(data, req) = (None, None)

cfg = target.config
method = 'get'
xformat = None

if 'format' in cfg:
xformat = cfg.pop('format').lower()

if 'uri' in cfg and not cfg.get('url'):
cfg['url'] = cfg.pop('uri')

if 'method' in cfg:
method = cfg.pop('method').lower()

if 'ssl_verify' in cfg:
cfg['verify'] = bool(cfg.pop('ssl_verify'))

if target.credentials:
auth = (target.credentials['username'],
target.credentials['password'])
cfg['auth'] = (target.credentials['username'],
target.credentials['password'])

if method not in _ALLOWED_METHODS:
raise CovenantConfigurationError("invalid http method: %r" % method)

try:
req = requests.get(cfg['uri'],
auth = auth,
timeout = timeout,
verify = ssl_verify)
req = getattr(requests, method)(**cfg)

if req.status_code != requests.codes.ok:
raise LookupError("invalid status code: %r. (error: %r)"
% (req.status_code, req.text))

if cfg.get('format') == 'json':
if xformat == 'json':
data = req.json()
else:
data = req.text
Expand Down
1 change: 1 addition & 0 deletions covenant/plugins/predis.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import logging
import redis

from covenant.classes.exceptions import CovenantConfigurationError
from covenant.classes.plugins import CovenantPlugBase, CovenantTargetFailed, PLUGINS

LOG = logging.getLogger('covenant.plugins.redis')
Expand Down
12 changes: 12 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
covenant (0.0.6.36) unstable; urgency=medium

* Added metric_prefix option.

-- Adrien Delle Cave <adrien.delle.cave@commandersact.com> Tue, 10 Jul 2018 07:57:59 +0200

covenant (0.0.6.35) unstable; urgency=medium

* Reviewed http plugin.

-- Adrien Delle Cave <adrien.delle.cave@commandersact.com> Tue, 10 Jul 2018 07:32:21 +0200

covenant (0.0.6.34) unstable; urgency=medium

* Reviewed README.md.
Expand Down
17 changes: 3 additions & 14 deletions etc/covenant/metrics.d/redis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -357,17 +357,6 @@
command: info
command_args:
- keyspace
labels:
- name: addr
value: "${vars['url']}"
static: true
- name: alias
value: "${vars.get('alias', '')}"
static: true
- name: db
label_tasks:
- '@labelize': dict
'value': 'keys'
collects:
- db_keys:
labels:
Expand All @@ -380,7 +369,7 @@
- name: db
label_tasks:
- '@labelize': dict
'value': 'keys'
value: 'keys'
type: gauge
documentation: Total number of keys by DB.
- db_keys_expiring:
Expand All @@ -394,7 +383,7 @@
- name: db
label_tasks:
- '@labelize': dict
'value': 'expires'
value: 'expires'
type: gauge
documentation: Total number of expiring keys by DB.
- db_avg_ttl_seconds:
Expand All @@ -408,6 +397,6 @@
- name: db
label_tasks:
- '@labelize': dict
'value': 'avg_ttl'
value: 'avg_ttl'
type: gauge
documentation: Avg TTL in seconds.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
from setuptools import find_packages, setup

version = '0.0.6.34'
version = '0.0.6.36'

current_dir = os.path.abspath(os.path.dirname(__file__))
requirements = [line.strip() for line in open(os.path.join(current_dir, 'requirements.txt'), 'r').readlines()]
Expand Down

0 comments on commit fa37b6f

Please sign in to comment.