From 427c92e3c2aec125f2320a7a41d850a3121500de Mon Sep 17 00:00:00 2001 From: Denys Zhdanov Date: Sun, 11 Mar 2018 21:28:54 +0100 Subject: [PATCH 1/8] Adding dummy.txt to storage dirs --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b32b864dc..a5ed97d31 100644 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ storage_dirs = [] -for subdir in ('whisper', 'ceres', 'rrd', 'log', 'log/webapp'): +for subdir in ('whisper/dummy.txt', 'ceres/dummy.txt', 'rrd/dummy.txt', 'log/dummy.txt', 'log/webapp/dummy.txt'): storage_dirs.append( ('storage/%s' % subdir, []) ) webapp_content = defaultdict(list) From 9774c10041ffbb6c28ccc9c6a73bbfd0409dc5a3 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Mon, 19 Mar 2018 21:58:12 +0200 Subject: [PATCH 2/8] Fix test_delay list nesting --- webapp/tests/test_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/tests/test_functions.py b/webapp/tests/test_functions.py index e76f78e04..71d38bd69 100644 --- a/webapp/tests/test_functions.py +++ b/webapp/tests/test_functions.py @@ -876,11 +876,11 @@ def test_changed(self): def test_delay(self): source = [ - TimeSeries('collectd.test-db1.load.value',0,1,1,[list(range(18))] + [None, None]), + TimeSeries('collectd.test-db1.load.value',0,1,1,list(range(18)) + [None, None]), ] delay = 2 expectedList = [ - TimeSeries('delay(collectd.test-db1.load.value,2)',0,1,1,[None, None] + [list(range(18))]), + TimeSeries('delay(collectd.test-db1.load.value,2)',0,1,1,[None, None] + list(range(18))), ] gotList = functions.delay({}, source, delay) self.assertEqual(len(gotList), len(expectedList)) From d81b1eb3cb41304bdc6d94b4679a26a739e14f13 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Mon, 19 Mar 2018 21:58:35 +0200 Subject: [PATCH 3/8] Add test for delay func where step > len(series) --- webapp/tests/test_functions.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/webapp/tests/test_functions.py b/webapp/tests/test_functions.py index 71d38bd69..b47b481e9 100644 --- a/webapp/tests/test_functions.py +++ b/webapp/tests/test_functions.py @@ -887,6 +887,19 @@ def test_delay(self): for got, expected in zip(gotList, expectedList): self.assertEqual(got, expected) + def test_delay_too_many_steps(self): + source = [ + TimeSeries('collectd.test-db1.load.value',0,1,1,list(range(20))), + ] + delay = 25 + expectedList = [ + TimeSeries('delay(collectd.test-db1.load.value,25)',0,1,1,[None]*20), + ] + gotList = functions.delay({}, source, delay) + self.assertEqual(len(gotList), len(expectedList)) + for got, expected in zip(gotList, expectedList): + self.assertEqual(got, expected) + def test_asPercent_error(self): seriesList = self._gen_series_list_with_data( key=[ From a93ba1014fc2c64755a717d9c9f7c5b34e4c5ace Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Mon, 19 Mar 2018 22:10:55 +0200 Subject: [PATCH 4/8] Add tests for delay render function with negative step They currently fail. --- webapp/tests/test_functions.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/webapp/tests/test_functions.py b/webapp/tests/test_functions.py index b47b481e9..9c723d668 100644 --- a/webapp/tests/test_functions.py +++ b/webapp/tests/test_functions.py @@ -900,6 +900,32 @@ def test_delay_too_many_steps(self): for got, expected in zip(gotList, expectedList): self.assertEqual(got, expected) + def test_delay_negative(self): + source = [ + TimeSeries('collectd.test-db1.load.value',0,1,1,[None,None] + list(range(2,20))), + ] + delay = -2 + expectedList = [ + TimeSeries('delay(collectd.test-db1.load.value,-2)',0,1,1,list(range(2,20)) + [None,None]), + ] + gotList = functions.delay({}, source, delay) + self.assertEqual(len(gotList), len(expectedList)) + for got, expected in zip(gotList, expectedList): + self.assertEqual(got, expected) + + def test_delay_negative_too_many_steps(self): + source = [ + TimeSeries('collectd.test-db1.load.value',0,1,1,list(range(20))), + ] + delay = -25 + expectedList = [ + TimeSeries('delay(collectd.test-db1.load.value,-25)',0,1,1,[None]*20), + ] + gotList = functions.delay({}, source, delay) + self.assertEqual(len(gotList), len(expectedList)) + for got, expected in zip(gotList, expectedList): + self.assertEqual(got, expected) + def test_asPercent_error(self): seriesList = self._gen_series_list_with_data( key=[ From fb8b6933c80eee8ddb524fca44d75d0d745a27e4 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Mon, 19 Mar 2018 21:58:47 +0200 Subject: [PATCH 5/8] Simplify logic of delay function --- webapp/graphite/render/functions.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/webapp/graphite/render/functions.py b/webapp/graphite/render/functions.py index a015aaebf..8381c76c1 100644 --- a/webapp/graphite/render/functions.py +++ b/webapp/graphite/render/functions.py @@ -1930,15 +1930,7 @@ def delay(requestContext, seriesList, steps): """ results = [] for series in seriesList: - newValues = [] - prev = [] - for val in series: - if len(prev) < steps: - newValues.append(None) - prev.append(val) - continue - newValues.append(prev.pop(0)) - prev.append(val) + newValues = [None] * min(steps, len(series)) + series[:-steps] series.tags['delay'] = steps newName = "delay(%s,%d)" % (series.name, steps) newSeries = series.copy(name=newName, values=newValues) From af8e77b817f57aa62349d6d8402e4a08fb5aeae4 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Mon, 19 Mar 2018 22:11:16 +0200 Subject: [PATCH 6/8] Support negative steps in delay render function --- webapp/graphite/render/functions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/webapp/graphite/render/functions.py b/webapp/graphite/render/functions.py index 8381c76c1..3771a0084 100644 --- a/webapp/graphite/render/functions.py +++ b/webapp/graphite/render/functions.py @@ -1930,7 +1930,10 @@ def delay(requestContext, seriesList, steps): """ results = [] for series in seriesList: - newValues = [None] * min(steps, len(series)) + series[:-steps] + if steps < 0: + newValues = series[-steps:] + [None] * min(-steps, len(series)) + else: + newValues = [None] * min(steps, len(series)) + series[:-steps] series.tags['delay'] = steps newName = "delay(%s,%d)" % (series.name, steps) newSeries = series.copy(name=newName, values=newValues) From 5584b1f58e7c1b2163ae057bfc5c02fa6f16adc2 Mon Sep 17 00:00:00 2001 From: BitFur Date: Sun, 25 Mar 2018 21:57:59 +0300 Subject: [PATCH 7/8] fixed missing static location in nginx + uwsgi conf #2260 --- docs/config-webapp.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/config-webapp.rst b/docs/config-webapp.rst index fff6bb5ae..bdc28b524 100644 --- a/docs/config-webapp.rst +++ b/docs/config-webapp.rst @@ -253,6 +253,10 @@ Finally, configure the nginx vhost: server { listen 80; + location /static/ { + alias /opt/graphite/webapp/content/; + } + location / { include uwsgi_params; uwsgi_pass localhost:8080; From 1c5892ebb82e420d71641f6fe92cad42daa9bfd1 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 13 Mar 2018 20:35:50 +0000 Subject: [PATCH 8/8] graphite functions: handle max on empty sequences better I was seeing errors due to code like safeMax(series) > 0, where safeMax returned None. --- webapp/graphite/render/functions.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/webapp/graphite/render/functions.py b/webapp/graphite/render/functions.py index 3771a0084..1c0b9f0d1 100644 --- a/webapp/graphite/render/functions.py +++ b/webapp/graphite/render/functions.py @@ -130,15 +130,19 @@ def safeLast(values): for v in reversed(values): if v is not None: return v -def safeMin(values): +def safeMin(values, default=None): safeValues = [v for v in values if v is not None] if safeValues: return min(safeValues) + else: + return default -def safeMax(values): +def safeMax(values, default=None): safeValues = [v for v in values if v is not None] if safeValues: return max(safeValues) + else: + return default def safeMap(function, values): safeValues = [v for v in values if v is not None] @@ -3252,7 +3256,7 @@ def sortByMinima(requestContext, seriesList): &target=sortByMinima(server*.instance*.memory.free) """ - newSeries = [series for series in seriesList if safeMax(series) > 0] + newSeries = [series for series in seriesList if safeMax(series, default=0) > 0] newSeries.sort(key=keyFunc(safeMin)) return newSeries @@ -5255,12 +5259,8 @@ def minMax(requestContext, seriesList): for series in seriesList: series.name = "minMax(%s)" % (series.name) series.pathExpression = series.name - min_val = safeMin(series) - max_val = safeMax(series) - if min_val is None: - min_val = 0.0 - if max_val is None: - max_val = 0.0 + min_val = safeMin(series, default=0.0) + max_val = safeMax(series, default=0.0) for i, val in enumerate(series): if series[i] is not None: try: