django-orchestra/orchestra/contrib/resources/aggregations.py

175 lines
5.6 KiB
Python
Raw Normal View History

import datetime
2015-04-01 15:49:21 +00:00
import decimal
import itertools
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
2015-07-27 12:55:35 +00:00
from orchestra.utils.python import AttrDict
from orchestra import plugins
2015-04-08 14:41:09 +00:00
class Aggregation(plugins.Plugin, metaclass=plugins.PluginMount):
""" filters and computes dataset usage """
2015-07-27 12:55:35 +00:00
aggregated_history = False
def filter(self, dataset):
""" Filter the dataset to get the relevant data according to the period """
raise NotImplementedError
def compute_usage(self, dataset):
""" given a dataset computes its usage according to the method (avg, sum, ...) """
raise NotImplementedError
2015-07-27 12:55:35 +00:00
def aggregate_history(self, dataset):
raise NotImplementedError
2015-04-08 14:41:09 +00:00
class Last(Aggregation):
2015-04-09 14:32:10 +00:00
""" Sum of the last value of all monitors """
name = 'last'
2015-04-01 15:49:21 +00:00
verbose_name = _("Last value")
2015-07-16 13:07:15 +00:00
def filter(self, dataset, date=None):
# dataset = dataset.order_by('object_id', '-id').distinct('monitor')
now = timezone.now()
epoch = now - datetime.timedelta(minutes=2)
dataset = dataset.filter( created_at__range=(epoch, now ))
2015-07-16 13:07:15 +00:00
if date is not None:
dataset = dataset.filter(created_at__lte=date)
return dataset
def compute_usage(self, dataset):
values = dataset.values_list('value', flat=True)
if values:
return sum(values)
return None
2015-07-27 12:55:35 +00:00
def aggregate_history(self, dataset):
prev_object_id = None
2016-07-15 08:41:38 +00:00
prev_object_repr = None
2015-07-27 12:55:35 +00:00
for mdata in dataset.order_by('object_id', 'created_at'):
object_id = mdata.object_id
if object_id != prev_object_id:
if prev_object_id is not None:
2016-07-15 08:41:38 +00:00
yield (prev_object_repr, datas)
2015-07-27 12:55:35 +00:00
datas = [mdata]
else:
datas.append(mdata)
prev_object_id = object_id
2016-07-15 08:41:38 +00:00
prev_object_repr = mdata.content_object_repr
2015-07-27 12:55:35 +00:00
if prev_object_id is not None:
2016-07-15 08:41:38 +00:00
yield (prev_object_repr, datas)
class MonthlySum(Last):
2015-04-09 14:32:10 +00:00
""" Monthly sum the values of all monitors """
name = 'monthly-sum'
verbose_name = _("Monthly Sum")
2015-07-27 12:55:35 +00:00
aggregated_history = True
2015-07-16 13:07:15 +00:00
def filter(self, dataset, date=None):
if date is None:
date = timezone.now().date()
return dataset.filter(
2015-07-16 13:07:15 +00:00
created_at__year=date.year,
created_at__month=date.month,
)
2015-07-16 13:07:15 +00:00
2015-07-27 12:55:35 +00:00
def aggregate_history(self, dataset):
prev = None
2015-07-27 12:55:35 +00:00
prev_object_id = None
datas = []
sink = AttrDict(object_id=-1, value=-1, content_object_repr='',
created_at=AttrDict(year=-1, month=-1))
for mdata in itertools.chain(dataset.order_by('object_id', 'created_at'), [sink]):
2015-07-27 12:55:35 +00:00
object_id = mdata.object_id
ymonth = (mdata.created_at.year, mdata.created_at.month)
if object_id != prev_object_id or ymonth != prev.ymonth:
2015-07-27 12:55:35 +00:00
if prev_object_id is not None:
data = AttrDict(
date=datetime.date(
year=prev.ymonth[0],
month=prev.ymonth[1],
day=1
),
value=current,
content_object_repr=prev.content_object_repr
)
datas.append(data)
2015-07-27 12:55:35 +00:00
current = mdata.value
else:
current += mdata.value
if object_id != prev_object_id:
if prev_object_id is not None:
2016-07-15 08:41:38 +00:00
yield (prev.content_object_repr, datas)
datas = []
prev = mdata
prev.ymonth = ymonth
2015-07-27 12:55:35 +00:00
prev_object_id = object_id
class MonthlyAvg(MonthlySum):
2015-04-09 14:32:10 +00:00
""" sum of the monthly averages of each monitor """
name = 'monthly-avg'
verbose_name = _("Monthly AVG")
2015-07-27 12:55:35 +00:00
aggregated_history = False
2015-07-16 13:07:15 +00:00
def get_epoch(self, date=None):
if date is None:
date = timezone.now().date()
return datetime.date(
2015-07-16 13:07:15 +00:00
year=date.year,
month=date.month,
day=1,
)
def compute_usage(self, dataset):
2015-04-03 10:14:45 +00:00
result = 0
2015-04-09 14:32:10 +00:00
has_result = False
aggregate = []
for object_id, dataset in dataset.order_by('created_at').group_by('object_id').items():
2015-04-09 14:32:10 +00:00
try:
last = dataset[-1]
except IndexError:
continue
2015-07-16 13:07:15 +00:00
epoch = self.get_epoch(date=last.created_at)
2015-04-09 14:32:10 +00:00
total = (last.created_at-epoch).total_seconds()
ini = epoch
current = 0
for mdata in dataset:
2015-04-09 14:32:10 +00:00
has_result = True
slot = (mdata.created_at-ini).total_seconds()
current += mdata.value * decimal.Decimal(str(slot/total))
ini = mdata.created_at
else:
result += current
2015-04-09 14:32:10 +00:00
if has_result:
2015-04-03 10:14:45 +00:00
return result
2015-04-09 14:32:10 +00:00
return None
2015-07-27 12:55:35 +00:00
def aggregate_history(self, dataset):
yield from super(MonthlySum, self).aggregate_history(dataset)
class Last10DaysAvg(MonthlyAvg):
2015-04-09 14:32:10 +00:00
""" sum of the last 10 days averages of each monitor """
name = 'last-10-days-avg'
verbose_name = _("Last 10 days AVG")
days = 10
2015-07-16 13:07:15 +00:00
def get_epoch(self, date=None):
if date is None:
date = timezone.now().date()
2015-07-16 13:07:15 +00:00
return date - datetime.timedelta(days=self.days)
2015-07-16 13:07:15 +00:00
def filter(self, dataset, date=None):
epoch = self.get_epoch(date=date)
dataset = dataset.filter(created_at__gt=epoch)
2015-07-16 13:07:15 +00:00
if date is not None:
dataset = dataset.filter(created_at__lte=date)
return dataset