# Copyright (C) The Arvados Authors. All rights reserved.
#
# SPDX-License-Identifier: AGPL-3.0
import json
import pkg_resources
from arvados._internal.report_template import ReportTemplate
class DygraphsChart(ReportTemplate):
"""Crunchstat report using dygraphs for charting.
"""
CSS = 'https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.css'
JSLIB = 'https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.js'
JSASSETS = ['synchronizer.js','dygraphs.js']
def __init__(self, label, summarizers, beforechart, afterchart):
super().__init__(label)
self.summarizers = summarizers
self.beforechart = beforechart
self.afterchart = afterchart
def html(self):
self.cards.extend(self.beforechart)
self.cards.append("""
Graph
""")
self.cards.extend(self.afterchart)
return super().html()
def js(self):
return '''
'''.format(
jslib=self.JSLIB,
chartdata=json.dumps(self.sections()),
jsassets='\n'.join([pkg_resources.resource_string('crunchstat_summary', jsa).decode('utf-8') for jsa in self.JSASSETS]))
def sections(self):
return [
{
'label': s.long_label(),
'charts': [
self.chartdata(s.label, s.tasks, stat)
for stat in (('cpu', ['user+sys__rate', 'user__rate', 'sys__rate']),
('mem', ['rss']),
('net:eth0', ['tx+rx__rate','rx__rate','tx__rate']),
('net:keep0', ['tx+rx__rate','rx__rate','tx__rate']),
('statfs', ['used', 'total']),
)
],
}
for s in self.summarizers]
def chartdata(self, label, tasks, stats):
'''For Crunch2, label is the name of container request,
tasks is the top level container and
stats is index by a tuple of (category, metric).
'''
return {
'data': self._collate_data(tasks, stats),
'options': {
'legend': 'always',
'connectSeparatedPoints': True,
'labels': ['elapsed'] + stats[1],
'includeZero': True,
'title': '{}: {}'.format(label, stats[0]) if label else stats[0],
},
}
def _collate_data(self, tasks, stats):
data = []
nulls = []
# uuid is category for crunch2
for uuid, task in tasks.items():
# All stats in a category are assumed to have the same time base and same number of samples
category = stats[0]
series_names = stats[1]
sn0 = series_names[0]
series = task.series[(category,sn0)]
for i in range(len(series)):
pt = series[i]
vals = [task.series[(category,stat)][i][1] for stat in series_names[1:]]
data.append([pt[0].total_seconds()] + nulls + [pt[1]] + vals)
nulls.append(None)
return sorted(data)
def style(self):
return '\n'.join((super().style(),
'\n'.format(self.CSS)))