Skip to content

Commit

Permalink
added: method of comparison for graphite
Browse files Browse the repository at this point in the history
  • Loading branch information
delong1 committed Jun 29, 2016
1 parent 0be6759 commit f183bc6
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
44 changes: 44 additions & 0 deletions graphite_beacon/alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from . import _compat as _
from .graphite import GraphiteRecord
from .utils import (
COMPARISON,
HISTORICAL,
LOGICAL_OPERATORS,
convert_to_format,
Expand All @@ -13,6 +14,7 @@
parse_rule,
)
import math
import time
from collections import deque, defaultdict
from itertools import islice

Expand Down Expand Up @@ -80,6 +82,7 @@ def __init__(self, reactor, **options):
self.waiting = False
self.state = {None: "normal", "waiting": "normal", "loading": "normal"}
self.history = defaultdict(lambda: sliceable_deque([], self.history_size))
self.comparing = {}

LOGGER.info("Alert '%s': has inited", self)

Expand Down Expand Up @@ -205,6 +208,18 @@ def get_value_for_expr(self, expr, target):
return None
rvalue = sum(history) / float(len(history))

if rvalue == COMPARISON:
current_time = int(time.time())
if self.comparing.has_key(target) and self.comparing[target]['time'] == current_time:
rvalue = self.comparing[target]['value']
else:
rvalue = self.get_graph_comparison()
if rvalue != -1:
if not self.comparing.has_key(target):
self.comparing[target] = {}
self.comparing[target]['value'] = rvalue
self.comparing[target]['time'] = current_time

rvalue = expr['mod'](rvalue)
return rvalue

Expand All @@ -226,6 +241,10 @@ def load(self):
"""Load from remote."""
raise NotImplementedError()

def get_graph_comparison(self):
"""Only from graphite."""
raise NotImplementedError()


class GraphiteAlert(BaseAlert):

Expand All @@ -241,6 +260,7 @@ def configure(self, **options):
self.default_nan_value = options.get(
'default_nan_value', self.reactor.options['default_nan_value'])
self.ignore_nan = options.get('ignore_nan', self.reactor.options['ignore_nan'])
self.compare_size = options.get('compare_size', self.reactor.options['compare_size'])
assert self.method in METHODS, "Method is invalid"

self.auth_username = self.reactor.options.get('auth_username')
Expand Down Expand Up @@ -274,6 +294,7 @@ def load(self):
self.check(data)
self.notify('normal', 'Metrics are loaded', target='loading', ntype='common')
except Exception as e:
LOGGER.debug("ee: %s", str(e))
self.notify(
self.loading_error, 'Loading error: %s' % e, target='loading', ntype='common')
self.waiting = False
Expand All @@ -293,6 +314,29 @@ def _graphite_url(self, query, raw_data=False, graphite_url=None):
url = "{0}&rawData=true".format(url)
return url

def get_graph_comparison(self):
time_shift = self.compare_size
if time_shift[0] != '-':
time_shift = '-' + time_shift

query = 'timeShift(' + self.query + ', "' + time_shift + '")'
url = self._graphite_url(
query, graphite_url=self.reactor.options.get('graphite_url'), raw_data=True)

http_client = hc.HTTPClient()
try:
response = http_client.fetch(url, auth_username=self.auth_username,
auth_password=self.auth_password,
request_timeout=self.request_timeout,
connect_timeout=self.connect_timeout)
record = GraphiteRecord(response.body.decode('utf-8'), self.default_nan_value, self.ignore_nan)
value = getattr(record, self.method)
LOGGER.debug("%s [%s]: %s", self.name, record.target, value)
return value
except Exception as e:
LOGGER.error('No data to compare: %s', str(e))
return -1


class URLAlert(BaseAlert):

Expand Down
1 change: 1 addition & 0 deletions graphite_beacon/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Reactor(object):
'debug': False,
'format': 'short',
'graphite_url': 'http://localhost',
'compare_size': '7d',
'history_size': '1day',
'interval': '10minute',
'logging': 'info',
Expand Down
7 changes: 5 additions & 2 deletions graphite_beacon/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
IDENTITY = lambda x: x


COMPARISON = 'comparison'
HISTORICAL = 'historical'
COMPARATORS = {'>': op.gt, '>=': op.ge, '<': op.lt, '<=': op.le, '==': op.eq, '!=': op.ne}
OPERATORS = {'*': op.mul, '/': op.truediv, '+': op.add, '-': op.sub}
Expand All @@ -51,6 +52,7 @@
RULE_TOKENIZER = make_tokenizer(
[
(u'Level', (r'(critical|warning|normal)',)),
(u'Comparison', (COMPARISON,)),
(u'Historical', (HISTORICAL,)),
(u'Comparator', (r'({0})'.format('|'.join(sorted(COMPARATORS.keys(), reverse=True))),)),
(u'LogicalOperator', (r'({0})'.format('|'.join(LOGICAL_OPERATORS.keys())),)),
Expand Down Expand Up @@ -113,12 +115,13 @@ def _parse_rule(seq):
level = toktype(u'Level')
comparator = toktype(u'Comparator') >> COMPARATORS.get
number = toktype(u'Number') >> float
comparison = toktype(u'Comparison')
historical = toktype(u'Historical')
unit = toktype(u'Unit')
operator = toktype(u'Operator')
logical_operator = toktype(u'LogicalOperator') >> LOGICAL_OPERATORS.get

exp = comparator + ((number + maybe(unit)) | historical) + maybe(operator + number)
exp = comparator + ((number + maybe(unit)) | comparison | historical) + maybe(operator + number)
rule = (
level + s_sep(':') + exp + many(logical_operator + exp)
)
Expand All @@ -130,7 +133,7 @@ def _parse_rule(seq):
def _parse_expr(expr):
cond, value, mod = expr

if value != HISTORICAL:
if value != HISTORICAL and value != COMPARISON:
value = convert_from_format(*value)

if mod:
Expand Down
Empty file modified setup.py
100644 → 100755
Empty file.

0 comments on commit f183bc6

Please sign in to comment.