Commit ea40ce87 authored by Patrick Godwin's avatar Patrick Godwin

add ability to serve multiple dashboard pages, overhaul config file layout

parent 2419730c
Pipeline #74694 passed with stages
in 1 minute and 41 seconds
......@@ -72,54 +72,62 @@ def static(file_):
@app.route("/")
def index():
@app.route("/<page>")
def dashboard(page='index'):
"""Route to serve a dashboard.
"""
config = dict(app.config)
static_dir = '../' if config['use_cgi'] else ''
if page != 'index':
static_dir += '../'
if 'type' in bottle.request.query:
config['dashboard']['type'] = bottle.request.query['type']
config['pages'][page]['type'] = bottle.request.query['type']
else:
config['dashboard']['type'] = 'online'
if config['dashboard']['type'] == 'online':
config['pages'][page]['type'] = 'online'
if config['pages'][page]['type'] == 'online':
if 'lookback' in bottle.request.query:
config['dashboard']['lookback'] = int(bottle.request.query['lookback'])
elif 'duration' in config['dashboard']: ### backwards compatibility
config['dashboard']['lookback'] = config['dashboard']['duration']
config['pages'][page]['lookback'] = int(bottle.request.query['lookback'])
if 'delay' in bottle.request.query:
config['dashboard']['delay'] = int(bottle.request.query['delay'])
elif 'gps' in config['dashboard'] and config['dashboard']['gps'] < 0: ### backwards compatibility
config['dashboard']['delay'] = - config['dashboard']['gps']
config['pages'][page]['delay'] = int(bottle.request.query['delay'])
else:
config['dashboard']['start'] = int(bottle.request.query['start'])
config['dashboard']['end'] = int(bottle.request.query['end'])
config['pages'][page]['start'] = int(bottle.request.query['start'])
config['pages'][page]['end'] = int(bottle.request.query['end'])
### find out whether query is for realtime or historical data
if config['dashboard']['type'] == 'online':
stop = int(aggregator.now() - config['dashboard']['delay'])
start = stop - config['dashboard']['lookback']
if config['pages'][page]['type'] == 'online':
stop = int(aggregator.now() - config['pages'][page]['delay'])
start = stop - config['pages'][page]['lookback']
refresh = 2000
else:
start = config['dashboard']['start']
stop = config['dashboard']['end']
start = config['pages'][page]['start']
stop = config['dashboard'][page]['end']
refresh = -1
### fill in plot section for page with plot/schema info
plots = config['pages'][page]['plots']
for plot in plots:
plot_name = plot['plot']
plot.update(config['plots'][plot_name])
plot['schema'] = config['schemas'][plot['schema']]
### generate html
yield bottle.template(
'dashboard.html',
static_dir=static_dir,
script_name=config['script_name'],
plots=config['plots'],
plot_defaults=config['plotly'] if 'plotly' in config else {},
plots=plots,
start=start,
stop=stop,
refresh=refresh,
lookback=config['dashboard']['lookback'],
delay=config['dashboard']['delay'],
query_type=config['dashboard']['type'],
dashboard_config=config['dashboard'],
lookback=config['pages'][page]['lookback'],
delay=config['pages'][page]['delay'],
query_type=config['pages'][page]['type'],
dashboard_config=config['navbar'],
page_config=config['pages'],
current_page=page,
)
......@@ -309,9 +317,9 @@ def serve_latest(measurement, start, end):
"""
query = parse_query(bottle.request.query)
tag = app.config['measurements'][measurement]['tag']
default_value = app.config['measurements'][measurement]['default']
transform = app.config['measurements'][measurement]['transform']
tag = app.config['schemas'][measurement]['tag']
default_value = app.config['schemas'][measurement]['default']
transform = app.config['schemas'][measurement]['transform']
y = []
### query for timeseries
......@@ -391,14 +399,15 @@ def serve_nagios(check):
dt = utils.duration_to_dt(duration)
### data settings
measurement = nagios_config['measurement']
column = nagios_config['column']
tags = nagios_config['tags'] if 'tags' in nagios_config else []
aggregate = nagios_config['aggregate']
schema = app.config['schemas'][check]
measurement = schema['measurement']
column = schema['column']
tags = schema['tags'] if 'tags' in schema else []
aggregate = schema['aggregate']
### alert settings
alert_type = nagios_config['alert_type']
alert_tags = utils.extract_alert_tags(nagios_config['alert_settings'])
alert_tags = utils.extract_alert_tags(schema)
### alert tracking
alert_values = []
......@@ -428,13 +437,13 @@ def serve_nagios(check):
if bad_status:
if alert_type == 'heartbeat':
text_status = "{num_tags} {alert_tag} more than {lookback} seconds behind".format(
alert_tag=nagios_config['alert_settings']['tag_type'],
alert_tag=nagios_config['alert_settings']['tag_key'],
num_tags=bad_status,
lookback=duration,
)
elif alert_type == 'threshold':
text_status = "{num_tags} {alert_tag} above {column} threshold = {threshold} {units} from gps times: {start} - {end}".format(
alert_tag=nagios_config['alert_settings']['tag_type'],
alert_tag=nagios_config['alert_settings']['tag_key'],
threshold=nagios_config['alert_settings']['threshold'],
units=nagios_config['alert_settings']['threshold_units'],
num_tags=bad_status,
......@@ -448,7 +457,7 @@ def serve_nagios(check):
text_status = "OK: Max delay: {delay} seconds".format(delay=max(alert_values))
elif alert_type == 'threshold':
text_status = "OK: No {alert_tag}s above {column} threshold = {threshold} {units} from gps times: {start} - {end}".format(
alert_tag=nagios_config['alert_settings']['tag_type'],
alert_tag=nagios_config['alert_settings']['tag_key'],
threshold=nagios_config['alert_settings']['threshold'],
units=nagios_config['alert_settings']['threshold_units'],
column=measurement,
......
......@@ -209,16 +209,16 @@ def status_to_nagios_response(text_status, bad_status):
}
def extract_alert_tags(alert_settings):
if 'tags' in alert_settings:
return alert_settings['tags']
def extract_alert_tags(schema):
if 'tags' in schema:
return schema['tags']
else:
tag_type = alert_settings['tag_type']
alert_tag_format = alert_settings['tag_format']
tag_type = schema['tag_key']
alert_tag_format = schema['tag_format']
if 'digit' in alert_tag_format:
num_digits = int(alert_tag_format[0])
num_tags = int(alert_settings['num_tags'])
tag_start = int(alert_settings['tag_start']) if 'tag_start' in alert_settings else 0
num_tags = int(schema['num_tags'])
tag_start = int(schema['tag_start']) if 'tag_start' in schema else 0
return [(tag_type, str(tag_num).zfill(num_digits)) for tag_num in range(tag_start, tag_start+num_tags)]
else:
raise ValueError('{} tag format not recognized'.format(alert_tag_format))
......
......@@ -707,6 +707,7 @@ class MultiSchema extends _TimePlot{
this.stream = new Stream2D(this.measurement, this.schema, this.segment, this.data_options, this.refresh_interval, this.update, this.delay);
delete this.url_params;
delete this.schema.dt;
delete this.schema.measurement;
this.script_name = script_name;
for (var key in this.schema) {
// Set a custom base URL for each schema measurement
......@@ -788,6 +789,7 @@ class MultiAxis extends _TimePlot{
this.stream = new Stream2D(this.measurement, this.schema, this.segment, this.data_options, this.refresh_interval, this.update, this.delay);
delete this.url_params;
delete this.schema.dt;
delete this.schema.measurement;
var axis = 1;
for (var key in this.schema) {
// Create the info for each yaxis supplied
......
......@@ -14,6 +14,21 @@
<b-collapse is-nav id="nav_collapse">
<ul class="navbar-nav mr-auto">
<!-- add pages -->
% if 'pages' in dashboard_config:
% if current_page != 'index':
% script_name = '../' + script_name
% end
% for page in pages:
% if page == 'index':
% url = script_name if script_name[-1] != '/' else script_name[:-1]
% else:
% url = script_name + page
% end
<li><a class="nav-link mt-0" href="{{ url }}">{{ page_config[page]['title'] }}</a></li>
% end
% end
<!-- add tabs -->
% for tab in tabs:
<li><a class="nav-link mt-0" href="{{ tab['url'] }}">{{ tab['name'] }}</a></li>
......@@ -44,7 +59,7 @@
class ="m-lg-2"
name="livecharts{{ plot['title'].replace(' ', '_').lower() }}"
href="#"
:checked={{ 'true' if plot['value'] == 'checked' else 'false' }}
:checked={{ 'true' if plot['visible'] else 'false' }}
@click="addItem(plots[{{ i }}])"
>
{{ plot['title'] }}
......
% import json
% if current_page != 'index':
% script_name = '../' + script_name
% end
<script>
document.body.onkeydown = function(e) {
if (e.keyCode == 32) {
......@@ -219,7 +223,7 @@
grid.type = plot.type;
grid.i = idx;
grid.divname = 'plot'+idx;
if (plot.value === 'checked') {
if (plot.visible) {
if (!('y' in grid)) {
grid.y = this.ySpace;
};
......@@ -243,19 +247,33 @@
var options = ('options' in plot) ? plot.options : {};
var segment = {"start": {{ start }}, "stop": {{ stop }} };
if ('layout' in this.plotDefaults) {
plotLayout = update_config_object(plotLayout, this.plotDefaults['layout']);
} if ('data_options' in this.plotDefaults) {
dataOptions = update_config_object(dataOptions, this.plotDefaults['data_options']);
} if ('options' in this.plotDefaults) {
options = update_config_object(options, this.plotDefaults['options']);
if ('default' in this.plotDefaults) {
if ('layout' in this.plotDefaults.default) {
plotLayout = update_config_object(plotLayout, this.plotDefaults['default']['layout']);
} if ('data_options' in this.plotDefaults.default) {
dataOptions = update_config_object(dataOptions, this.plotDefaults['default']['data_options']);
} if ('options' in this.plotDefaults.default) {
options = update_config_object(options, this.plotDefaults['default']['options']);
}
}
if (plot.type in this.plotDefaults) {
if ('layout' in this.plotDefaults[plot.type]) {
plotLayout = update_config_object(plotLayout, this.plotDefaults[plot.type]['layout']);
} if ('data_options' in this.plotDefaults[plot.type]) {
dataOptions = update_config_object(dataOptions, this.plotDefaults[plot.type]['data_options']);
} if ('options' in this.plotDefaults[plot.type]) {
options = update_config_object(options, this.plotDefaults[plot.type]['options']);
}
}
if ('schema' in plot) {
plot.schema = update_config_object(plot.schema, plot.settings);
}
// create the plot
var thisplot = new (plotFactory.get(plot.type))(
grid.divname, // div name for the plot
plot.title, // plot title stored for regeneration
plot.measurement, // name of measurement to query
plot.schema.measurement, // name of measurement to query
plot.schema, // schema for retrieving data
'{{ script_name }}', // script name (hack to deal with cgi/apache)
segment, // initial data segment
......@@ -268,7 +286,7 @@
);
// populate plot and push
if (plot.value === 'checked') {
if (plot.visible) {
thisplot.populate();
}
this.plots.push(thisplot);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment