Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev: Add a method of comparison #124

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.