From dfd4093742bf9b55f9267771413674a3a4d2f35c Mon Sep 17 00:00:00 2001 From: Emmanuel Leroy Date: Wed, 31 Jul 2019 17:11:02 -0700 Subject: [PATCH 1/2] fix issues with breaking changes from module switch to all milliseconds --- GrafanaDatastoreServer.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/GrafanaDatastoreServer.py b/GrafanaDatastoreServer.py index cc6a2b6..ae80d41 100755 --- a/GrafanaDatastoreServer.py +++ b/GrafanaDatastoreServer.py @@ -3,7 +3,7 @@ import argparse import redis import flask -import calendar +from datetime import timedelta, datetime import dateutil.parser from gevent.pywsgi import WSGIServer from flask import Flask, jsonify @@ -12,6 +12,8 @@ app = Flask(__name__) CORS(app) +EPOCH = datetime(1970, 1, 1, 0, 0, 0) + REDIS_POOL = None SCAN_TYPE_SCRIPT = """local cursor, pat, typ, cnt = ARGV[1], ARGV[2], ARGV[3], ARGV[4] or 100 local rep = {} @@ -61,19 +63,22 @@ def query(): request = flask.request.get_json() response = [] - stime = calendar.timegm(dateutil.parser.parse(request['range']['from']).timetuple()) - etime = calendar.timegm(dateutil.parser.parse(request['range']['to']).timetuple()) + # !!! dates 'from' and 'to' are expected to be in UTC, which is what Grafana provides here. + # If not in UTC, use pytz to set to UTC timezone and subtract the utcoffset(). + # Time delta calculations should always be done in UTC to avoid pitfalls of daylight offset changes. + stime = (dateutil.parser.parse(request['range']['from']) - EPOCH) / timedelta(milliseconds=1) + etime = (dateutil.parser.parse(request['range']['to']) - EPOCH) / timedelta(milliseconds=1) redis_client = redis.Redis(connection_pool=REDIS_POOL) targets = process_targets([t['target'] for t in request['targets']], redis_client) for target in targets: args = ['ts.range', target, int(stime), int(etime)] - if 'intervalMs' in request and request['intervalMs'] > 0 and request['intervalMs']/1000 > 1: - args += ['avg', int(round(request['intervalMs']/1000))] + if 'intervalMs' in request and request['intervalMs'] > 0: + args += ['avg', int(request['intervalMs'])] print(args) redis_resp = redis_client.execute_command(*args) - datapoints = [(float(x2.decode("ascii")), x1*1000) for x1, x2 in redis_resp] + datapoints = [(float(x2.decode("ascii")), x1) for x1, x2 in redis_resp] response.append(dict(target=target, datapoints=datapoints)) return jsonify(response) From a62a36dfba14757e4c8e10fded1432d6776bd561 Mon Sep 17 00:00:00 2001 From: Emmanuel Leroy Date: Wed, 31 Jul 2019 17:11:57 -0700 Subject: [PATCH 2/2] fix issues with search and lookup with pattern: need to decode bytes to strings --- GrafanaDatastoreServer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GrafanaDatastoreServer.py b/GrafanaDatastoreServer.py index ae80d41..2bb7361 100755 --- a/GrafanaDatastoreServer.py +++ b/GrafanaDatastoreServer.py @@ -43,7 +43,7 @@ def search(): cursor = 0 while True: cursor, keys = redis_client.eval(SCAN_TYPE_SCRIPT, 0, cursor, "*", "TSDB-TYPE", 100) - result.extend(keys) + result.extend([k.decode("ascii") for k in keys]) if cursor == 0: break @@ -53,7 +53,7 @@ def process_targets(targets, redis_client): result = [] for target in targets: if '*' in target: - result.extend(redis_client.keys(target)) + result.extend([k.decode('ascii') for k in redis_client.keys(target)]) else: result.append(target) return result