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; 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) diff --git a/webapp/graphite/render/functions.py b/webapp/graphite/render/functions.py index a015aaebf..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] @@ -1930,15 +1934,10 @@ 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) + 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) @@ -3257,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 @@ -5260,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: diff --git a/webapp/tests/test_functions.py b/webapp/tests/test_functions.py index e76f78e04..9c723d668 100644 --- a/webapp/tests/test_functions.py +++ b/webapp/tests/test_functions.py @@ -876,11 +876,50 @@ 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)) + 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_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))