Skip to content

Commit

Permalink
Merge pull request #1109 from plockaby/timeSlice
Browse files Browse the repository at this point in the history
adding timeslice method
  • Loading branch information
obfuscurity committed Jan 20, 2015
2 parents 789a4e6 + 47a6888 commit c73bb30
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 3 deletions.
1 change: 1 addition & 0 deletions webapp/content/js/composer_widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ function createFunctionsMenu() {
{text: 'Invert', handler: applyFuncToEach('invert')},
{text: 'Absolute Value', handler: applyFuncToEach('absolute')},
{text: 'timeShift', handler: applyFuncToEachWithInput('timeShift', 'Shift this metric ___ back in time (examples: 10min, 7d, 2w)', {quote: true})},
{text: 'timeSlice', handler: applyFuncToEachWithInput('timeSlice', 'Start showing metric at (example: 14:57 20150115)', {quote: true})},
{text: 'Summarize', handler: applyFuncToEachWithInput('summarize', 'Please enter a summary interval (examples: 10min, 1h, 7d)', {quote: true})},
{text: 'Hit Count', handler: applyFuncToEachWithInput('hitcount', 'Please enter a summary interval (examples: 10min, 1h, 7d)', {quote: true})}
]
Expand Down
49 changes: 46 additions & 3 deletions webapp/graphite/render/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import time

from graphite.logger import log
from graphite.render.attime import parseTimeOffset
from graphite.render.attime import parseTimeOffset, parseATTime

from graphite.events import models

Expand Down Expand Up @@ -2406,7 +2406,10 @@ def timeStack(requestContext, seriesList, timeShiftUnit, timeShiftStart, timeShi
if timeShiftUnit[0].isdigit():
timeShiftUnit = '-' + timeShiftUnit
delta = parseTimeOffset(timeShiftUnit)
series = seriesList[0] # if len(seriesList) > 1, they will all have the same pathExpression, which is all we care about.

# if len(seriesList) > 1, they will all have the same pathExpression, which is all we care about.
series = seriesList[0]

results = []
timeShiftStartint = int(timeShiftStart)
timeShiftEndint = int(timeShiftEnd)
Expand Down Expand Up @@ -2461,7 +2464,8 @@ def timeShift(requestContext, seriesList, timeShift, resetEnd=True):
myContext['endTime'] = requestContext['endTime'] + delta
results = []
if len(seriesList) > 0:
series = seriesList[0] # if len(seriesList) > 1, they will all have the same pathExpression, which is all we care about.
# if len(seriesList) > 1, they will all have the same pathExpression, which is all we care about.
series = seriesList[0]

for shiftedSeries in evaluateTarget(myContext, series.pathExpression):
shiftedSeries.name = 'timeShift(%s, %s)' % (shiftedSeries.name, timeShift)
Expand All @@ -2474,6 +2478,44 @@ def timeShift(requestContext, seriesList, timeShift, resetEnd=True):

return results


def timeSlice(requestContext, seriesList, startSliceAt, endSliceAt="now"):
"""
Takes one metric or a wildcard metric, followed by a quoted string with the
time to start the line and another quoted string with the time to end the line.
The start and end times are inclusive. See ``from / until`` in the render\_api_
for examples of time formats.
Useful for filtering out a part of a series of data from a wider range of
data.
Example:
.. code-block:: none
&target=timeSlice(network.core.port1,"00:00 20140101","11:59 20140630")
&target=timeSlice(network.core.port1,"12:00 20140630","now")
"""

results = []
start = time.mktime(parseATTime(startSliceAt).timetuple())
end = time.mktime(parseATTime(endSliceAt).timetuple())

for slicedSeries in seriesList:
slicedSeries.name = 'timeSlice(%s, %s, %s)' % (slicedSeries.name, int(start), int(end))

curr = time.mktime(requestContext["startTime"].timetuple())
for i, v in enumerate(slicedSeries):
if v is None or curr < start or curr > end:
slicedSeries[i] = None
curr += slicedSeries.step

results.append(slicedSeries)

return results


def constantLine(requestContext, value):
"""
Takes a float F.
Expand Down Expand Up @@ -3266,6 +3308,7 @@ def pieMinimum(requestContext, series):
'invert' : invert,
'timeStack': timeStack,
'timeShift': timeShift,
'timeSlice': timeSlice,
'summarize' : summarize,
'smartSummarize' : smartSummarize,
'hitcount' : hitcount,
Expand Down
24 changes: 24 additions & 0 deletions webapp/tests/test_functions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import copy
import math
import pytz
from datetime import datetime

from django.test import TestCase
from django.conf import settings
from mock import patch, call, MagicMock

from graphite.render.datalib import TimeSeries
Expand Down Expand Up @@ -375,3 +379,23 @@ def test_multiplySeriesWithWildcards(self):
]
results = functions.multiplySeriesWithWildcards({}, copy.deepcopy(seriesList1+seriesList2), 2,3)
self.assertEqual(results,expectedResult)

def test_timeSlice(self):
seriesList = [
# series starts at 60 seconds past the epoch and continues for 600 seconds (ten minutes)
# steps are every 60 seconds
TimeSeries('test.value',0,600,60,[None,1,2,3,None,5,6,None,7,8,9]),
]

# we're going to slice such that we only include minutes 3 to 8 (of 0 to 9)
expectedResult = [
TimeSeries('timeSlice(test.value, 180, 480)',0,600,60,[None,None,None,3,None,5,6,None,7,None,None])
]

results = functions.timeSlice({
'startTime': datetime(1970, 1, 1, 0, 0, 0, 0, pytz.timezone(settings.TIME_ZONE)),
'endTime': datetime(1970, 1, 1, 0, 9, 0, 0, pytz.timezone(settings.TIME_ZONE)),
'localOnly': False,
'data': [],
}, seriesList, '00:03 19700101', '00:08 19700101')
self.assertEqual(results, expectedResult)

0 comments on commit c73bb30

Please sign in to comment.