luci-app-statistics: convert graph rendering to client side js
This conversion requires cgi-io >= version 17 and uhttpd version >= 2020-02-12 to function properly. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
1d47f0c1a9
commit
9680fdea9e
95 changed files with 15542 additions and 14612 deletions
|
@ -0,0 +1,717 @@
|
||||||
|
'use strict';
|
||||||
|
'require fs';
|
||||||
|
'require uci';
|
||||||
|
'require tools.prng as random';
|
||||||
|
|
||||||
|
function subst(str, val) {
|
||||||
|
return str.replace(/%(H|pn|pi|dt|di|ds)/g, function(m, p1) {
|
||||||
|
switch (p1) {
|
||||||
|
case 'H': return val.host || '';
|
||||||
|
case 'pn': return val.plugin || '';
|
||||||
|
case 'pi': return val.pinst || '';
|
||||||
|
case 'dt': return val.dtype || '';
|
||||||
|
case 'di': return val.dinst || '';
|
||||||
|
case 'ds': return val.dsrc || '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var i18n = L.Class.singleton({
|
||||||
|
title: function(host, plugin, pinst, dtype, dinst, user_title) {
|
||||||
|
var title = user_title || 'p=%s/pi=%s/dt=%s/di=%s'.format(
|
||||||
|
plugin,
|
||||||
|
pinst || '(nil)',
|
||||||
|
dtype || '(nil)',
|
||||||
|
dinst || '(nil)'
|
||||||
|
);
|
||||||
|
|
||||||
|
return subst(title, {
|
||||||
|
host: host,
|
||||||
|
plugin: plugin,
|
||||||
|
pinst: pinst,
|
||||||
|
dtype: dtype,
|
||||||
|
dinst: dinst
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
label: function(host, plugin, pinst, dtype, dinst, user_label) {
|
||||||
|
var label = user_label || 'dt=%s/%di=%s'.format(
|
||||||
|
dtype || '(nil)',
|
||||||
|
dinst || '(nil)'
|
||||||
|
);
|
||||||
|
|
||||||
|
return subst(label, {
|
||||||
|
host: host,
|
||||||
|
plugin: plugin,
|
||||||
|
pinst: pinst,
|
||||||
|
dtype: dtype,
|
||||||
|
dinst: dinst
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
ds: function(host, source) {
|
||||||
|
var label = source.title || 'dt=%s/di=%s/ds=%s'.format(
|
||||||
|
source.type || '(nil)',
|
||||||
|
source.instance || '(nil)',
|
||||||
|
source.ds || '(nil)'
|
||||||
|
);
|
||||||
|
|
||||||
|
return subst(label, {
|
||||||
|
host: host,
|
||||||
|
dtype: source.type,
|
||||||
|
dinst: source.instance,
|
||||||
|
dsrc: source.ds
|
||||||
|
}).replace(/:/g, '\\:');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var colors = L.Class.singleton({
|
||||||
|
fromString: function(s) {
|
||||||
|
if (typeof(s) != 'string' || !s.match(/^[0-9a-fA-F]{6}$/))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return [
|
||||||
|
parseInt(s.substring(0, 2), 16),
|
||||||
|
parseInt(s.substring(2, 4), 16),
|
||||||
|
parseInt(s.substring(4, 6), 16)
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
asString: function(c) {
|
||||||
|
if (!Array.isArray(c) || c.length != 3)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return '%02x%02x%02x'.format(c[0], c[1], c[2]);
|
||||||
|
},
|
||||||
|
|
||||||
|
defined: function(i) {
|
||||||
|
var t = [
|
||||||
|
[230, 25, 75],
|
||||||
|
[245, 130, 48],
|
||||||
|
[255, 225, 25],
|
||||||
|
[60, 180, 75],
|
||||||
|
[70, 240, 240],
|
||||||
|
[0, 130, 200],
|
||||||
|
[0, 0, 128],
|
||||||
|
[170, 110, 40]
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.asString(t[i % t.length]);
|
||||||
|
},
|
||||||
|
|
||||||
|
random: function() {
|
||||||
|
var r = random.get(255),
|
||||||
|
g = random.get(255),
|
||||||
|
min = 0, max = 255;
|
||||||
|
|
||||||
|
if (r + g < 255)
|
||||||
|
min = 255 - r - g;
|
||||||
|
else
|
||||||
|
max = 511 - r - g;
|
||||||
|
|
||||||
|
var b = min + Math.floor(random.get() * (max - min));
|
||||||
|
|
||||||
|
return [ r, g, b ];
|
||||||
|
},
|
||||||
|
|
||||||
|
faded: function(fg, bg, alpha) {
|
||||||
|
fg = this.fromString(fg) || (this.asString(fg) ? fg : null);
|
||||||
|
bg = this.fromString(bg) || (this.asString(bg) ? bg : [255, 255, 255]);
|
||||||
|
alpha = !isNaN(alpha) ? +alpha : 0.25;
|
||||||
|
|
||||||
|
if (!fg)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return [
|
||||||
|
(alpha * fg[0]) + ((1.0 - alpha) * bg[0]),
|
||||||
|
(alpha * fg[1]) + ((1.0 - alpha) * bg[1]),
|
||||||
|
(alpha * fg[2]) + ((1.0 - alpha) * bg[2])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var rrdtree = {},
|
||||||
|
graphdefs = {};
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
__init__: function() {
|
||||||
|
this.opts = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
load: function() {
|
||||||
|
return Promise.all([
|
||||||
|
L.resolveDefault(fs.list('/www' + L.resource('statistics/rrdtool/definitions')), []),
|
||||||
|
fs.trimmed('/proc/sys/kernel/hostname'),
|
||||||
|
uci.load('luci_statistics')
|
||||||
|
]).then(L.bind(function(data) {
|
||||||
|
var definitions = data[0],
|
||||||
|
hostname = data[1];
|
||||||
|
|
||||||
|
this.opts.host = uci.get('luci_statistics', 'collectd', 'Hostname') || hostname;
|
||||||
|
this.opts.timespan = uci.get('luci_statistics', 'rrdtool', 'default_timespan') || 900;
|
||||||
|
this.opts.width = uci.get('luci_statistics', 'rrdtool', 'image_width') || 400;
|
||||||
|
this.opts.height = uci.get('luci_statistics', 'rrdtool', 'image_height') || 100;
|
||||||
|
this.opts.rrdpath = (uci.get('luci_statistics', 'collectd_rrdtool', 'DataDir') || '/tmp/rrd').replace(/\/$/, '');
|
||||||
|
this.opts.rrasingle = (uci.get('luci_statistics', 'collectd_rrdtool', 'RRASingle') == '1');
|
||||||
|
this.opts.rramax = (uci.get('luci_statistics', 'collectd_rrdtool', 'RRAMax') == '1');
|
||||||
|
|
||||||
|
graphdefs = {};
|
||||||
|
|
||||||
|
var tasks = [ this.scan() ];
|
||||||
|
|
||||||
|
for (var i = 0; i < definitions.length; i++) {
|
||||||
|
var m = definitions[i].name.match(/^(.+)\.js$/);
|
||||||
|
|
||||||
|
if (definitions[i].type != 'file' || m == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tasks.push(L.require('statistics.rrdtool.definitions.' + m[1]).then(L.bind(function(name, def) {
|
||||||
|
graphdefs[name] = def;
|
||||||
|
}, this, m[1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(tasks);
|
||||||
|
}, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
ls: function() {
|
||||||
|
var dir = this.opts.rrdpath;
|
||||||
|
|
||||||
|
return L.resolveDefault(fs.list(dir), []).then(function(entries) {
|
||||||
|
var tasks = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < entries.length; i++) {
|
||||||
|
if (entries[i].type != 'directory')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tasks.push(L.resolveDefault(fs.list(dir + '/' + entries[i].name), []).then(L.bind(function(entries) {
|
||||||
|
var tasks = [];
|
||||||
|
|
||||||
|
for (var j = 0; j < entries.length; j++) {
|
||||||
|
if (entries[j].type != 'directory')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tasks.push(L.resolveDefault(fs.list(dir + '/' + this.name + '/' + entries[j].name), []).then(L.bind(function(entries) {
|
||||||
|
return Object.assign(this, {
|
||||||
|
entries: entries.filter(function(e) {
|
||||||
|
return e.type == 'file' && e.name.match(/\.rrd$/);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}, entries[j])));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(tasks).then(L.bind(function(entries) {
|
||||||
|
return Object.assign(this, {
|
||||||
|
entries: entries
|
||||||
|
});
|
||||||
|
}, this));
|
||||||
|
}, entries[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(tasks);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
scan: function() {
|
||||||
|
return this.ls().then(L.bind(function(entries) {
|
||||||
|
rrdtree = {};
|
||||||
|
|
||||||
|
for (var i = 0; i < entries.length; i++) {
|
||||||
|
var hostInstance = entries[i].name;
|
||||||
|
|
||||||
|
rrdtree[hostInstance] = rrdtree[hostInstance] || {};
|
||||||
|
|
||||||
|
for (var j = 0; j < entries[i].entries.length; j++) {
|
||||||
|
var m = entries[i].entries[j].name.match(/^([^-]+)(?:-(.+))?$/);
|
||||||
|
|
||||||
|
if (!m)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var pluginName = m[1],
|
||||||
|
pluginInstance = m[2] || '';
|
||||||
|
|
||||||
|
rrdtree[hostInstance][pluginName] = rrdtree[hostInstance][pluginName] || {};
|
||||||
|
rrdtree[hostInstance][pluginName][pluginInstance] = rrdtree[hostInstance][pluginName][pluginInstance] || {};
|
||||||
|
|
||||||
|
for (var k = 0; k < entries[i].entries[j].entries.length; k++) {
|
||||||
|
var m = entries[i].entries[j].entries[k].name.match(/^([^-]+)(?:-(.+))?\.rrd$/);
|
||||||
|
|
||||||
|
if (!m)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var dataType = m[1],
|
||||||
|
dataInstance = m[2] || '';
|
||||||
|
|
||||||
|
rrdtree[hostInstance][pluginName][pluginInstance][dataType] = rrdtree[hostInstance][pluginName][pluginInstance][dataType] || [];
|
||||||
|
rrdtree[hostInstance][pluginName][pluginInstance][dataType].push(dataInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
hostInstances: function() {
|
||||||
|
return Object.keys(rrdtree).sort();
|
||||||
|
},
|
||||||
|
|
||||||
|
pluginNames: function(hostInstance) {
|
||||||
|
return Object.keys(rrdtree[hostInstance] || {}).sort();
|
||||||
|
},
|
||||||
|
|
||||||
|
pluginInstances: function(hostInstance, pluginName) {
|
||||||
|
return Object.keys((rrdtree[hostInstance] || {})[pluginName] || {}).sort();
|
||||||
|
},
|
||||||
|
|
||||||
|
dataTypes: function(hostInstance, pluginName, pluginInstance) {
|
||||||
|
return Object.keys(((rrdtree[hostInstance] || {})[pluginName] || {})[pluginInstance] || {}).sort();
|
||||||
|
},
|
||||||
|
|
||||||
|
dataInstances: function(hostInstance, pluginName, pluginInstance, dataType) {
|
||||||
|
return ((((rrdtree[hostInstance] || {})[pluginName] || {})[pluginInstance] || {})[dataType] || []).sort();
|
||||||
|
},
|
||||||
|
|
||||||
|
pluginTitle: function(pluginName) {
|
||||||
|
var def = graphdefs[pluginName];
|
||||||
|
return (def ? def.title : null) || pluginName;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasDefinition: function(pluginName) {
|
||||||
|
return (graphdefs[pluginName] != null);
|
||||||
|
},
|
||||||
|
|
||||||
|
_mkpath: function(host, plugin, plugin_instance, dtype, data_instance) {
|
||||||
|
var path = host + '/' + plugin;
|
||||||
|
|
||||||
|
if (plugin_instance != null && plugin_instance != '')
|
||||||
|
path += '-' + plugin_instance;
|
||||||
|
|
||||||
|
path += '/' + dtype;
|
||||||
|
|
||||||
|
if (data_instance != null && data_instance != '')
|
||||||
|
path += '-' + data_instance;
|
||||||
|
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
|
||||||
|
mkrrdpath: function(/* ... */) {
|
||||||
|
return '%s/%s.rrd'.format(
|
||||||
|
this.opts.rrdpath,
|
||||||
|
this._mkpath.apply(this, arguments)
|
||||||
|
).replace(/[\\:]/g, '\\$&');
|
||||||
|
},
|
||||||
|
|
||||||
|
_forcelol: function(list) {
|
||||||
|
return L.isObject(list[0]) ? list : [ list ];
|
||||||
|
},
|
||||||
|
|
||||||
|
_rrdtool: function(def, rrd, timespan, width, height) {
|
||||||
|
var cmdline = [
|
||||||
|
'graph', '-', '-a', 'PNG',
|
||||||
|
'-s', 'NOW-%s'.format(timespan || this.opts.timespan),
|
||||||
|
'-e', 'NOW-60',
|
||||||
|
'-w', width || this.opts.width,
|
||||||
|
'-h', height || this.opts.height
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < def.length; i++) {
|
||||||
|
var opt = String(def[i]);
|
||||||
|
|
||||||
|
if (rrd)
|
||||||
|
opt = opt.replace(/\{file\}/g, rrd);
|
||||||
|
|
||||||
|
cmdline.push(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.exec_direct('/usr/bin/rrdtool', cmdline, 'blob', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_generic: function(opts, host, plugin, plugin_instance, dtype, index) {
|
||||||
|
var defs = [],
|
||||||
|
gopts = this.opts,
|
||||||
|
_args = [],
|
||||||
|
_sources = [],
|
||||||
|
_stack_neg = [],
|
||||||
|
_stack_pos = [],
|
||||||
|
_longest_name = 0,
|
||||||
|
_has_totals = false;
|
||||||
|
|
||||||
|
function __def(source) {
|
||||||
|
var inst = source.sname,
|
||||||
|
rrd = source.rrd.replace(/[\\:]/g, '\\$&'),
|
||||||
|
ds = source.ds || 'value';
|
||||||
|
|
||||||
|
_args.push(
|
||||||
|
'DEF:%s_avg_raw=%s:%s:AVERAGE'.format(inst, rrd, ds),
|
||||||
|
'CDEF:%s_avg=%s_avg_raw,%s'.format(inst, inst, source.transform_rpn)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!gopts.rrasingle)
|
||||||
|
_args.push(
|
||||||
|
'DEF:%s_min_raw=%s:%s:MIN'.format(inst, rrd, ds),
|
||||||
|
'CDEF:%s_min=%s_min_raw,%s'.format(inst, inst, source.transform_rpn),
|
||||||
|
'DEF:%s_max_raw=%s:%s:MAX'.format(inst, rrd, ds),
|
||||||
|
'CDEF:%s_max=%s_max_raw,%s'.format(inst, inst, source.transform_rpn)
|
||||||
|
);
|
||||||
|
|
||||||
|
_args.push(
|
||||||
|
'CDEF:%s_nnl=%s_avg,UN,0,%s_avg,IF'.format(inst, inst, inst)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __cdef(source) {
|
||||||
|
var prev;
|
||||||
|
|
||||||
|
if (source.flip)
|
||||||
|
prev = _stack_neg[_stack_neg.length - 1];
|
||||||
|
else
|
||||||
|
prev = _stack_pos[_stack_pos.length - 1];
|
||||||
|
|
||||||
|
/* is first source in stack or overlay source: source_stk = source_nnl */
|
||||||
|
if (prev == null || source.overlay) {
|
||||||
|
/* create cdef statement for cumulative stack (no NaNs) and also
|
||||||
|
for display (preserving NaN where no points should be displayed) */
|
||||||
|
if (gopts.rrasingle || !gopts.rramax)
|
||||||
|
_args.push(
|
||||||
|
'CDEF:%s_stk=%s_nnl'.format(source.sname, source.sname),
|
||||||
|
'CDEF:%s_plot=%s_avg'.format(source.sname, source.sname)
|
||||||
|
);
|
||||||
|
else
|
||||||
|
_args.push(
|
||||||
|
'CDEF:%s_stk=%s_nnl'.format(source.sname, source.sname),
|
||||||
|
'CDEF:%s_plot=%s_max'.format(source.sname, source.sname)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/* is subsequent source without overlay: source_stk = source_nnl + previous_stk */
|
||||||
|
else {
|
||||||
|
/* create cdef statement */
|
||||||
|
if (gopts.rrasingle || !gopts.rramax)
|
||||||
|
_args.push(
|
||||||
|
'CDEF:%s_stk=%s_nnl,%s_stk,+'.format(source.sname, source.sname, prev),
|
||||||
|
'CDEF:%s_plot=%s_avg,%s_stk,+'.format(source.sname, source.sname, prev)
|
||||||
|
);
|
||||||
|
else
|
||||||
|
_args.push(
|
||||||
|
'CDEF:%s_stk=%s_nnl,%s_stk,+'.format(source.sname, source.sname, prev),
|
||||||
|
'CDEF:%s_plot=%s_max,%s_stk,+'.format(source.sname, source.sname, prev)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create multiply by minus one cdef if flip is enabled */
|
||||||
|
if (source.flip) {
|
||||||
|
_args.push('CDEF:%s_neg=%s_plot,-1,*'.format(source.sname, source.sname));
|
||||||
|
|
||||||
|
/* push to negative stack if overlay is disabled */
|
||||||
|
if (!source.overlay)
|
||||||
|
_stack_neg.push(source.sname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no flipping, push to positive stack if overlay is disabled */
|
||||||
|
else if (!source.overlay) {
|
||||||
|
/* push to positive stack */
|
||||||
|
_stack_pos.push(source.sname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate total amount of data if requested */
|
||||||
|
if (source.total)
|
||||||
|
_args.push(
|
||||||
|
'CDEF:%s_avg_sample=%s_avg,UN,0,%s_avg,IF,sample_len,*'.format(source.sname, source.sname, source.sname),
|
||||||
|
'CDEF:%s_avg_sum=PREV,UN,0,PREV,IF,%s_avg_sample,+'.format(source.sname, source.sname, source.sname)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local helper: create cdefs required for calculating total values */
|
||||||
|
function __cdef_totals() {
|
||||||
|
if (_has_totals)
|
||||||
|
_args.push(
|
||||||
|
'CDEF:mytime=%s_avg,TIME,TIME,IF'.format(_sources[0].sname),
|
||||||
|
'CDEF:sample_len_raw=mytime,PREV(mytime),-',
|
||||||
|
'CDEF:sample_len=sample_len_raw,UN,0,sample_len_raw,IF'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local helper: create line and area statements */
|
||||||
|
function __line(source) {
|
||||||
|
var line_color, area_color, legend, variable;
|
||||||
|
|
||||||
|
/* find colors: try source, then opts.colors; fall back to random color */
|
||||||
|
if (typeof(source.color) == 'string') {
|
||||||
|
line_color = source.color;
|
||||||
|
area_color = colors.fromString(line_color);
|
||||||
|
}
|
||||||
|
else if (typeof(opts.colors[source.name.replace(/\W/g, '_')]) == 'string') {
|
||||||
|
line_color = opts.colors[source.name.replace(/\W/g, '_')];
|
||||||
|
area_color = colors.fromString(line_color);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
area_color = colors.random();
|
||||||
|
line_color = colors.asString(area_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* derive area background color from line color */
|
||||||
|
area_color = colors.asString(colors.faded(area_color));
|
||||||
|
|
||||||
|
/* choose source_plot or source_neg variable depending on flip state */
|
||||||
|
variable = source.flip ? 'neg' : 'plot';
|
||||||
|
|
||||||
|
/* create legend */
|
||||||
|
legend = '%%-%us'.format(_longest_name).format(source.title);
|
||||||
|
|
||||||
|
/* create area is not disabled */
|
||||||
|
if (!source.noarea)
|
||||||
|
_args.push('AREA:%s_%s#%s'.format(source.sname, variable, area_color));
|
||||||
|
|
||||||
|
/* create line statement */
|
||||||
|
_args.push('LINE%d:%s_%s#%s:%s'.format(
|
||||||
|
source.width || (source.noarea ? 2 : 1),
|
||||||
|
source.sname, variable, line_color, legend
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local helper: create gprint statements */
|
||||||
|
function __gprint(source) {
|
||||||
|
var numfmt = opts.number_format || '%6.1lf',
|
||||||
|
totfmt = opts.totals_format || '%5.1lf%s';
|
||||||
|
|
||||||
|
/* don't include MIN if rrasingle is enabled */
|
||||||
|
if (!gopts.rrasingle)
|
||||||
|
_args.push('GPRINT:%s_min:MIN:\tMin\\: %s'.format(source.sname, numfmt));
|
||||||
|
|
||||||
|
/* always include AVERAGE */
|
||||||
|
_args.push('GPRINT:%s_avg:AVERAGE:\tAvg\\: %s'.format(source.sname, numfmt));
|
||||||
|
|
||||||
|
/* don't include MAX if rrasingle is enabled */
|
||||||
|
if (!gopts.rrasingle)
|
||||||
|
_args.push('GPRINT:%s_max:MAX:\tMax\\: %s'.format(source.sname, numfmt));
|
||||||
|
|
||||||
|
/* include total count if requested else include LAST */
|
||||||
|
if (source.total)
|
||||||
|
_args.push('GPRINT:%s_avg_sum:LAST:(ca. %s Total)\\l'.format(source.sname, totfmt));
|
||||||
|
else
|
||||||
|
_args.push('GPRINT:%s_avg:LAST:\tLast\\: %s\\l'.format(source.sname, numfmt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find all data sources
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* find data types */
|
||||||
|
var data_types = dtype ? [ dtype ] : (opts.data.types || []);
|
||||||
|
|
||||||
|
if (!(dtype || opts.data.types)) {
|
||||||
|
if (L.isObject(opts.data.instances))
|
||||||
|
data_types.push.apply(data_types, Object.keys(opts.data.instances));
|
||||||
|
else if (L.isObject(opts.data.sources))
|
||||||
|
data_types.push.apply(data_types, Object.keys(opts.data.sources));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate over data types */
|
||||||
|
for (var i = 0; i < data_types.length; i++) {
|
||||||
|
/* find instances */
|
||||||
|
var data_instances;
|
||||||
|
|
||||||
|
if (!opts.per_instance) {
|
||||||
|
if (L.isObject(opts.data.instances) && Array.isArray(opts.data.instances[data_types[i]]))
|
||||||
|
data_instances = opts.data.instances[data_types[i]];
|
||||||
|
else
|
||||||
|
data_instances = this.dataInstances(host, plugin, plugin_instance, data_types[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(data_instances) || data_instances.length == 0)
|
||||||
|
data_instances = [ '' ];
|
||||||
|
|
||||||
|
/* iterate over data instances */
|
||||||
|
for (var j = 0; j < data_instances.length; j++) {
|
||||||
|
/* construct combined data type / instance name */
|
||||||
|
var dname = data_types[i];
|
||||||
|
|
||||||
|
if (data_instances[j].length)
|
||||||
|
dname += '_' + data_instances[j];
|
||||||
|
|
||||||
|
/* find sources */
|
||||||
|
var data_sources = [ 'value' ];
|
||||||
|
|
||||||
|
if (L.isObject(opts.data.sources)) {
|
||||||
|
if (Array.isArray(opts.data.sources[dname]))
|
||||||
|
data_sources = opts.data.sources[dname];
|
||||||
|
else if (Array.isArray(opts.data.sources[data_types[i]]))
|
||||||
|
data_sources = opts.data.sources[data_types[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate over data sources */
|
||||||
|
for (var k = 0; k < data_sources.length; k++) {
|
||||||
|
var dsname = data_types[i] + '_' + data_instances[j].replace(/\W/g, '_') + '_' + data_sources[k],
|
||||||
|
altname = data_types[i] + '__' + data_sources[k];
|
||||||
|
|
||||||
|
/* find datasource options */
|
||||||
|
var dopts = {};
|
||||||
|
|
||||||
|
if (L.isObject(opts.data.options)) {
|
||||||
|
if (L.isObject(opts.data.options[dsname]))
|
||||||
|
dopts = opts.data.options[dsname];
|
||||||
|
else if (L.isObject(opts.data.options[altname]))
|
||||||
|
dopts = opts.data.options[altname];
|
||||||
|
else if (L.isObject(opts.data.options[dname]))
|
||||||
|
dopts = opts.data.options[dname];
|
||||||
|
else if (L.isObject(opts.data.options[data_types[i]]))
|
||||||
|
dopts = opts.data.options[data_types[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store values */
|
||||||
|
var source = {
|
||||||
|
rrd: dopts.rrd || this.mkrrdpath(host, plugin, plugin_instance, data_types[i], data_instances[j]),
|
||||||
|
color: dopts.color || colors.asString(colors.random()),
|
||||||
|
flip: dopts.flip || false,
|
||||||
|
total: dopts.total || false,
|
||||||
|
overlay: dopts.overlay || false,
|
||||||
|
transform_rpn: dopts.transform_rpn || '0,+',
|
||||||
|
noarea: dopts.noarea || false,
|
||||||
|
title: dopts.title || null,
|
||||||
|
weight: dopts.weight || (dopts.negweight ? -+data_instances[j] : null) || (dopts.posweight ? +data_instances[j] : null) || null,
|
||||||
|
ds: data_sources[j],
|
||||||
|
type: data_types[i],
|
||||||
|
instance: data_instances[j],
|
||||||
|
index: _sources.length + 1,
|
||||||
|
sname: String(_sources.length + 1) + data_types[i]
|
||||||
|
};
|
||||||
|
|
||||||
|
_sources.push(source);
|
||||||
|
|
||||||
|
/* generate datasource title */
|
||||||
|
source.title = i18n.ds(host, source);
|
||||||
|
|
||||||
|
/* find longest name */
|
||||||
|
_longest_name = Math.max(_longest_name, source.title.length);
|
||||||
|
|
||||||
|
/* has totals? */
|
||||||
|
if (source.total)
|
||||||
|
_has_totals = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* construct diagrams
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* if per_instance is enabled then find all instances from the first datasource in diagram */
|
||||||
|
/* if per_instance is disabled then use an empty pseudo instance and use model provided values */
|
||||||
|
var instances = [ '' ];
|
||||||
|
|
||||||
|
if (opts.per_instance)
|
||||||
|
instances = this.dataInstances(host, plugin, plugin_instance, _sources[0].type);
|
||||||
|
|
||||||
|
/* iterate over instances */
|
||||||
|
for (var i = 0; i < instances.length; i++) {
|
||||||
|
/* store title and vlabel */
|
||||||
|
_args.push(
|
||||||
|
'-t', i18n.title(host, plugin, plugin_instance, _sources[0].type, instances[i], opts.title),
|
||||||
|
'-v', i18n.label(host, plugin, plugin_instance, _sources[0].type, instances[i], opts.vlabel)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (opts.y_max)
|
||||||
|
_args.push('-u', String(opts.y_max));
|
||||||
|
|
||||||
|
if (opts.y_min)
|
||||||
|
_args.push('-l', String(opts.y_min));
|
||||||
|
|
||||||
|
if (opts.units_exponent)
|
||||||
|
_args.push('-X', String(opts.units_exponent));
|
||||||
|
|
||||||
|
if (opts.alt_autoscale)
|
||||||
|
_args.push('-A');
|
||||||
|
|
||||||
|
if (opts.alt_autoscale_max)
|
||||||
|
_args.push('-M');
|
||||||
|
|
||||||
|
/* store additional rrd options */
|
||||||
|
if (Array.isArray(opts.rrdopts))
|
||||||
|
for (var j = 0; j < opts.rrdopts.length; j++)
|
||||||
|
_args.push(String(opts.rrdopts[j]));
|
||||||
|
|
||||||
|
/* sort sources */
|
||||||
|
_sources.sort(function(a, b) {
|
||||||
|
var x = a.weight || a.index || 0,
|
||||||
|
y = b.weight || b.index || 0;
|
||||||
|
|
||||||
|
return +x < +y;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* define colors in order */
|
||||||
|
if (opts.ordercolor)
|
||||||
|
for (var j = 0; j < _sources.length; j++)
|
||||||
|
_sources[j].color = colors.defined(j);
|
||||||
|
|
||||||
|
/* create DEF statements for each instance */
|
||||||
|
for (var j = 0; j < _sources.length; j++) {
|
||||||
|
/* fixup properties for per instance mode... */
|
||||||
|
if (opts.per_instance) {
|
||||||
|
_sources[j].instance = instances[i];
|
||||||
|
_sources[j].rrd = this.mkrrdpath(host, plugin, plugin_instance, _sources[j].type, instances[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
__def(_sources[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create CDEF required for calculating totals */
|
||||||
|
__cdef_totals();
|
||||||
|
|
||||||
|
/* create CDEF statements for each instance in reversed order */
|
||||||
|
for (var j = _sources.length - 1; j >= 0; j--)
|
||||||
|
__cdef(_sources[j]);
|
||||||
|
|
||||||
|
/* create LINE1, AREA and GPRINT statements for each instance */
|
||||||
|
for (var j = 0; j < _sources.length; j++) {
|
||||||
|
__line(_sources[j]);
|
||||||
|
__gprint(_sources[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* push arg stack to definition list */
|
||||||
|
defs.push(_args);
|
||||||
|
|
||||||
|
/* reset stacks */
|
||||||
|
_args = [];
|
||||||
|
_stack_pos = [];
|
||||||
|
_stack_neg = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return defs;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(plugin, plugin_instance, is_index, hostname, timespan, width, height) {
|
||||||
|
var pngs = [];
|
||||||
|
|
||||||
|
/* check for a whole graph handler */
|
||||||
|
var def = graphdefs[plugin];
|
||||||
|
|
||||||
|
if (def && typeof(def.rrdargs) == 'function') {
|
||||||
|
/* temporary image matrix */
|
||||||
|
var _images = [];
|
||||||
|
|
||||||
|
/* get diagram definitions */
|
||||||
|
var optlist = this._forcelol(def.rrdargs(this, hostname, plugin, plugin_instance, null, is_index));
|
||||||
|
for (var i = 0; i < optlist.length; i++) {
|
||||||
|
var opt = optlist[i];
|
||||||
|
if (!is_index || !opt.detail) {
|
||||||
|
_images[i] = [];
|
||||||
|
|
||||||
|
/* get diagram definition instances */
|
||||||
|
var diagrams = this._generic(opt, hostname, plugin, plugin_instance, null, i);
|
||||||
|
|
||||||
|
/* render all diagrams */
|
||||||
|
for (var j = 0; j < diagrams.length; j++) {
|
||||||
|
/* exec */
|
||||||
|
_images[i][j] = this._rrdtool(diagrams[j], null, timespan, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember images - XXX: fixme (will cause probs with asymmetric data) */
|
||||||
|
for (var y = 0; y < _images[0].length; y++)
|
||||||
|
for (var x = 0; x < _images.length; x++)
|
||||||
|
pngs.push(_images[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(pngs);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,177 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('APC UPS'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var rv = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types and instances supported by APC UPS
|
||||||
|
* e.g. ups_types -> [ 'timeleft', 'charge', 'percent', 'voltage' ]
|
||||||
|
* e.g. ups_inst['voltage'] -> [ 'input', 'battery' ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
var ups_types = graph.dataTypes(host, plugin, plugin_instance),
|
||||||
|
ups_inst = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < ups_types.length; i++)
|
||||||
|
ups_inst.push(graph.dataInstances(host, plugin, plugin_instance, ups_types[i]));
|
||||||
|
|
||||||
|
/* Check if hash table or array is empty or nil-filled */
|
||||||
|
function empty(t) {
|
||||||
|
for (var k in t)
|
||||||
|
if (t[k] != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append graph definition but only types/instances which are */
|
||||||
|
/* supported and available to the plugin and UPS. */
|
||||||
|
|
||||||
|
function add_supported(t, defs) {
|
||||||
|
var def_inst = defs['data']['instances'];
|
||||||
|
|
||||||
|
if (L.isObject(def_inst)) {
|
||||||
|
for (var k in def_inst) {
|
||||||
|
if (ups_types.find(function(t) { return t == k }).length) {
|
||||||
|
for (var i = def_inst[k].length - 1; i >= 0; i--)
|
||||||
|
if (!ups_inst[k].find(function(n) { return n == def_inst[k][i] }).length)
|
||||||
|
def_inst[k].splice(i, 1);
|
||||||
|
|
||||||
|
if (def_inst[k].length == 0)
|
||||||
|
def_inst[k] = null; /* can't assign v: immutable */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
def_inst[k] = null; /* can't assign v: immutable */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty(def_inst))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.push(defs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Graph definitions for APC UPS measurements MUST use only 'instances': */
|
||||||
|
/* e.g. instances = { voltage = { "input", "output" } } */
|
||||||
|
|
||||||
|
var voltagesdc = {
|
||||||
|
title: "%H: Voltages on APC UPS - Battery",
|
||||||
|
vlabel: "Volts DC",
|
||||||
|
alt_autoscale: true,
|
||||||
|
number_format: "%5.1lfV",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
voltage: [ "battery" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
voltage: { title: "Battery voltage", noarea: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, voltagesdc);
|
||||||
|
|
||||||
|
var voltagesac = {
|
||||||
|
title: "%H: Voltages on APC UPS - AC",
|
||||||
|
vlabel: "Volts AC",
|
||||||
|
alt_autoscale: true,
|
||||||
|
number_format: "%5.1lfV",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
voltage: [ "input", "output" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
voltage_output : { color: "00e000", title: "Output voltage", noarea: true, overlay: true },
|
||||||
|
voltage_input : { color: "ffb000", title: "Input voltage", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, voltagesac);
|
||||||
|
|
||||||
|
var percentload = {
|
||||||
|
title: "%H: Load on APC UPS ",
|
||||||
|
vlabel: "Percent",
|
||||||
|
y_min: "0",
|
||||||
|
y_max: "100",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
percent: [ "load" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
percent_load: { color: "00ff00", title: "Load level" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, percentload);
|
||||||
|
|
||||||
|
var charge_percent = {
|
||||||
|
title: "%H: Battery charge on APC UPS ",
|
||||||
|
vlabel: "Percent",
|
||||||
|
y_min: "0",
|
||||||
|
y_max: "100",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
charge: [ "" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
charge: { color: "00ff0b", title: "Charge level" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, charge_percent);
|
||||||
|
|
||||||
|
var temperature = {
|
||||||
|
title: "%H: Battery temperature on APC UPS ",
|
||||||
|
vlabel: "\u00b0C",
|
||||||
|
number_format: "%5.1lf\u00b0C",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
temperature: [ "" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
temperature: { color: "ffb000", title: "Battery temperature" } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, temperature);
|
||||||
|
|
||||||
|
var timeleft = {
|
||||||
|
title: "%H: Time left on APC UPS ",
|
||||||
|
vlabel: "Minutes",
|
||||||
|
number_format: "%.1lfm",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
timeleft: [ "" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
timeleft: { color: "0000ff", title: "Time left" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, timeleft);
|
||||||
|
|
||||||
|
var frequency = {
|
||||||
|
title: "%H: Incoming line frequency on APC UPS ",
|
||||||
|
vlabel: "Hz",
|
||||||
|
number_format: "%5.0lfhz",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
frequency: [ "input" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
frequency_input: { color: "000fff", title: "Line frequency" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add_supported(rv, frequency);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Conntrack'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Conntrack entries",
|
||||||
|
vlabel: "Count",
|
||||||
|
number_format: "%5.0lf",
|
||||||
|
data: {
|
||||||
|
/* collectd 5.5+: specify "" to exclude "max" instance */
|
||||||
|
instances: {
|
||||||
|
conntrack: [ "" ]
|
||||||
|
},
|
||||||
|
sources: {
|
||||||
|
conntrack: [ "value" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
conntrack: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Tracked connections"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Context Switches'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Context switches",
|
||||||
|
alt_autoscale: true,
|
||||||
|
vlabel: "Switches/s",
|
||||||
|
number_format: "%5.0lf",
|
||||||
|
data: {
|
||||||
|
types: [ "contextswitch" ],
|
||||||
|
sources: {
|
||||||
|
contextswitch: [ "value" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
contextswitch: { color: "0000ff", title: "Context switches", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,163 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
'require uci';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Processor'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var p = [];
|
||||||
|
|
||||||
|
var title = "%H: Processor usage";
|
||||||
|
|
||||||
|
if (plugin_instance != '')
|
||||||
|
title = "%H: Processor usage on core #%pi";
|
||||||
|
|
||||||
|
if (uci.get("luci_statistics", "collectd_cpu", "ReportByState") == "1") {
|
||||||
|
var cpu = {
|
||||||
|
title: title,
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
vlabel: "Jiffies",
|
||||||
|
number_format: "%5.1lf",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
cpu: [
|
||||||
|
"idle",
|
||||||
|
"interrupt",
|
||||||
|
"nice",
|
||||||
|
"softirq",
|
||||||
|
"steal",
|
||||||
|
"system",
|
||||||
|
"user",
|
||||||
|
"wait"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
cpu_idle: {
|
||||||
|
color: "ffffff",
|
||||||
|
title: "Idle"
|
||||||
|
},
|
||||||
|
cpu_interrupt: {
|
||||||
|
color: "a000a0",
|
||||||
|
title: "Interrupt"
|
||||||
|
},
|
||||||
|
cpu_nice: {
|
||||||
|
color: "00e000",
|
||||||
|
title: "Nice"
|
||||||
|
},
|
||||||
|
cpu_softirq: {
|
||||||
|
color: "ff00ff",
|
||||||
|
title: "Softirq"
|
||||||
|
},
|
||||||
|
cpu_steal: {
|
||||||
|
color: "000000",
|
||||||
|
title: "Steal"
|
||||||
|
},
|
||||||
|
cpu_system: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "System"
|
||||||
|
},
|
||||||
|
cpu_user: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "User"
|
||||||
|
},
|
||||||
|
cpu_wait: {
|
||||||
|
color: "ffb000",
|
||||||
|
title: "Wait"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var percent = {
|
||||||
|
title: title,
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
vlabel: "Percent",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
percent: [
|
||||||
|
"idle",
|
||||||
|
"interrupt",
|
||||||
|
"nice",
|
||||||
|
"softirq",
|
||||||
|
"steal",
|
||||||
|
"system",
|
||||||
|
"user",
|
||||||
|
"wait"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
percent_idle: {
|
||||||
|
color: "ffffff",
|
||||||
|
title: "Idle"
|
||||||
|
},
|
||||||
|
percent_interrupt: {
|
||||||
|
color: "a000a0",
|
||||||
|
title: "Interrupt"
|
||||||
|
},
|
||||||
|
percent_nice: {
|
||||||
|
color: "00e000",
|
||||||
|
title: "Nice"
|
||||||
|
},
|
||||||
|
percent_softirq: {
|
||||||
|
color: "ff00ff",
|
||||||
|
title: "Softirq"
|
||||||
|
},
|
||||||
|
percent_steal: {
|
||||||
|
color: "000000",
|
||||||
|
title: "Steal"
|
||||||
|
},
|
||||||
|
percent_system: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "System"
|
||||||
|
},
|
||||||
|
percent_user: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "User"
|
||||||
|
},
|
||||||
|
percent_wait: {
|
||||||
|
color: "ffb000",
|
||||||
|
title: "Wait"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var types = graph.dataTypes(host, plugin, plugin_instance);
|
||||||
|
|
||||||
|
for (var i = 0; i < types.length; i++)
|
||||||
|
if (types[i] == 'cpu')
|
||||||
|
p.push(cpu);
|
||||||
|
else if (types[i] == 'percent')
|
||||||
|
p.push(percent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p = {
|
||||||
|
title: title,
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
vlabel: "Percent",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
percent: [
|
||||||
|
"active",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
percent_active: {
|
||||||
|
color: "00e000",
|
||||||
|
title: "Active"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,57 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
'require uci';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('CPU Frequency'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var cpufreq = {
|
||||||
|
title: "%H: Processor frequency - core %pi",
|
||||||
|
alt_autoscale: true,
|
||||||
|
vlabel: "Frequency (Hz)",
|
||||||
|
number_format: "%3.2lf%s",
|
||||||
|
data: {
|
||||||
|
types: [ "cpufreq" ],
|
||||||
|
options: {
|
||||||
|
cpufreq: { color: "ff0000", title: "Frequency" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (uci.get("luci_statistics", "collectd_cpufreq", "ExtraItems")) {
|
||||||
|
var transitions = {
|
||||||
|
title: "%H: Frequency transitions - core %pi",
|
||||||
|
alt_autoscale: true,
|
||||||
|
vlabel: "Transitions",
|
||||||
|
number_format: "%3.2lf%s",
|
||||||
|
data: {
|
||||||
|
types: [ "transitions" ],
|
||||||
|
options: {
|
||||||
|
transitions: { color: "0000ff", title: "Transitions", noarea: true },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var percentage = {
|
||||||
|
title: "%H: Frequency distribution - core %pi",
|
||||||
|
alt_autoscale: true,
|
||||||
|
vlabel: "Percent",
|
||||||
|
number_format: "%5.2lf%%",
|
||||||
|
ordercolor: true,
|
||||||
|
data: {
|
||||||
|
types: [ "percent" ],
|
||||||
|
options: {
|
||||||
|
percent: { title: "%di kHz", negweight: true },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ cpufreq, percentage, transitions ];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [ cpufreq ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Chizhong Jin <pjincz@gmail.com>
|
||||||
|
* Licensed to the public under the BSD 3-clause license
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('cUrl'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: cUrl Response Time for #%pi",
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
vlabel: "Response Time",
|
||||||
|
number_format: "%5.1lf%Ss",
|
||||||
|
data: {
|
||||||
|
types: [ "response_time" ],
|
||||||
|
options: {
|
||||||
|
response_time: {
|
||||||
|
title: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Disk Space Usage'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var df_complex = {
|
||||||
|
title: "%H: Disk space usage on %pi",
|
||||||
|
vlabel: "Bytes",
|
||||||
|
number_format: "%5.1lf%sB",
|
||||||
|
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
df_complex: [ "free", "used", "reserved" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
df_complex_free: {
|
||||||
|
color: "00ff00",
|
||||||
|
overlay: false,
|
||||||
|
title: "free"
|
||||||
|
},
|
||||||
|
|
||||||
|
df_complex_used: {
|
||||||
|
color: "ff0000",
|
||||||
|
overlay: false,
|
||||||
|
title: "used"
|
||||||
|
},
|
||||||
|
|
||||||
|
df_complex_reserved: {
|
||||||
|
color: "0000ff",
|
||||||
|
overlay: false,
|
||||||
|
title: "reserved"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var percent_bytes = {
|
||||||
|
title: "%H: Disk space usage on %pi",
|
||||||
|
vlabel: "Percent",
|
||||||
|
number_format: "%5.2lf %%",
|
||||||
|
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
percent_bytes: [ "free", "used", "reserved" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
percent_bytes_free: {
|
||||||
|
color: "00ff00",
|
||||||
|
overlay: false,
|
||||||
|
title: "free"
|
||||||
|
},
|
||||||
|
|
||||||
|
percent_bytes_used: {
|
||||||
|
color: "ff0000",
|
||||||
|
overlay: false,
|
||||||
|
title: "used"
|
||||||
|
},
|
||||||
|
|
||||||
|
percent_bytes_reserved: {
|
||||||
|
color: "0000ff",
|
||||||
|
overlay: false,
|
||||||
|
title: "reserved"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var types = graph.dataTypes(host, plugin, plugin_instance);
|
||||||
|
|
||||||
|
for (var i = 0; i < types.length; i++)
|
||||||
|
if (types[i] == 'percent_bytes')
|
||||||
|
p.push(percent_bytes);
|
||||||
|
else if (types[i] == 'df_complex')
|
||||||
|
p.push(df_complex);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
||||||
|
* Licensed to the public under the Apache License 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Disk Usage'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return [{
|
||||||
|
title: "%H: Disk I/O operations on %pi",
|
||||||
|
vlabel: "Operations/s",
|
||||||
|
number_format: "%5.1lf%sOp/s",
|
||||||
|
|
||||||
|
data: {
|
||||||
|
types: [ "disk_ops" ],
|
||||||
|
sources: {
|
||||||
|
disk_ops: [ "read", "write" ],
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
disk_ops__read: {
|
||||||
|
title: "Reads",
|
||||||
|
color: "00ff00",
|
||||||
|
flip : false
|
||||||
|
},
|
||||||
|
|
||||||
|
disk_ops__write: {
|
||||||
|
title: "Writes",
|
||||||
|
color: "ff0000",
|
||||||
|
flip : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: "%H: Disk I/O bandwidth on %pi",
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
number_format: "%5.1lf%sB/s",
|
||||||
|
|
||||||
|
detail: true,
|
||||||
|
|
||||||
|
data: {
|
||||||
|
types: [ "disk_octets" ],
|
||||||
|
sources: {
|
||||||
|
disk_octets: [ "read", "write" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
disk_octets__read: {
|
||||||
|
title: "Read",
|
||||||
|
color: "00ff00",
|
||||||
|
flip : false
|
||||||
|
},
|
||||||
|
disk_octets__write: {
|
||||||
|
title: "Write",
|
||||||
|
color: "ff0000",
|
||||||
|
flip : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
||||||
|
* Licensed to the public under the Apache License 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('DNS'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var traffic = {
|
||||||
|
title: "%H: DNS traffic", vlabel: "Bit/s",
|
||||||
|
|
||||||
|
data: {
|
||||||
|
sources: {
|
||||||
|
dns_octets: [ "queries", "responses" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
dns_octets__responses: {
|
||||||
|
total: true,
|
||||||
|
color: "00ff00",
|
||||||
|
title: "Responses"
|
||||||
|
},
|
||||||
|
|
||||||
|
dns_octets__queries: {
|
||||||
|
total: true,
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Queries"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var opcode_query = {
|
||||||
|
title: "%H: DNS Opcode Query", vlabel: "Queries/s",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
dns_opcode: [ "Query" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
dns_opcode_Query_value: {
|
||||||
|
total: true,
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Queries/s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var qtype = {
|
||||||
|
title: "%H: DNS QType", vlabel: "Queries/s",
|
||||||
|
data: {
|
||||||
|
sources: { dns_qtype: [ "" ] },
|
||||||
|
options: {
|
||||||
|
dns_qtype_AAAA_ : { title: "AAAA", noarea: true, total: true },
|
||||||
|
dns_qtype_A_ : { title: "A", noarea: true, total: true },
|
||||||
|
dns_qtype_A6_ : { title: "A6", noarea: true, total: true },
|
||||||
|
dns_qtype_TXT_ : { title: "TXT", noarea: true, total: true },
|
||||||
|
dns_qtype_MX_ : { title: "MX", noarea: true, total: true },
|
||||||
|
dns_qtype_NS_ : { title: "NS", noarea: true, total: true },
|
||||||
|
dns_qtype_ANY_ : { title: "ANY", noarea: true, total: true },
|
||||||
|
dns_qtype_CNAME_: { title: "CNAME", noarea: true, total: true },
|
||||||
|
dns_qtype_SOA_ : { title: "SOA", noarea: true, total: true },
|
||||||
|
dns_qtype_SRV_ : { title: "SRV", noarea: true, total: true },
|
||||||
|
dns_qtype_PTR_ : { title: "PTR", noarea: true, total: true },
|
||||||
|
dns_qtype_RP_ : { title: "RP", noarea: true, total: true },
|
||||||
|
dns_qtype_MAILB_: { title: "MAILB", noarea: true, total: true },
|
||||||
|
dns_qtype_IXFR_ : { title: "IXFR", noarea: true, total: true },
|
||||||
|
dns_qtype_HINFO_: { title: "HINFO", noarea: true, total: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ traffic, opcode_query, qtype ];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 Hannu Nyman <hannu.nyman@iki.fi>
|
||||||
|
* Licensed to the public under the Apache License 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Entropy'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Available entropy",
|
||||||
|
vlabel: "bits",
|
||||||
|
number_format: "%4.0lf",
|
||||||
|
data: {
|
||||||
|
types: [ "entropy" ],
|
||||||
|
options: { entropy: { title: "Entropy %di" } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,110 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Interfaces'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
/*
|
||||||
|
* traffic diagram
|
||||||
|
*/
|
||||||
|
var traffic = {
|
||||||
|
|
||||||
|
/* draw this diagram for each plugin instance */
|
||||||
|
per_instance: true,
|
||||||
|
title: "%H: Transfer on %pi",
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* defined sources for data types, if omitted assume a single DS named "value" (optional) */
|
||||||
|
sources: {
|
||||||
|
if_octets: [ "tx", "rx" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
if_octets__tx: {
|
||||||
|
total: true, /* report total amount of bytes */
|
||||||
|
color: "00ff00", /* tx is green */
|
||||||
|
title: "Bytes (TX)"
|
||||||
|
},
|
||||||
|
|
||||||
|
if_octets__rx: {
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total: true, /* report total amount of bytes */
|
||||||
|
color: "0000ff", /* rx is blue */
|
||||||
|
title: "Bytes (RX)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* packet diagram
|
||||||
|
*/
|
||||||
|
var packets = {
|
||||||
|
|
||||||
|
/* draw this diagram for each plugin instance */
|
||||||
|
per_instance: true,
|
||||||
|
title: "%H: Packets on %pi",
|
||||||
|
vlabel: "Packets/s",
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* data type order */
|
||||||
|
types: [ "if_packets", "if_errors" ],
|
||||||
|
|
||||||
|
/* defined sources for data types */
|
||||||
|
sources: {
|
||||||
|
if_packets: [ "tx", "rx" ],
|
||||||
|
if_errors : [ "tx", "rx" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
/* processed packets (tx DS) */
|
||||||
|
if_packets__tx: {
|
||||||
|
weight : 1,
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
total : true, /* report total amount of bytes */
|
||||||
|
color : "00ff00", /* processed tx is green */
|
||||||
|
title : "Processed (TX)"
|
||||||
|
},
|
||||||
|
|
||||||
|
/* processed packets (rx DS) */
|
||||||
|
if_packets__rx: {
|
||||||
|
weight : 2,
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total : true, /* report total amount of bytes */
|
||||||
|
color : "0000ff", /* processed rx is blue */
|
||||||
|
title : "Processed (RX)"
|
||||||
|
},
|
||||||
|
|
||||||
|
/* packet errors (tx DS) */
|
||||||
|
if_errors__tx: {
|
||||||
|
weight : 0,
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
total : true, /* report total amount of packets */
|
||||||
|
color : "ff5500", /* tx errors are orange */
|
||||||
|
title : "Errors (TX)"
|
||||||
|
},
|
||||||
|
|
||||||
|
/* packet errors (rx DS) */
|
||||||
|
if_errors__rx: {
|
||||||
|
weight : 3,
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total : true, /* report total amount of packets */
|
||||||
|
color : "ff0000", /* rx errors are red */
|
||||||
|
title : "Errors (RX)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ traffic, packets ];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Firewall (IPv6)'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return [{
|
||||||
|
title: "%H: Firewall: Processed bytes in %pi",
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
number_format: "%5.1lf%sB/s",
|
||||||
|
totals_format: "%5.1lf%sB",
|
||||||
|
data: {
|
||||||
|
types: [ "ipt_bytes" ],
|
||||||
|
options: {
|
||||||
|
ipt_bytes: {
|
||||||
|
total: true,
|
||||||
|
title: "%di"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: "%H: Firewall: Processed packets in %pi",
|
||||||
|
vlabel: "Packets/s",
|
||||||
|
number_format: "%5.1lf P/s",
|
||||||
|
totals_format: "%5.1lf%s",
|
||||||
|
data: {
|
||||||
|
types: [ "ipt_packets" ],
|
||||||
|
options: {
|
||||||
|
ipt_packets: {
|
||||||
|
total: true,
|
||||||
|
title: "%di"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Firewall'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return [{
|
||||||
|
title: "%H: Firewall: Processed bytes in %pi",
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
number_format: "%5.1lf%sB/s",
|
||||||
|
totals_format: "%5.1lf%sB",
|
||||||
|
data: {
|
||||||
|
types: [ "ipt_bytes" ],
|
||||||
|
options: {
|
||||||
|
ipt_bytes: {
|
||||||
|
total: true,
|
||||||
|
title: "%di"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: "%H: Firewall: Processed packets in %pi",
|
||||||
|
vlabel: "Packets/s",
|
||||||
|
number_format: "%5.1lf P/s",
|
||||||
|
totals_format: "%5.1lf%s",
|
||||||
|
data: {
|
||||||
|
types: [ "ipt_packets" ],
|
||||||
|
options: {
|
||||||
|
ipt_packets: {
|
||||||
|
total: true,
|
||||||
|
title: "%di"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Interrupts'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Interrupts", vlabel: "Issues/s",
|
||||||
|
number_format: "%5.0lf", data: {
|
||||||
|
types: [ "irq" ],
|
||||||
|
options: {
|
||||||
|
irq: { title: "IRQ %di", noarea: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Wireless'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
/*
|
||||||
|
* signal/noise diagram
|
||||||
|
*/
|
||||||
|
var snr = {
|
||||||
|
title: "%H: Signal and noise on %pi",
|
||||||
|
detail: true,
|
||||||
|
vlabel: "dBm",
|
||||||
|
number_format: "%5.1lf dBm",
|
||||||
|
data: {
|
||||||
|
types: [ "signal_power", "signal_noise" ],
|
||||||
|
options: {
|
||||||
|
signal_power: {
|
||||||
|
title : "Signal",
|
||||||
|
overlay: true,
|
||||||
|
color : "0000ff"
|
||||||
|
},
|
||||||
|
signal_noise: {
|
||||||
|
title : "Noise",
|
||||||
|
overlay: true,
|
||||||
|
color : "ff0000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* signal quality diagram
|
||||||
|
*/
|
||||||
|
var quality = {
|
||||||
|
title: "%H: Signal quality on %pi",
|
||||||
|
vlabel: "Quality",
|
||||||
|
number_format: "%3.0lf",
|
||||||
|
data: {
|
||||||
|
types: [ "signal_quality" ],
|
||||||
|
options: {
|
||||||
|
signal_quality: {
|
||||||
|
title : "Quality",
|
||||||
|
noarea: true,
|
||||||
|
color : "0000ff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* phy rate diagram
|
||||||
|
*/
|
||||||
|
var bitrate = {
|
||||||
|
title: "%H: Average phy rate on %pi",
|
||||||
|
detail: true,
|
||||||
|
vlabel: "MBit/s",
|
||||||
|
number_format: "%5.1lf%sBit/s",
|
||||||
|
data: {
|
||||||
|
types: [ "bitrate" ],
|
||||||
|
options: {
|
||||||
|
bitrate: {
|
||||||
|
title: "Rate",
|
||||||
|
color: "00ff00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* associated stations
|
||||||
|
*/
|
||||||
|
var stations = {
|
||||||
|
title: "%H: Associated stations on %pi",
|
||||||
|
detail: true,
|
||||||
|
vlabel: "Stations",
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
number_format: "%3.0lf",
|
||||||
|
data: {
|
||||||
|
types: [ "stations" ],
|
||||||
|
options: {
|
||||||
|
stations: {
|
||||||
|
title: "Stations",
|
||||||
|
color: "0000ff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ quality, snr, bitrate, stations ];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('System Load'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Load", vlabel: "Load",
|
||||||
|
y_min: "0",
|
||||||
|
units_exponent: "0",
|
||||||
|
number_format: "%5.2lf", data: {
|
||||||
|
sources: {
|
||||||
|
load: [ "shortterm", "midterm", "longterm" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
load__shortterm: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "1 minute",
|
||||||
|
noarea: true,
|
||||||
|
weight: 3
|
||||||
|
},
|
||||||
|
load__midterm: {
|
||||||
|
color: "ff6600",
|
||||||
|
title: "5 minutes",
|
||||||
|
overlay: true,
|
||||||
|
weight: 1
|
||||||
|
},
|
||||||
|
load__longterm: {
|
||||||
|
color: "ffaa00",
|
||||||
|
title: "15 minutes",
|
||||||
|
overlay: true,
|
||||||
|
weight: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
||||||
|
* Licensed to the public under the Apache License 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Memory'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var p = [];
|
||||||
|
|
||||||
|
var memory = {
|
||||||
|
title: "%H: Memory usage",
|
||||||
|
vlabel: "MB",
|
||||||
|
number_format: "%5.1lf%s",
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
memory: [
|
||||||
|
"free",
|
||||||
|
"buffered",
|
||||||
|
"cached",
|
||||||
|
"used"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
memory_buffered: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Buffered"
|
||||||
|
},
|
||||||
|
memory_cached: {
|
||||||
|
color: "ff00ff",
|
||||||
|
title: "Cached"
|
||||||
|
},
|
||||||
|
memory_used: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "Used"
|
||||||
|
},
|
||||||
|
memory_free: {
|
||||||
|
color: "00ff00",
|
||||||
|
title: "Free"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var percent = {
|
||||||
|
title: "%H: Memory usage",
|
||||||
|
vlabel: "Percent",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
y_min: "0",
|
||||||
|
alt_autoscale_max: true,
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
percent: [
|
||||||
|
"free",
|
||||||
|
"buffered",
|
||||||
|
"cached",
|
||||||
|
"used"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
percent_buffered: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Buffered"
|
||||||
|
},
|
||||||
|
percent_cached: {
|
||||||
|
color: "ff00ff",
|
||||||
|
title: "Cached"
|
||||||
|
},
|
||||||
|
percent_used: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "Used"
|
||||||
|
},
|
||||||
|
percent_free: {
|
||||||
|
color: "00ff00",
|
||||||
|
title: "Free"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var types = graph.dataTypes(host, plugin, plugin_instance);
|
||||||
|
|
||||||
|
for (var i = 0; i < types.length; i++)
|
||||||
|
if (types[i] == 'percent')
|
||||||
|
p.push(percent);
|
||||||
|
else if (types[i] == 'memory')
|
||||||
|
p.push(memory);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,208 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Netlink'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
/*
|
||||||
|
* traffic diagram
|
||||||
|
*/
|
||||||
|
var traffic = {
|
||||||
|
title: "%H: Netlink - Transfer on %pi",
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* defined sources for data types, if omitted assume a single DS named "value" (optional) */
|
||||||
|
sources: {
|
||||||
|
if_octets: [ "tx", "rx" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
if_octets__tx: {
|
||||||
|
title: "Bytes (TX)",
|
||||||
|
total: true, /* report total amount of bytes */
|
||||||
|
color: "00ff00" /* tx is green */
|
||||||
|
},
|
||||||
|
|
||||||
|
if_octets__rx: {
|
||||||
|
title: "Bytes (RX)",
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total: true, /* report total amount of bytes */
|
||||||
|
color: "0000ff" /* rx is blue */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* packet diagram
|
||||||
|
*/
|
||||||
|
var packets = {
|
||||||
|
title: "%H: Netlink - Packets on %pi",
|
||||||
|
vlabel: "Packets/s", detail: true,
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* data type order */
|
||||||
|
types: [ "if_packets", "if_dropped", "if_errors" ],
|
||||||
|
|
||||||
|
/* defined sources for data types */
|
||||||
|
sources: {
|
||||||
|
if_packets: [ "tx", "rx" ],
|
||||||
|
if_dropped: [ "tx", "rx" ],
|
||||||
|
if_errors : [ "tx", "rx" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
/* processed packets (tx DS) */
|
||||||
|
if_packets__tx: {
|
||||||
|
weight : 2,
|
||||||
|
title : "Total (TX)",
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
total : true, /* report total amount of bytes */
|
||||||
|
color : "00ff00" /* processed tx is green */
|
||||||
|
},
|
||||||
|
|
||||||
|
/* processed packets (rx DS) */
|
||||||
|
if_packets__rx: {
|
||||||
|
weight : 3,
|
||||||
|
title : "Total (RX)",
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total : true, /* report total amount of bytes */
|
||||||
|
color : "0000ff" /* processed rx is blue */
|
||||||
|
},
|
||||||
|
|
||||||
|
/* dropped packets (tx DS) */
|
||||||
|
if_dropped__tx: {
|
||||||
|
weight : 1,
|
||||||
|
title : "Dropped (TX)",
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
total : true, /* report total amount of bytes */
|
||||||
|
color : "660055" /* dropped tx is ... dunno ;) */
|
||||||
|
},
|
||||||
|
|
||||||
|
/* dropped packets (rx DS) */
|
||||||
|
if_dropped__rx: {
|
||||||
|
weight : 4,
|
||||||
|
title : "Dropped (RX)",
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total : true, /* report total amount of bytes */
|
||||||
|
color : "ff00ff" /* dropped rx is violett */
|
||||||
|
},
|
||||||
|
|
||||||
|
/* packet errors (tx DS) */
|
||||||
|
if_errors__tx: {
|
||||||
|
weight : 0,
|
||||||
|
title : "Errors (TX)",
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
total : true, /* report total amount of packets */
|
||||||
|
color : "ff5500" /* tx errors are orange */
|
||||||
|
},
|
||||||
|
|
||||||
|
/* packet errors (rx DS) */
|
||||||
|
if_errors__rx: {
|
||||||
|
weight : 5,
|
||||||
|
title : "Errors (RX)",
|
||||||
|
overlay: true, /* don't summarize */
|
||||||
|
flip : true, /* flip rx line */
|
||||||
|
total : true, /* report total amount of packets */
|
||||||
|
color : "ff0000" /* rx errors are red */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* multicast diagram
|
||||||
|
*/
|
||||||
|
var multicast = {
|
||||||
|
title: "%H: Netlink - Multicast on %pi",
|
||||||
|
vlabel: "Packets/s", detail: true,
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* data type order */
|
||||||
|
types: [ "if_multicast" ],
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
/* multicast packets */
|
||||||
|
if_multicast: {
|
||||||
|
title: "Packets",
|
||||||
|
total: true, /* report total amount of packets */
|
||||||
|
color: "0000ff" /* multicast is blue */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* collision diagram
|
||||||
|
*/
|
||||||
|
var collisions = {
|
||||||
|
title: "%H: Netlink - Collisions on %pi",
|
||||||
|
vlabel: "Collisions/s", detail: true,
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* data type order */
|
||||||
|
types: [ "if_collisions" ],
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
/* collision rate */
|
||||||
|
if_collisions: {
|
||||||
|
title: "Collisions",
|
||||||
|
total: true, /* report total amount of packets */
|
||||||
|
color: "ff0000" /* collsions are red */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* error diagram
|
||||||
|
*/
|
||||||
|
var errors = {
|
||||||
|
title: "%H: Netlink - Errors on %pi",
|
||||||
|
vlabel: "Errors/s", detail: true,
|
||||||
|
|
||||||
|
/* diagram data description */
|
||||||
|
data: {
|
||||||
|
/* data type order */
|
||||||
|
types: [ "if_tx_errors", "if_rx_errors" ],
|
||||||
|
|
||||||
|
/* data type instances */
|
||||||
|
instances: {
|
||||||
|
if_tx_errors: [ "aborted", "carrier", "fifo", "heartbeat", "window" ],
|
||||||
|
if_rx_errors: [ "length", "missed", "over", "crc", "fifo", "frame" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
/* special options for single data lines */
|
||||||
|
options: {
|
||||||
|
if_tx_errors_aborted_value : { total: true, color: "ffff00", title: "Aborted (TX)" },
|
||||||
|
if_tx_errors_carrier_value : { total: true, color: "ffcc00", title: "Carrier (TX)" },
|
||||||
|
if_tx_errors_fifo_value : { total: true, color: "ff9900", title: "Fifo (TX)" },
|
||||||
|
if_tx_errors_heartbeat_value: { total: true, color: "ff6600", title: "Heartbeat (TX)" },
|
||||||
|
if_tx_errors_window_value : { total: true, color: "ff3300", title: "Window (TX)" },
|
||||||
|
|
||||||
|
if_rx_errors_length_value : { flip: true, total: true, color: "ff0000", title: "Length (RX)" },
|
||||||
|
if_rx_errors_missed_value : { flip: true, total: true, color: "ff0033", title: "Missed (RX)" },
|
||||||
|
if_rx_errors_over_value : { flip: true, total: true, color: "ff0066", title: "Over (RX)" },
|
||||||
|
if_rx_errors_crc_value : { flip: true, total: true, color: "ff0099", title: "CRC (RX)" },
|
||||||
|
if_rx_errors_fifo_value : { flip: true, total: true, color: "ff00cc", title: "Fifo (RX)" },
|
||||||
|
if_rx_errors_frame_value : { flip: true, total: true, color: "ff00ff", title: "Frame (RX)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ traffic, packets, multicast, collisions, errors ];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('UPS'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var voltages_ac = {
|
||||||
|
title: "%H: AC voltages on UPS \"%pi\"",
|
||||||
|
vlabel: "V",
|
||||||
|
number_format: "%5.1lfV",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
voltage: [ "input", "output" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
voltage_output : { color: "00e000", title: "Output voltage", noarea: true, overlay: true },
|
||||||
|
voltage_input : { color: "ffb000", title: "Input voltage", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var voltages_dc = {
|
||||||
|
title: "%H: Battery voltage on UPS \"%pi\"",
|
||||||
|
vlabel: "V",
|
||||||
|
number_format: "%5.1lfV",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
voltage: [ "battery" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
voltage: { color: "0000ff", title: "Battery voltage", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var currents = {
|
||||||
|
title: "%H: Current on UPS \"%pi\"",
|
||||||
|
vlabel: "A",
|
||||||
|
number_format: "%5.3lfA",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
current: [ "battery", "output" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
current_output : { color: "00e000", title: "Output current", noarea: true, overlay: true },
|
||||||
|
current_battery: { color: "0000ff", title: "Battery current", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var percentage = {
|
||||||
|
title: "%H: Battery charge/load on UPS \"%pi\"",
|
||||||
|
vlabel: "Percent",
|
||||||
|
y_min: "0",
|
||||||
|
y_max: "100",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
percent: [ "charge", "load" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
percent_charge: { color: "00ff00", title: "Charge level", noarea: true, overlay: true },
|
||||||
|
percent_load: { color: "ff0000", title: "Load", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Note: This is in ISO8859-1 for rrdtool. Welcome to the 20th century. */
|
||||||
|
var temperature = {
|
||||||
|
title: "%H: Battery temperature on UPS \"%pi\"",
|
||||||
|
vlabel: "\u00b0C",
|
||||||
|
number_format: "%5.1lf\u00b0C",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
temperature: "battery"
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
temperature_battery: { color: "ffb000", title: "Battery temperature", noarea: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var timeleft = {
|
||||||
|
title: "%H: Time left on UPS \"%pi\"",
|
||||||
|
vlabel: "Minutes",
|
||||||
|
number_format: "%.1lfm",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
timeleft: [ "battery" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
timeleft_battery: { color: "0000ff", title: "Time left", transform_rpn: "60,/", noarea: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var power = {
|
||||||
|
title: "%H: Power on UPS \"%pi\"",
|
||||||
|
vlabel: "Power",
|
||||||
|
number_format: "%5.1lf%%",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
power: [ "ups" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
power_ups: { color: "00ff00", title: "Power level" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var frequencies = {
|
||||||
|
title: "%H: Frequencies on UPS \"%pi\"",
|
||||||
|
vlabel: "Hz",
|
||||||
|
number_format: "%5.1lfHz",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
frequency: [ "input", "output" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
frequency_output : { color: "00e000", title: "Output frequency", noarea: true, overlay: true },
|
||||||
|
frequency_input : { color: "ffb000", title: "Input frequency", noarea: true, overlay: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ voltages_ac, voltages_dc, currents, percentage, temperature, timeleft, power, frequencies ];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
||||||
|
* Licensed to the public under the Apache License 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('OLSRd'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var g = [];
|
||||||
|
|
||||||
|
if (plugin_instance == "routes") {
|
||||||
|
g.push({
|
||||||
|
/* diagram data description */
|
||||||
|
title: "%H: Total amount of OLSR routes", vlabel: "n",
|
||||||
|
number_format: "%5.0lf", data: {
|
||||||
|
types: [ "routes" ],
|
||||||
|
options: {
|
||||||
|
routes: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "Total number of routes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: "%H: Average route ETX", vlabel: "ETX", detail: true,
|
||||||
|
number_format: "%5.1lf", data: {
|
||||||
|
instances: [ "average" ], /* falls es irgendwann mal welche pro ip gibt, wie bei links, dann werden die hier excludiert */
|
||||||
|
types: [ "route_etx" ],
|
||||||
|
options: {
|
||||||
|
route_etx: {
|
||||||
|
title: "Average route ETX"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: "%H: Average route metric", vlabel: "metric", detail: true,
|
||||||
|
number_format: "%5.1lf", data: {
|
||||||
|
instances: [ "average" ], /* falls es irgendwann mal welche pro ip gibt, wie bei links, dann werden die hier excludiert */
|
||||||
|
types: [ "route_metric" ],
|
||||||
|
options: {
|
||||||
|
route_metric: {
|
||||||
|
title: "Average route metric"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (plugin_instance == "links") {
|
||||||
|
g.push({
|
||||||
|
/* diagram data description */
|
||||||
|
title: "%H: Total amount of OLSR neighbours", vlabel: "n",
|
||||||
|
number_format: "%5.0lf", data: {
|
||||||
|
instances: [ "" ],
|
||||||
|
types: [ "links" ],
|
||||||
|
options: {
|
||||||
|
links: {
|
||||||
|
color: "00ff00",
|
||||||
|
title: "Number of neighbours"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var instances = graph.dataInstances(host, plugin, plugin_instance, "signal_quality").sort();
|
||||||
|
|
||||||
|
/* define one diagram per host, containing the rx and lq values */
|
||||||
|
for (var i = 0; i < instances.length; i += 2) {
|
||||||
|
var dsn1 = "signal_quality_%s_value".format(instances[i].replace(/\W+/g, '_')),
|
||||||
|
dsn2 = "signal_quality_%s_value".format(instances[i+1].replace(/\W+/g, '_')),
|
||||||
|
host = instances[i].match(/^[^-]+-([^-]+)-.+$/),
|
||||||
|
host = host ? host[1] : 'avg',
|
||||||
|
opts = {};
|
||||||
|
|
||||||
|
opts[dsn1] = { color: "00ff00", title: "LQ (%s)".format(host) };
|
||||||
|
opts[dns2] = { color: "0000ff", title: "NLQ (%s)".format(host), flip: true };
|
||||||
|
|
||||||
|
g.push({
|
||||||
|
title: "%H: Signal Quality (%s)".format(host), vlabel: "ETX",
|
||||||
|
number_format: "%5.2lf", detail: true,
|
||||||
|
data: {
|
||||||
|
types: [ "signal_quality" ],
|
||||||
|
|
||||||
|
instances: {
|
||||||
|
signal_quality: [ instances[i], instances[i+1] ],
|
||||||
|
},
|
||||||
|
|
||||||
|
options: opts
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (plugin_instance == "topology") {
|
||||||
|
g.push({
|
||||||
|
title: "%H: Total amount of OLSR links", vlabel: "n",
|
||||||
|
number_format: "%5.0lf", data: {
|
||||||
|
instances: [ "" ],
|
||||||
|
types: [ "links" ],
|
||||||
|
options: {
|
||||||
|
links: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Total number of links"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
title: "%H: Average signal quality", vlabel: "n",
|
||||||
|
number_format: "%5.2lf", detail: true,
|
||||||
|
data: {
|
||||||
|
instances: [ "average" ], /* exclude possible per-ip stuff */
|
||||||
|
types: [ "signal_quality" ],
|
||||||
|
options: {
|
||||||
|
signal_quality: {
|
||||||
|
color: "0000ff",
|
||||||
|
title: "Average signal quality"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('OpenVPN'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var inst = plugin_instance.replace(/^openvpn\.(.+)\.status$/, '$1');
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: "%%H: OpenVPN \"%s\" - Traffic".format(inst),
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
if_octets: [ "traffic", "overhead" ]
|
||||||
|
},
|
||||||
|
sources: {
|
||||||
|
if_octets: [ "tx", "rx" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
if_octets_traffic_tx : { weight: 0, title: "Bytes (TX)", total: true, color: "00ff00" },
|
||||||
|
if_octets_overhead_tx: { weight: 1, title: "Overhead (TX)", total: true, color: "ff9900" },
|
||||||
|
if_octets_overhead_rx: { weight: 2, title: "Overhead (RX)", total: true, flip: true, color: "ff00ff" },
|
||||||
|
if_octets_traffic_rx : { weight: 3, title: "Bytes (RX)", total: true, flip: true, color: "0000ff" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "%%H: OpenVPN \"%s\" - Compression".format(inst),
|
||||||
|
vlabel: "Bytes/s",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
compression: [ "data_out", "data_in" ]
|
||||||
|
},
|
||||||
|
sources: {
|
||||||
|
compression: [ "uncompressed", "compressed" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
compression_data_out_uncompressed: { weight: 0, title: "Uncompressed (TX)", total: true, color: "00ff00" },
|
||||||
|
compression_data_out_compressed : { weight: 1, title: "Compressed (TX)", total: true, color: "008800" },
|
||||||
|
compression_data_in_compressed : { weight: 2, title: "Compressed (RX)", total: true, flip: true, color: "000088" },
|
||||||
|
compression_data_in_uncompressed : { weight: 3, title: "Uncompressed (RX)", total: true, flip: true, color: "0000ff" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Ping'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
var ping = {
|
||||||
|
title: "%H: ICMP Round Trip Time",
|
||||||
|
vlabel: "ms",
|
||||||
|
number_format: "%5.1lf ms",
|
||||||
|
data: {
|
||||||
|
sources: {
|
||||||
|
ping: [ "value" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
ping__value: {
|
||||||
|
noarea: true,
|
||||||
|
overlay: true,
|
||||||
|
title: "%di"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var droprate = {
|
||||||
|
title: "%H: ICMP Drop Rate",
|
||||||
|
vlabel: "%",
|
||||||
|
number_format: "%5.2lf %%",
|
||||||
|
data: {
|
||||||
|
types: [ "ping_droprate" ],
|
||||||
|
options: {
|
||||||
|
ping_droprate: {
|
||||||
|
noarea: true,
|
||||||
|
overlay: true,
|
||||||
|
title: "%di",
|
||||||
|
transform_rpn: "100,*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var stddev = {
|
||||||
|
title: "%H: ICMP Standard Deviation",
|
||||||
|
vlabel: "ms",
|
||||||
|
number_format: "%5.1lf ms",
|
||||||
|
data: {
|
||||||
|
types: [ "ping_stddev" ],
|
||||||
|
options: {
|
||||||
|
ping_stddev: {
|
||||||
|
noarea: true,
|
||||||
|
overlay: true,
|
||||||
|
title: "%di"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ ping, droprate, stddev ];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,120 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Processes'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
if (plugin_instance == "") {
|
||||||
|
return {
|
||||||
|
title: "%H: Processes",
|
||||||
|
vlabel: "Processes/s",
|
||||||
|
data: {
|
||||||
|
instances: {
|
||||||
|
ps_state: [
|
||||||
|
"sleeping", "running", "paging",
|
||||||
|
"blocked", "stopped", "zombies"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
ps_state_sleeping: { color: "0000ff", title: "Sleeping" },
|
||||||
|
ps_state_running : { color: "008000", title: "Running" },
|
||||||
|
ps_state_paging : { color: "ffff00", title: "Paging" },
|
||||||
|
ps_state_blocked : { color: "ff5000", title: "Blocked" },
|
||||||
|
ps_state_stopped : { color: "555555", title: "Stopped" },
|
||||||
|
ps_state_zombies : { color: "ff0000", title: "Zombies" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: "%H: CPU time used by %pi",
|
||||||
|
vlabel: "Jiffies",
|
||||||
|
data: {
|
||||||
|
sources: {
|
||||||
|
ps_cputime: [ "syst", "user" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
ps_cputime__user: {
|
||||||
|
color : "0000ff",
|
||||||
|
title : "User",
|
||||||
|
overlay: true
|
||||||
|
},
|
||||||
|
|
||||||
|
ps_cputime__syst: {
|
||||||
|
color : "ff0000",
|
||||||
|
title : "System",
|
||||||
|
overlay: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "%H: Threads and processes belonging to %pi",
|
||||||
|
vlabel: "Count",
|
||||||
|
detail: true,
|
||||||
|
data: {
|
||||||
|
sources: {
|
||||||
|
ps_count: [ "threads", "processes" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
ps_count__threads : { color: "00ff00", title: "Threads" },
|
||||||
|
ps_count__processes: { color: "0000bb", title: "Processes" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "%H: Page faults in %pi",
|
||||||
|
vlabel: "Page faults",
|
||||||
|
detail: true,
|
||||||
|
data: {
|
||||||
|
sources: {
|
||||||
|
ps_pagefaults: [ "minflt", "majflt" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
ps_pagefaults__minflt: { color: "0000ff", title: "Minor" },
|
||||||
|
ps_pagefaults__majflt: { color: "ff0000", title: "Major" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "%H: Resident segment size (RSS) of %pi",
|
||||||
|
vlabel: "Bytes",
|
||||||
|
detail: true,
|
||||||
|
number_format: "%5.1lf%sB",
|
||||||
|
data: {
|
||||||
|
types: [ "ps_rss" ],
|
||||||
|
|
||||||
|
options: {
|
||||||
|
ps_rss: { color: "0000ff", title: "Resident segment" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "%H: Virtual memory size (VSZ) of %pi",
|
||||||
|
vlabel: "Bytes",
|
||||||
|
detail: true,
|
||||||
|
number_format: "%5.1lf%sB",
|
||||||
|
data: {
|
||||||
|
types: [ "ps_vm" ],
|
||||||
|
|
||||||
|
options: {
|
||||||
|
ps_vm: { color: "0000ff", title: "Virtual memory" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Sensors'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
per_instance: true,
|
||||||
|
title: "%H: %pi - %di",
|
||||||
|
vlabel: "\xb0C",
|
||||||
|
number_format: "%4.1lf\xb0C",
|
||||||
|
data: {
|
||||||
|
types: [ "temperature" ],
|
||||||
|
options: {
|
||||||
|
temperature__value: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "Temperature"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Freifunk Augsburg / Michael Wendland <michael@michiwend.com>
|
||||||
|
* Licensed to the public under the Apache License 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Splash Leases'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Splash Leases",
|
||||||
|
vlabel: "Active Clients",
|
||||||
|
y_min: "0",
|
||||||
|
number_format: "%5.1lf",
|
||||||
|
data: {
|
||||||
|
sources: {
|
||||||
|
splash_leases: [ "leased", "whitelisted", "blacklisted" ]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
splash_leases__leased : { color: "00CC00", title: "Leased", overlay: false },
|
||||||
|
splash_leases__whitelisted: { color: "0000FF", title: "Whitelisted", overlay: false },
|
||||||
|
splash_leases__blacklisted: { color: "FF0000", title: "Blacklisted", overlay: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('TCP Connections'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: TCP connections to port %pi",
|
||||||
|
vlabel: "Connections/s",
|
||||||
|
number_format: "%5.0lf",
|
||||||
|
data: {
|
||||||
|
types: [ "tcp_connections" ],
|
||||||
|
instances: {
|
||||||
|
tcp_connections: [
|
||||||
|
"SYN_SENT", "SYN_RECV", "LISTEN", "ESTABLISHED",
|
||||||
|
"LAST_ACK", "TIME_WAIT", "CLOSING", "CLOSE_WAIT",
|
||||||
|
"CLOSED", "FIN_WAIT1", "FIN_WAIT2"
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
load__ESTABLISHED: { title: "%di", noarea: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Licensed to the public under the Apache License 2.0. */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Thermal'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Temperature of %pi",
|
||||||
|
alt_autoscale: true,
|
||||||
|
vlabel: "Celsius",
|
||||||
|
number_format: "%3.1lf%s",
|
||||||
|
data: {
|
||||||
|
types: [ "temperature" ],
|
||||||
|
options: {
|
||||||
|
temperature: {
|
||||||
|
color: "ff0000",
|
||||||
|
title: "Temperature",
|
||||||
|
noarea: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
Copyright 2013 Thomas Endt <tmo26@gmx.de>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
return L.Class.extend({
|
||||||
|
title: _('Uptime'),
|
||||||
|
|
||||||
|
rrdargs: function(graph, host, plugin, plugin_instance, dtype) {
|
||||||
|
return {
|
||||||
|
title: "%H: Uptime",
|
||||||
|
vlabel: "seconds",
|
||||||
|
number_format: "%5.0lf%s",
|
||||||
|
data: {
|
||||||
|
types: [ "uptime" ],
|
||||||
|
options: {
|
||||||
|
uptime: {
|
||||||
|
title: "Uptime %di",
|
||||||
|
noarea: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,205 @@
|
||||||
|
'use strict';
|
||||||
|
'require ui';
|
||||||
|
'require uci';
|
||||||
|
'require statistics.rrdtool as rrdtool';
|
||||||
|
|
||||||
|
var pollFn = null,
|
||||||
|
activePlugin = null,
|
||||||
|
activeInstance = null;
|
||||||
|
|
||||||
|
return L.view.extend({
|
||||||
|
load: function() {
|
||||||
|
return rrdtool.load();
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePluginTab: function(host, span, time, ev) {
|
||||||
|
var container = ev.target,
|
||||||
|
plugin = ev.detail.tab,
|
||||||
|
plugin_instances = rrdtool.pluginInstances(host.value, plugin);
|
||||||
|
|
||||||
|
activePlugin = plugin;
|
||||||
|
|
||||||
|
L.dom.content(container, [
|
||||||
|
E('p', {}, [
|
||||||
|
E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
Promise.all(plugin_instances.map(function(instance) {
|
||||||
|
return rrdtool.render(plugin, instance, false, host.value, span.value, Math.max(200, container.offsetWidth - 100));
|
||||||
|
})).then(function(blobs) {
|
||||||
|
var multiple = blobs.length > 1;
|
||||||
|
|
||||||
|
L.dom.content(container, E('div', {}, blobs.map(function(blobs, i) {
|
||||||
|
var plugin_instance = plugin_instances[i];
|
||||||
|
|
||||||
|
return E('div', {
|
||||||
|
'class': 'center',
|
||||||
|
'data-tab': multiple ? i : null,
|
||||||
|
'data-tab-title': multiple ? '%s: %s'.format(rrdtool.pluginTitle(plugin), plugin_instances[i]) : null,
|
||||||
|
'data-plugin': plugin,
|
||||||
|
'data-plugin-instance': plugin_instances[i],
|
||||||
|
'cbi-tab-active': function(ev) { activeInstance = ev.target.getAttribute('data-plugin-instance') }
|
||||||
|
}, blobs.map(function(blob) {
|
||||||
|
return E('img', {
|
||||||
|
'src': URL.createObjectURL(new Blob([blob], { type: 'image/png' }))
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
})));
|
||||||
|
|
||||||
|
if (multiple)
|
||||||
|
ui.tabs.initTabGroup(container.lastElementChild.childNodes);
|
||||||
|
else
|
||||||
|
activeInstance = plugin_instances[0];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateGraphs: function(host, span, time, container, ev) {
|
||||||
|
var plugin_names = rrdtool.pluginNames(host.value);
|
||||||
|
|
||||||
|
container.querySelectorAll('img').forEach(function(img) {
|
||||||
|
URL.revokeObjectURL(img.src);
|
||||||
|
});
|
||||||
|
|
||||||
|
L.dom.content(container, null);
|
||||||
|
|
||||||
|
if (container.hasAttribute('data-initialized')) {
|
||||||
|
container.removeAttribute('data-initialized');
|
||||||
|
container.parentNode.removeChild(container.previousElementSibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < plugin_names.length; i++) {
|
||||||
|
if (!rrdtool.hasDefinition(plugin_names[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
container.appendChild(E('div', {
|
||||||
|
'data-tab': plugin_names[i],
|
||||||
|
'data-tab-title': rrdtool.pluginTitle(plugin_names[i]),
|
||||||
|
'cbi-tab-active': L.bind(this.updatePluginTab, this, host, span, time)
|
||||||
|
}, [
|
||||||
|
E('p', {}, [
|
||||||
|
E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
|
||||||
|
])
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.tabs.initTabGroup(container.childNodes);
|
||||||
|
},
|
||||||
|
|
||||||
|
refreshGraphs: function(host, span, time, container) {
|
||||||
|
var div = document.querySelector('[data-plugin="%s"][data-plugin-instance="%s"]'.format(activePlugin, activeInstance || ''));
|
||||||
|
|
||||||
|
return rrdtool.render(activePlugin, activeInstance || '', false, host.value, span.value, Math.max(200, container.offsetWidth - 100)).then(function(blobs) {
|
||||||
|
return Promise.all(blobs.map(function(blob) {
|
||||||
|
return new Promise(function(resolveFn, rejectFn) {
|
||||||
|
var img = E('img', { 'src': URL.createObjectURL(new Blob([blob], { type: 'image/png' })) });
|
||||||
|
img.onload = function(ev) { resolveFn(img) };
|
||||||
|
img.onerror = function(ev) { resolveFn(img) };
|
||||||
|
});
|
||||||
|
})).then(function(imgs) {
|
||||||
|
while (div.childNodes.length > imgs.length)
|
||||||
|
div.removeChild(div.lastElementChild);
|
||||||
|
|
||||||
|
for (var i = 0; i < imgs.length; i++) {
|
||||||
|
if (i < div.childNodes.length) {
|
||||||
|
URL.revokeObjectURL(div.childNodes[i].src);
|
||||||
|
div.childNodes[i].src = imgs[i].src;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
div.appendChild(E('img', { 'src': imgs[i].src }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
togglePolling: function(host, span, time, container, ev) {
|
||||||
|
var btn = ev.currentTarget;
|
||||||
|
|
||||||
|
if (pollFn) {
|
||||||
|
L.Poll.remove(pollFn);
|
||||||
|
pollFn = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time.value != '0') {
|
||||||
|
pollFn = L.bind(this.refreshGraphs, this, host, span, time, container);
|
||||||
|
L.Poll.add(pollFn, +time.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var hosts = rrdtool.hostInstances();
|
||||||
|
return hosts.length ? this.renderGraphs() : this.renderNoData();
|
||||||
|
},
|
||||||
|
|
||||||
|
renderNoData: function() {
|
||||||
|
ui.showModal(_('No RRD data found'), [
|
||||||
|
E('p', {}, _('There is no RRD data available yet to render graphs.')),
|
||||||
|
E('p', {}, _('You need to configure <em>collectd</em> to gather data into <em>.rrd</em> files.')),
|
||||||
|
E('div', { 'class': 'right' }, [
|
||||||
|
E('button', {
|
||||||
|
'class': 'cbi-button',
|
||||||
|
'click': function(ev) { location.href = 'collectd' }
|
||||||
|
}, [ _('Setup collectd') ])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderGraphs: function() {
|
||||||
|
var hostSel = E('select', { 'style': 'max-width:170px', 'data-name': 'host' }, rrdtool.hostInstances().map(function(host) {
|
||||||
|
return E('option', {
|
||||||
|
'selected': (rrdtool.opts.host == host) ? 'selected' : null
|
||||||
|
}, [ host ])
|
||||||
|
}));
|
||||||
|
|
||||||
|
var spanSel = E('select', { 'style': 'max-width:170px', 'data-name': 'timespan' }, L.toArray(uci.get('luci_statistics', 'collectd_rrdtool', 'RRATimespans')).map(function(span) {
|
||||||
|
return E('option', {
|
||||||
|
'selected': (rrdtool.opts.timespan == span) ? 'selected' : null
|
||||||
|
}, [ span ])
|
||||||
|
}));
|
||||||
|
|
||||||
|
var timeSel = E('select', { 'style': 'max-width:170px', 'data-name': 'refresh' }, [
|
||||||
|
E('option', { 'value': 0 }, [ _('Do not refresh') ]),
|
||||||
|
E('option', { 'value': 5 }, [ _('Every 5 seconds') ]),
|
||||||
|
E('option', { 'value': 30 }, [ _('Every 30 seconds') ]),
|
||||||
|
E('option', { 'value': 60 }, [ _('Every minute') ])
|
||||||
|
]);
|
||||||
|
|
||||||
|
var graphDiv = E('div', { 'data-name': 'graphs' });
|
||||||
|
|
||||||
|
var view = E([], [
|
||||||
|
E('h2', {}, [ _('Statistics') ]),
|
||||||
|
E('div', {}, [
|
||||||
|
E('div', {}, [
|
||||||
|
hostSel,
|
||||||
|
E('button', {
|
||||||
|
'class': 'cbi-button cbi-button-apply',
|
||||||
|
'click': ui.createHandlerFn(this, 'updateGraphs', hostSel, spanSel, timeSel, graphDiv, )
|
||||||
|
}, [ _('Display Host »') ]),
|
||||||
|
' ',
|
||||||
|
spanSel,
|
||||||
|
E('button', {
|
||||||
|
'class': 'cbi-button cbi-button-apply',
|
||||||
|
'click': ui.createHandlerFn(this, 'updateGraphs', hostSel, spanSel, timeSel, graphDiv)
|
||||||
|
}, [ _('Display timespan »') ]),
|
||||||
|
' ',
|
||||||
|
timeSel,
|
||||||
|
E('button', {
|
||||||
|
'class': 'cbi-button cbi-button-apply',
|
||||||
|
'click': ui.createHandlerFn(this, 'togglePolling', hostSel, spanSel, timeSel, graphDiv)
|
||||||
|
}, [ _('Apply interval »') ])
|
||||||
|
]),
|
||||||
|
E('hr'),
|
||||||
|
graphDiv
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
requestAnimationFrame(L.bind(this.updateGraphs, this, hostSel, spanSel, timeSel, graphDiv));
|
||||||
|
|
||||||
|
return view;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave: null,
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset: null
|
||||||
|
});
|
|
@ -1,132 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.controller.luci_statistics.luci_statistics", package.seeall)
|
|
||||||
|
|
||||||
function index()
|
|
||||||
|
|
||||||
require("nixio.fs")
|
|
||||||
require("luci.util")
|
|
||||||
require("luci.statistics.datatree")
|
|
||||||
|
|
||||||
-- create toplevel menu nodes
|
|
||||||
local st = entry({"admin", "statistics"}, template("admin_statistics/index"), _("Statistics"), 80)
|
|
||||||
st.index = true
|
|
||||||
|
|
||||||
entry({"admin", "statistics", "collectd"}, view("statistics/collectd"), _("Setup"), 20).subindex = true
|
|
||||||
|
|
||||||
-- output views
|
|
||||||
local page = entry( { "admin", "statistics", "graph" }, template("admin_statistics/index"), _("Graphs"), 10)
|
|
||||||
page.setuser = "nobody"
|
|
||||||
page.setgroup = "nogroup"
|
|
||||||
|
|
||||||
local vars = luci.http.formvalue(nil, true)
|
|
||||||
local span = vars.timespan or nil
|
|
||||||
local host = vars.host or nil
|
|
||||||
|
|
||||||
-- get rrd data tree
|
|
||||||
local tree = luci.statistics.datatree.Instance(host)
|
|
||||||
|
|
||||||
local _, plugin, idx
|
|
||||||
for _, plugin, idx in luci.util.vspairs( tree:plugins() ) do
|
|
||||||
|
|
||||||
-- get plugin instances
|
|
||||||
local instances = tree:plugin_instances( plugin )
|
|
||||||
|
|
||||||
-- load plugin menu entry from the description
|
|
||||||
local plugin_name = "luci.statistics.rrdtool.definitions." .. plugin
|
|
||||||
local stat, def = pcall( require, plugin_name )
|
|
||||||
if stat and def and type(def.item) == "function" then
|
|
||||||
entry(
|
|
||||||
{ "admin", "statistics", "graph", plugin },
|
|
||||||
call("statistics_render"), def.item(), idx
|
|
||||||
).query = { timespan = span , host = host }
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if more then one instance is found then generate submenu
|
|
||||||
if #instances > 1 then
|
|
||||||
local _, inst, idx2
|
|
||||||
for _, inst, idx2 in luci.util.vspairs(instances) do
|
|
||||||
-- instance menu entry
|
|
||||||
entry(
|
|
||||||
{ "admin", "statistics", "graph", plugin, inst },
|
|
||||||
call("statistics_render"), inst, idx2
|
|
||||||
).query = { timespan = span , host = host }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function statistics_render()
|
|
||||||
|
|
||||||
require("luci.statistics.rrdtool")
|
|
||||||
require("luci.template")
|
|
||||||
require("luci.model.uci")
|
|
||||||
|
|
||||||
local vars = luci.http.formvalue()
|
|
||||||
local req = luci.dispatcher.context.request
|
|
||||||
local path = luci.dispatcher.context.path
|
|
||||||
local uci = luci.model.uci.cursor()
|
|
||||||
local spans = luci.util.split( uci:get( "luci_statistics", "collectd_rrdtool", "RRATimespans" ), "%s+", nil, true )
|
|
||||||
local span = vars.timespan or uci:get( "luci_statistics", "rrdtool", "default_timespan" ) or spans[1]
|
|
||||||
local host = vars.host or uci:get( "luci_statistics", "collectd", "Hostname" ) or luci.sys.hostname()
|
|
||||||
local opts = { host = vars.host }
|
|
||||||
local graph = luci.statistics.rrdtool.Graph( luci.util.parse_units( span ), opts )
|
|
||||||
local hosts = graph.tree:host_instances()
|
|
||||||
|
|
||||||
local is_index = false
|
|
||||||
local i, p, inst, idx
|
|
||||||
|
|
||||||
-- deliver image
|
|
||||||
if vars.img then
|
|
||||||
local l12 = require "luci.ltn12"
|
|
||||||
local png = io.open(graph.opts.imgpath .. "/" .. vars.img:gsub("%.+", "."), "r")
|
|
||||||
if png then
|
|
||||||
luci.http.prepare_content("image/png")
|
|
||||||
l12.pump.all(l12.source.file(png), luci.http.write)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local plugin, instances
|
|
||||||
local images = { }
|
|
||||||
|
|
||||||
-- find requested plugin and instance
|
|
||||||
for i, p in ipairs( luci.dispatcher.context.path ) do
|
|
||||||
if luci.dispatcher.context.path[i] == "graph" then
|
|
||||||
plugin = luci.dispatcher.context.path[i+1]
|
|
||||||
instances = { luci.dispatcher.context.path[i+2] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- no instance requested, find all instances
|
|
||||||
if #instances == 0 then
|
|
||||||
--instances = { graph.tree:plugin_instances( plugin )[1] }
|
|
||||||
instances = graph.tree:plugin_instances( plugin )
|
|
||||||
is_index = (#instances > 1)
|
|
||||||
|
|
||||||
-- index instance requested
|
|
||||||
elseif instances[1] == "-" then
|
|
||||||
instances[1] = ""
|
|
||||||
is_index = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- render graphs
|
|
||||||
for i, inst in luci.util.vspairs( instances ) do
|
|
||||||
for i, img in luci.util.vspairs( graph:render( plugin, inst, is_index ) ) do
|
|
||||||
table.insert( images, graph:strippngpath( img ) )
|
|
||||||
images[images[#images]] = inst
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
luci.template.render( "public_statistics/graph", {
|
|
||||||
images = images,
|
|
||||||
plugin = plugin,
|
|
||||||
timespans = spans,
|
|
||||||
current_timespan = span,
|
|
||||||
hosts = hosts,
|
|
||||||
current_host = host,
|
|
||||||
is_index = is_index
|
|
||||||
} )
|
|
||||||
end
|
|
|
@ -1,205 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.datatree", package.seeall)
|
|
||||||
|
|
||||||
local util = require("luci.util")
|
|
||||||
local sys = require("luci.sys")
|
|
||||||
local fs = require("nixio.fs")
|
|
||||||
local uci = require("luci.model.uci").cursor()
|
|
||||||
local sections = uci:get_all("luci_statistics")
|
|
||||||
|
|
||||||
|
|
||||||
Instance = util.class()
|
|
||||||
|
|
||||||
function Instance.__init__( self, host )
|
|
||||||
self._host = host or sys.hostname()
|
|
||||||
self._libdir = "/usr/lib/collectd"
|
|
||||||
self._rrddir = "/tmp/rrd"
|
|
||||||
|
|
||||||
if sections and sections.collectd then
|
|
||||||
self._host = host or sections.collectd.Hostname or sys.hostname()
|
|
||||||
self._libdir = sections.collectd.PluginDir or "/usr/lib/collectd"
|
|
||||||
end
|
|
||||||
if sections and sections.collectd_rrdtool then
|
|
||||||
self._rrddir = sections.collectd_rrdtool.DataDir or "/tmp/rrd"
|
|
||||||
end
|
|
||||||
|
|
||||||
self._libdir = self._libdir:gsub("/$","")
|
|
||||||
self._rrddir = self._rrddir:gsub("/$","")
|
|
||||||
self._plugins = { }
|
|
||||||
|
|
||||||
self:_scan()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance._mkpath( self, plugin, pinstance )
|
|
||||||
local dir = self._rrddir .. "/" .. self._host
|
|
||||||
|
|
||||||
if type(plugin) == "string" and plugin:len() > 0 then
|
|
||||||
dir = dir .. "/" .. plugin
|
|
||||||
|
|
||||||
if type(pinstance) == "string" and pinstance:len() > 0 then
|
|
||||||
dir = dir .. "-" .. pinstance
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return dir
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance._ls( self, ... )
|
|
||||||
local ditr = fs.dir(self:_mkpath(...))
|
|
||||||
if ditr then
|
|
||||||
local dirs = { }
|
|
||||||
while true do
|
|
||||||
local d = ditr()
|
|
||||||
if not d then break end
|
|
||||||
dirs[#dirs+1] = d
|
|
||||||
end
|
|
||||||
return dirs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance._notzero( self, table )
|
|
||||||
for k in pairs(table) do
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance._scan( self )
|
|
||||||
local dirs = self:_ls()
|
|
||||||
if not dirs then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- for i, plugin in ipairs( dirs ) do
|
|
||||||
-- if plugin:match("%w+.so") then
|
|
||||||
-- self._plugins[ plugin:gsub("%.so$", "") ] = { }
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
|
|
||||||
for _, dir in ipairs(dirs) do
|
|
||||||
if dir ~= "." and dir ~= ".." and
|
|
||||||
fs.stat(self:_mkpath(dir)).type == "dir"
|
|
||||||
then
|
|
||||||
local plugin = dir:gsub("%-.+$", "")
|
|
||||||
if not self._plugins[plugin] then
|
|
||||||
self._plugins[plugin] = { }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for plugin, instances in pairs( self._plugins ) do
|
|
||||||
|
|
||||||
local dirs = self:_ls()
|
|
||||||
|
|
||||||
if type(dirs) == "table" then
|
|
||||||
for i, dir in ipairs(dirs) do
|
|
||||||
if dir:find( plugin .. "%-" ) or dir == plugin then
|
|
||||||
local instance = ""
|
|
||||||
|
|
||||||
if dir ~= plugin then
|
|
||||||
instance = dir:gsub( plugin .. "%-", "", 1 )
|
|
||||||
end
|
|
||||||
|
|
||||||
instances[instance] = { }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for instance, data_instances in pairs( instances ) do
|
|
||||||
|
|
||||||
dirs = self:_ls(plugin, instance)
|
|
||||||
|
|
||||||
if type(dirs) == "table" then
|
|
||||||
for i, file in ipairs(dirs) do
|
|
||||||
if file:find("%.rrd") then
|
|
||||||
file = file:gsub("%.rrd","")
|
|
||||||
|
|
||||||
local data_type
|
|
||||||
local data_instance
|
|
||||||
|
|
||||||
if file:find("%-") then
|
|
||||||
data_type = file:gsub( "%-.+","" )
|
|
||||||
data_instance = file:gsub( "[^%-]-%-", "", 1 )
|
|
||||||
else
|
|
||||||
data_type = file
|
|
||||||
data_instance = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
if not data_instances[data_type] then
|
|
||||||
data_instances[data_type] = { data_instance }
|
|
||||||
else
|
|
||||||
table.insert( data_instances[data_type], data_instance )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function Instance.plugins( self )
|
|
||||||
local rv = { }
|
|
||||||
|
|
||||||
for plugin, val in pairs( self._plugins ) do
|
|
||||||
if self:_notzero( val ) then
|
|
||||||
table.insert( rv, plugin )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.plugin_instances( self, plugin )
|
|
||||||
local rv = { }
|
|
||||||
|
|
||||||
for instance, val in pairs( self._plugins[plugin] ) do
|
|
||||||
table.insert( rv, instance )
|
|
||||||
end
|
|
||||||
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.data_types( self, plugin, instance )
|
|
||||||
local rv = { }
|
|
||||||
local p = self._plugins[plugin]
|
|
||||||
|
|
||||||
if type(p) == "table" and type(p[instance]) == "table" then
|
|
||||||
for type, val in pairs(p[instance]) do
|
|
||||||
table.insert( rv, type )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.data_instances( self, plugin, instance, dtype )
|
|
||||||
local rv = { }
|
|
||||||
local p = self._plugins[plugin]
|
|
||||||
|
|
||||||
if type(p) == "table" and type(p[instance]) == "table" and type(p[instance][dtype]) == "table" then
|
|
||||||
for i, instance in ipairs(p[instance][dtype]) do
|
|
||||||
table.insert( rv, instance )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.host_instances( self )
|
|
||||||
local hosts_path = fs.glob(self._rrddir..'/*')
|
|
||||||
local hosts = { }
|
|
||||||
|
|
||||||
if hosts_path then
|
|
||||||
local path
|
|
||||||
for path in hosts_path do
|
|
||||||
hosts[#hosts+1] = fs.basename(path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return hosts
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.i18n", package.seeall)
|
|
||||||
|
|
||||||
local util = require("luci.util")
|
|
||||||
local i18n = require("luci.i18n")
|
|
||||||
|
|
||||||
|
|
||||||
Instance = util.class()
|
|
||||||
|
|
||||||
function Instance.__init__( self, graph )
|
|
||||||
self.i18n = i18n
|
|
||||||
self.graph = graph
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance._subst( self, str, val )
|
|
||||||
str = str:gsub( "%%H", self.graph.opts.host or "" )
|
|
||||||
str = str:gsub( "%%pn", val.plugin or "" )
|
|
||||||
str = str:gsub( "%%pi", val.pinst or "" )
|
|
||||||
str = str:gsub( "%%dt", val.dtype or "" )
|
|
||||||
str = str:gsub( "%%di", val.dinst or "" )
|
|
||||||
str = str:gsub( "%%ds", val.dsrc or "" )
|
|
||||||
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.title( self, plugin, pinst, dtype, dinst, user_title )
|
|
||||||
|
|
||||||
local title = user_title or
|
|
||||||
"p=%s/pi=%s/dt=%s/di=%s" % {
|
|
||||||
plugin,
|
|
||||||
(pinst and #pinst > 0) and pinst or "(nil)",
|
|
||||||
(dtype and #dtype > 0) and dtype or "(nil)",
|
|
||||||
(dinst and #dinst > 0) and dinst or "(nil)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return self:_subst( title, {
|
|
||||||
plugin = plugin,
|
|
||||||
pinst = pinst,
|
|
||||||
dtype = dtype,
|
|
||||||
dinst = dinst
|
|
||||||
} )
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.label( self, plugin, pinst, dtype, dinst, user_label )
|
|
||||||
|
|
||||||
local label = user_label or
|
|
||||||
"dt=%s/di=%s" % {
|
|
||||||
(dtype and #dtype > 0) and dtype or "(nil)",
|
|
||||||
(dinst and #dinst > 0) and dinst or "(nil)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return self:_subst( label, {
|
|
||||||
plugin = plugin,
|
|
||||||
pinst = pinst,
|
|
||||||
dtype = dtype,
|
|
||||||
dinst = dinst
|
|
||||||
} )
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.ds( self, source )
|
|
||||||
|
|
||||||
local label = source.title or
|
|
||||||
"dt=%s/di=%s/ds=%s" % {
|
|
||||||
(source.type and #source.type > 0) and source.type or "(nil)",
|
|
||||||
(source.instance and #source.instance > 0) and source.instance or "(nil)",
|
|
||||||
(source.ds and #source.ds > 0) and source.ds or "(nil)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return self:_subst( label, {
|
|
||||||
dtype = source.type,
|
|
||||||
dinst = source.instance,
|
|
||||||
dsrc = source.ds
|
|
||||||
} ):gsub(":", "\\:")
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,581 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool", package.seeall)
|
|
||||||
|
|
||||||
local tree = require("luci.statistics.datatree")
|
|
||||||
local colors = require("luci.statistics.rrdtool.colors")
|
|
||||||
local i18n = require("luci.statistics.i18n")
|
|
||||||
local uci = require("luci.model.uci").cursor()
|
|
||||||
local util = require("luci.util")
|
|
||||||
local sys = require("luci.sys")
|
|
||||||
local fs = require("nixio.fs")
|
|
||||||
|
|
||||||
|
|
||||||
Graph = util.class()
|
|
||||||
|
|
||||||
function Graph.__init__( self, timespan, opts )
|
|
||||||
|
|
||||||
opts = opts or { }
|
|
||||||
|
|
||||||
local sections = uci:get_all( "luci_statistics" )
|
|
||||||
|
|
||||||
-- options
|
|
||||||
opts.timespan = timespan or sections.rrdtool.default_timespan or 900
|
|
||||||
opts.rrasingle = opts.rrasingle or ( sections.collectd_rrdtool.RRASingle == "1" )
|
|
||||||
opts.rramax = opts.rramax or ( sections.collectd_rrdtool.RRAMax == "1" )
|
|
||||||
opts.host = opts.host or sections.collectd.Hostname or sys.hostname()
|
|
||||||
opts.width = opts.width or sections.rrdtool.image_width or 400
|
|
||||||
opts.height = opts.height or sections.rrdtool.image_height or 100
|
|
||||||
opts.rrdpath = opts.rrdpath or sections.collectd_rrdtool.DataDir or "/tmp/rrd"
|
|
||||||
opts.imgpath = opts.imgpath or sections.rrdtool.image_path or "/tmp/rrdimg"
|
|
||||||
opts.rrdpath = opts.rrdpath:gsub("/$","")
|
|
||||||
opts.imgpath = opts.imgpath:gsub("/$","")
|
|
||||||
|
|
||||||
-- helper classes
|
|
||||||
self.colors = colors.Instance()
|
|
||||||
self.tree = tree.Instance(opts.host)
|
|
||||||
self.i18n = i18n.Instance( self )
|
|
||||||
|
|
||||||
-- rrdtool default args
|
|
||||||
self.args = {
|
|
||||||
"-a", "PNG",
|
|
||||||
"-s", "NOW-" .. opts.timespan,
|
|
||||||
"-w", opts.width,
|
|
||||||
"-h", opts.height
|
|
||||||
}
|
|
||||||
|
|
||||||
-- store options
|
|
||||||
self.opts = opts
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph._mkpath( self, plugin, plugin_instance, dtype, dtype_instance )
|
|
||||||
local t = self.opts.host .. "/" .. plugin
|
|
||||||
if type(plugin_instance) == "string" and plugin_instance:len() > 0 then
|
|
||||||
t = t .. "-" .. plugin_instance
|
|
||||||
end
|
|
||||||
t = t .. "/" .. dtype
|
|
||||||
if type(dtype_instance) == "string" and dtype_instance:len() > 0 then
|
|
||||||
t = t .. "-" .. dtype_instance
|
|
||||||
end
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph.mkrrdpath( self, ... )
|
|
||||||
return string.format( "%s/%s.rrd", self.opts.rrdpath, self:_mkpath( ... ):gsub("\\", "\\\\"):gsub(":", "\\:") )
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph.mkpngpath( self, ... )
|
|
||||||
return string.format( "%s/%s.%i.png", self.opts.imgpath, self:_mkpath( ... ), self.opts.timespan )
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph.strippngpath( self, path )
|
|
||||||
return path:sub( self.opts.imgpath:len() + 2 )
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph._forcelol( self, list )
|
|
||||||
if type(list[1]) ~= "table" then
|
|
||||||
return( { list } )
|
|
||||||
end
|
|
||||||
return( list )
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph._rrdtool( self, def, rrd )
|
|
||||||
|
|
||||||
-- prepare directory
|
|
||||||
local dir = def[1]:gsub("/[^/]+$","")
|
|
||||||
fs.mkdirr( dir )
|
|
||||||
|
|
||||||
-- construct commandline
|
|
||||||
local cmdline = { "rrdtool", "graph" }
|
|
||||||
|
|
||||||
-- copy default arguments to def stack
|
|
||||||
for i, opt in ipairs(self.args) do
|
|
||||||
table.insert( def, 1 + i, opt )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- construct commandline from def stack
|
|
||||||
for i, opt in ipairs(def) do
|
|
||||||
opt = opt .. "" -- force string
|
|
||||||
|
|
||||||
if rrd then
|
|
||||||
opt = opt:gsub( "{file}", rrd )
|
|
||||||
end
|
|
||||||
|
|
||||||
cmdline[#cmdline+1] = util.shellquote(opt)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- execute rrdtool
|
|
||||||
local rrdtool = io.popen(table.concat(cmdline, " "))
|
|
||||||
rrdtool:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph._generic( self, opts, plugin, plugin_instance, dtype, index )
|
|
||||||
|
|
||||||
-- generated graph defs
|
|
||||||
local defs = { }
|
|
||||||
|
|
||||||
-- internal state variables
|
|
||||||
local _args = { }
|
|
||||||
local _sources = { }
|
|
||||||
local _stack_neg = { }
|
|
||||||
local _stack_pos = { }
|
|
||||||
local _longest_name = 0
|
|
||||||
local _has_totals = false
|
|
||||||
|
|
||||||
-- some convenient aliases
|
|
||||||
local _ti = table.insert
|
|
||||||
local _sf = string.format
|
|
||||||
|
|
||||||
-- local helper: append a string.format() formatted string to given table
|
|
||||||
function _tif( list, fmt, ... )
|
|
||||||
table.insert( list, string.format( fmt, ... ) )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- local helper: create definitions for min, max, avg and create *_nnl (not null) variable from avg
|
|
||||||
function __def(source)
|
|
||||||
|
|
||||||
local inst = source.sname
|
|
||||||
local rrd = source.rrd:gsub(":", "\\:")
|
|
||||||
local ds = source.ds
|
|
||||||
|
|
||||||
if not ds or ds:len() == 0 then ds = "value" end
|
|
||||||
|
|
||||||
_tif( _args, "DEF:%s_avg_raw=%s:%s:AVERAGE", inst, rrd, ds )
|
|
||||||
_tif( _args, "CDEF:%s_avg=%s_avg_raw,%s", inst, inst, source.transform_rpn )
|
|
||||||
|
|
||||||
if not self.opts.rrasingle then
|
|
||||||
_tif( _args, "DEF:%s_min_raw=%s:%s:MIN", inst, rrd, ds )
|
|
||||||
_tif( _args, "CDEF:%s_min=%s_min_raw,%s", inst, inst, source.transform_rpn )
|
|
||||||
_tif( _args, "DEF:%s_max_raw=%s:%s:MAX", inst, rrd, ds )
|
|
||||||
_tif( _args, "CDEF:%s_max=%s_max_raw,%s", inst, inst, source.transform_rpn )
|
|
||||||
end
|
|
||||||
|
|
||||||
_tif( _args, "CDEF:%s_nnl=%s_avg,UN,0,%s_avg,IF", inst, inst, inst )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- local helper: create cdefs depending on source options like flip and overlay
|
|
||||||
function __cdef(source)
|
|
||||||
|
|
||||||
local prev
|
|
||||||
|
|
||||||
-- find previous source, choose stack depending on flip state
|
|
||||||
if source.flip then
|
|
||||||
prev = _stack_neg[#_stack_neg]
|
|
||||||
else
|
|
||||||
prev = _stack_pos[#_stack_pos]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- is first source in stack or overlay source: source_stk = source_nnl
|
|
||||||
if not prev or source.overlay then
|
|
||||||
if self.opts.rrasingle or not self.opts.rramax then
|
|
||||||
-- create cdef statement for cumulative stack (no NaNs) and also
|
|
||||||
-- for display (preserving NaN where no points should be displayed)
|
|
||||||
_tif( _args, "CDEF:%s_stk=%s_nnl", source.sname, source.sname )
|
|
||||||
_tif( _args, "CDEF:%s_plot=%s_avg", source.sname, source.sname )
|
|
||||||
else
|
|
||||||
-- create cdef statement for cumulative stack (no NaNs) and also
|
|
||||||
-- for display (preserving NaN where no points should be displayed)
|
|
||||||
_tif( _args, "CDEF:%s_stk=%s_nnl", source.sname, source.sname )
|
|
||||||
_tif( _args, "CDEF:%s_plot=%s_max", source.sname, source.sname )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- is subsequent source without overlay: source_stk = source_nnl + previous_stk
|
|
||||||
else
|
|
||||||
if self.opts.rrasingle or not self.opts.rramax then
|
|
||||||
-- create cdef statement
|
|
||||||
_tif( _args, "CDEF:%s_stk=%s_nnl,%s_stk,+", source.sname, source.sname, prev )
|
|
||||||
_tif( _args, "CDEF:%s_plot=%s_avg,%s_stk,+", source.sname, source.sname, prev )
|
|
||||||
else
|
|
||||||
-- create cdef statement
|
|
||||||
_tif( _args, "CDEF:%s_stk=%s_nnl,%s_stk,+", source.sname, source.sname, prev )
|
|
||||||
_tif( _args, "CDEF:%s_plot=%s_max,%s_stk,+", source.sname, source.sname, prev )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create multiply by minus one cdef if flip is enabled
|
|
||||||
if source.flip then
|
|
||||||
|
|
||||||
-- create cdef statement: source_stk = source_stk * -1
|
|
||||||
_tif( _args, "CDEF:%s_neg=%s_plot,-1,*", source.sname, source.sname )
|
|
||||||
|
|
||||||
-- push to negative stack if overlay is disabled
|
|
||||||
if not source.overlay then
|
|
||||||
_ti( _stack_neg, source.sname )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- no flipping, push to positive stack if overlay is disabled
|
|
||||||
elseif not source.overlay then
|
|
||||||
|
|
||||||
-- push to positive stack
|
|
||||||
_ti( _stack_pos, source.sname )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- calculate total amount of data if requested
|
|
||||||
if source.total then
|
|
||||||
_tif( _args,
|
|
||||||
"CDEF:%s_avg_sample=%s_avg,UN,0,%s_avg,IF,sample_len,*",
|
|
||||||
source.sname, source.sname, source.sname
|
|
||||||
)
|
|
||||||
|
|
||||||
_tif( _args,
|
|
||||||
"CDEF:%s_avg_sum=PREV,UN,0,PREV,IF,%s_avg_sample,+",
|
|
||||||
source.sname, source.sname, source.sname
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- local helper: create cdefs required for calculating total values
|
|
||||||
function __cdef_totals()
|
|
||||||
if _has_totals then
|
|
||||||
_tif( _args, "CDEF:mytime=%s_avg,TIME,TIME,IF", _sources[1].sname )
|
|
||||||
_ti( _args, "CDEF:sample_len_raw=mytime,PREV(mytime),-" )
|
|
||||||
_ti( _args, "CDEF:sample_len=sample_len_raw,UN,0,sample_len_raw,IF" )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- local helper: create line and area statements
|
|
||||||
function __line(source)
|
|
||||||
|
|
||||||
local line_color
|
|
||||||
local area_color
|
|
||||||
local legend
|
|
||||||
local var
|
|
||||||
|
|
||||||
-- find colors: try source, then opts.colors; fall back to random color
|
|
||||||
if type(source.color) == "string" then
|
|
||||||
line_color = source.color
|
|
||||||
area_color = self.colors:from_string( line_color )
|
|
||||||
elseif type(opts.colors[source.name:gsub("[^%w]","_")]) == "string" then
|
|
||||||
line_color = opts.colors[source.name:gsub("[^%w]","_")]
|
|
||||||
area_color = self.colors:from_string( line_color )
|
|
||||||
else
|
|
||||||
area_color = self.colors:random()
|
|
||||||
line_color = self.colors:to_string( area_color )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- derive area background color from line color
|
|
||||||
area_color = self.colors:to_string( self.colors:faded( area_color ) )
|
|
||||||
|
|
||||||
-- choose source_plot or source_neg variable depending on flip state
|
|
||||||
if source.flip then
|
|
||||||
var = "neg"
|
|
||||||
else
|
|
||||||
var = "plot"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create legend
|
|
||||||
legend = _sf( "%-" .. _longest_name .. "s", source.title )
|
|
||||||
|
|
||||||
-- create area if not disabled
|
|
||||||
if not source.noarea then
|
|
||||||
_tif( _args, "AREA:%s_%s#%s", source.sname, var, area_color )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create line1 statement
|
|
||||||
_tif( _args, "LINE%d:%s_%s#%s:%s",
|
|
||||||
source.width or (source.noarea and 2 or 1),
|
|
||||||
source.sname, var, line_color, legend )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- local helper: create gprint statements
|
|
||||||
function __gprint(source)
|
|
||||||
|
|
||||||
local numfmt = opts.number_format or "%6.1lf"
|
|
||||||
local totfmt = opts.totals_format or "%5.1lf%s"
|
|
||||||
|
|
||||||
-- don't include MIN if rrasingle is enabled
|
|
||||||
if not self.opts.rrasingle then
|
|
||||||
_tif( _args, "GPRINT:%s_min:MIN:\tMin\\: %s", source.sname, numfmt )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- always include AVERAGE
|
|
||||||
_tif( _args, "GPRINT:%s_avg:AVERAGE:\tAvg\\: %s", source.sname, numfmt )
|
|
||||||
|
|
||||||
-- don't include MAX if rrasingle is enabled
|
|
||||||
if not self.opts.rrasingle then
|
|
||||||
_tif( _args, "GPRINT:%s_max:MAX:\tMax\\: %s", source.sname, numfmt )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- include total count if requested else include LAST
|
|
||||||
if source.total then
|
|
||||||
_tif( _args, "GPRINT:%s_avg_sum:LAST:(ca. %s Total)\\l", source.sname, totfmt )
|
|
||||||
else
|
|
||||||
_tif( _args, "GPRINT:%s_avg:LAST:\tLast\\: %s\\l", source.sname, numfmt )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- find all data sources
|
|
||||||
--
|
|
||||||
|
|
||||||
-- find data types
|
|
||||||
local data_types
|
|
||||||
|
|
||||||
if dtype then
|
|
||||||
data_types = { dtype }
|
|
||||||
else
|
|
||||||
data_types = opts.data.types or { }
|
|
||||||
end
|
|
||||||
|
|
||||||
if not ( dtype or opts.data.types ) then
|
|
||||||
if opts.data.instances then
|
|
||||||
for k, v in pairs(opts.data.instances) do
|
|
||||||
_ti( data_types, k )
|
|
||||||
end
|
|
||||||
elseif opts.data.sources then
|
|
||||||
for k, v in pairs(opts.data.sources) do
|
|
||||||
_ti( data_types, k )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- iterate over data types
|
|
||||||
for i, dtype in ipairs(data_types) do
|
|
||||||
|
|
||||||
-- find instances
|
|
||||||
|
|
||||||
local data_instances
|
|
||||||
|
|
||||||
if not opts.per_instance then
|
|
||||||
if type(opts.data.instances) == "table" and type(opts.data.instances[dtype]) == "table" then
|
|
||||||
data_instances = opts.data.instances[dtype]
|
|
||||||
else
|
|
||||||
data_instances = self.tree:data_instances( plugin, plugin_instance, dtype )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(data_instances) ~= "table" or #data_instances == 0 then data_instances = { "" } end
|
|
||||||
|
|
||||||
|
|
||||||
-- iterate over data instances
|
|
||||||
for i, dinst in ipairs(data_instances) do
|
|
||||||
|
|
||||||
-- construct combined data type / instance name
|
|
||||||
local dname = dtype
|
|
||||||
|
|
||||||
if dinst:len() > 0 then
|
|
||||||
dname = dname .. "_" .. dinst
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- find sources
|
|
||||||
local data_sources = { "value" }
|
|
||||||
|
|
||||||
if type(opts.data.sources) == "table" then
|
|
||||||
if type(opts.data.sources[dname]) == "table" then
|
|
||||||
data_sources = opts.data.sources[dname]
|
|
||||||
elseif type(opts.data.sources[dtype]) == "table" then
|
|
||||||
data_sources = opts.data.sources[dtype]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- iterate over data sources
|
|
||||||
for i, dsource in ipairs(data_sources) do
|
|
||||||
|
|
||||||
local dsname = dtype .. "_" .. dinst:gsub("[^%w]","_") .. "_" .. dsource
|
|
||||||
local altname = dtype .. "__" .. dsource
|
|
||||||
|
|
||||||
--assert(dtype ~= "ping", dsname .. " or " .. altname)
|
|
||||||
|
|
||||||
-- find datasource options
|
|
||||||
local dopts = { }
|
|
||||||
|
|
||||||
if type(opts.data.options) == "table" then
|
|
||||||
if type(opts.data.options[dsname]) == "table" then
|
|
||||||
dopts = opts.data.options[dsname]
|
|
||||||
elseif type(opts.data.options[altname]) == "table" then
|
|
||||||
dopts = opts.data.options[altname]
|
|
||||||
elseif type(opts.data.options[dname]) == "table" then
|
|
||||||
dopts = opts.data.options[dname]
|
|
||||||
elseif type(opts.data.options[dtype]) == "table" then
|
|
||||||
dopts = opts.data.options[dtype]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- store values
|
|
||||||
_ti( _sources, {
|
|
||||||
rrd = dopts.rrd or self:mkrrdpath( plugin, plugin_instance, dtype, dinst ),
|
|
||||||
color = dopts.color or self.colors:to_string( self.colors:random() ),
|
|
||||||
flip = dopts.flip or false,
|
|
||||||
total = dopts.total or false,
|
|
||||||
overlay = dopts.overlay or false,
|
|
||||||
transform_rpn = dopts.transform_rpn or "0,+",
|
|
||||||
noarea = dopts.noarea or false,
|
|
||||||
title = dopts.title or nil,
|
|
||||||
weight = dopts.weight or
|
|
||||||
(dopts.negweight and -tonumber(dinst)) or
|
|
||||||
(dopts.posweight and tonumber(dinst)) or nil,
|
|
||||||
ds = dsource,
|
|
||||||
type = dtype,
|
|
||||||
instance = dinst,
|
|
||||||
index = #_sources + 1,
|
|
||||||
sname = ( #_sources + 1 ) .. dtype
|
|
||||||
} )
|
|
||||||
|
|
||||||
|
|
||||||
-- generate datasource title
|
|
||||||
_sources[#_sources].title = self.i18n:ds( _sources[#_sources] )
|
|
||||||
|
|
||||||
|
|
||||||
-- find longest name ...
|
|
||||||
if _sources[#_sources].title:len() > _longest_name then
|
|
||||||
_longest_name = _sources[#_sources].title:len()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- has totals?
|
|
||||||
if _sources[#_sources].total then
|
|
||||||
_has_totals = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- construct diagrams
|
|
||||||
--
|
|
||||||
|
|
||||||
-- if per_instance is enabled then find all instances from the first datasource in diagram
|
|
||||||
-- if per_instance is disabled then use an empty pseudo instance and use model provided values
|
|
||||||
local instances = { "" }
|
|
||||||
|
|
||||||
if opts.per_instance then
|
|
||||||
instances = self.tree:data_instances( plugin, plugin_instance, _sources[1].type )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- iterate over instances
|
|
||||||
for i, instance in ipairs(instances) do
|
|
||||||
|
|
||||||
-- store title and vlabel
|
|
||||||
_ti( _args, "-t" )
|
|
||||||
_ti( _args, self.i18n:title( plugin, plugin_instance, _sources[1].type, instance, opts.title ) )
|
|
||||||
_ti( _args, "-v" )
|
|
||||||
_ti( _args, self.i18n:label( plugin, plugin_instance, _sources[1].type, instance, opts.vlabel ) )
|
|
||||||
if opts.y_max then
|
|
||||||
_ti ( _args, "-u" )
|
|
||||||
_ti ( _args, opts.y_max )
|
|
||||||
end
|
|
||||||
if opts.y_min then
|
|
||||||
_ti ( _args, "-l" )
|
|
||||||
_ti ( _args, opts.y_min )
|
|
||||||
end
|
|
||||||
if opts.units_exponent then
|
|
||||||
_ti ( _args, "-X" )
|
|
||||||
_ti ( _args, opts.units_exponent )
|
|
||||||
end
|
|
||||||
if opts.alt_autoscale then
|
|
||||||
_ti ( _args, "-A" )
|
|
||||||
end
|
|
||||||
if opts.alt_autoscale_max then
|
|
||||||
_ti ( _args, "-M" )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- store additional rrd options
|
|
||||||
if opts.rrdopts then
|
|
||||||
for i, o in ipairs(opts.rrdopts) do _ti( _args, o ) end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- sort sources
|
|
||||||
table.sort(_sources, function(a, b)
|
|
||||||
local x = a.weight or a.index or 0
|
|
||||||
local y = b.weight or b.index or 0
|
|
||||||
return x < y
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- define colors in order
|
|
||||||
if opts.ordercolor then
|
|
||||||
for i, source in ipairs(_sources) do
|
|
||||||
source.color = self.colors:defined(i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create DEF statements for each instance
|
|
||||||
for i, source in ipairs(_sources) do
|
|
||||||
-- fixup properties for per instance mode...
|
|
||||||
if opts.per_instance then
|
|
||||||
source.instance = instance
|
|
||||||
source.rrd = self:mkrrdpath( plugin, plugin_instance, source.type, instance )
|
|
||||||
end
|
|
||||||
|
|
||||||
__def( source )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create CDEF required for calculating totals
|
|
||||||
__cdef_totals()
|
|
||||||
|
|
||||||
-- create CDEF statements for each instance in reversed order
|
|
||||||
for i, source in ipairs(_sources) do
|
|
||||||
__cdef( _sources[1 + #_sources - i] )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create LINE1, AREA and GPRINT statements for each instance
|
|
||||||
for i, source in ipairs(_sources) do
|
|
||||||
__line( source )
|
|
||||||
__gprint( source )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- prepend image path to arg stack
|
|
||||||
_ti( _args, 1, self:mkpngpath( plugin, plugin_instance, index .. instance ) )
|
|
||||||
|
|
||||||
-- push arg stack to definition list
|
|
||||||
_ti( defs, _args )
|
|
||||||
|
|
||||||
-- reset stacks
|
|
||||||
_args = { }
|
|
||||||
_stack_pos = { }
|
|
||||||
_stack_neg = { }
|
|
||||||
end
|
|
||||||
|
|
||||||
return defs
|
|
||||||
end
|
|
||||||
|
|
||||||
function Graph.render( self, plugin, plugin_instance, is_index )
|
|
||||||
|
|
||||||
dtype_instances = dtype_instances or { "" }
|
|
||||||
local pngs = { }
|
|
||||||
|
|
||||||
-- check for a whole graph handler
|
|
||||||
local plugin_def = "luci.statistics.rrdtool.definitions." .. plugin
|
|
||||||
local stat, def = pcall( require, plugin_def )
|
|
||||||
|
|
||||||
if stat and def and type(def.rrdargs) == "function" then
|
|
||||||
|
|
||||||
-- temporary image matrix
|
|
||||||
local _images = { }
|
|
||||||
|
|
||||||
-- get diagram definitions
|
|
||||||
for i, opts in ipairs( self:_forcelol( def.rrdargs( self, plugin, plugin_instance, nil, is_index ) ) ) do
|
|
||||||
if not is_index or not opts.detail then
|
|
||||||
_images[i] = { }
|
|
||||||
|
|
||||||
-- get diagram definition instances
|
|
||||||
local diagrams = self:_generic( opts, plugin, plugin_instance, nil, i )
|
|
||||||
|
|
||||||
-- render all diagrams
|
|
||||||
for j, def in ipairs( diagrams ) do
|
|
||||||
-- remember image
|
|
||||||
_images[i][j] = def[1]
|
|
||||||
|
|
||||||
-- exec
|
|
||||||
self:_rrdtool( def )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- remember images - XXX: fixme (will cause probs with asymmetric data)
|
|
||||||
for y = 1, #_images[1] do
|
|
||||||
for x = 1, #_images do
|
|
||||||
table.insert( pngs, _images[x][y] )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return pngs
|
|
||||||
end
|
|
|
@ -1,77 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.colors", package.seeall)
|
|
||||||
|
|
||||||
local util = require("luci.util")
|
|
||||||
|
|
||||||
|
|
||||||
Instance = util.class()
|
|
||||||
|
|
||||||
function Instance.from_string( self, s )
|
|
||||||
return {
|
|
||||||
tonumber(s:sub(1,2), 16),
|
|
||||||
tonumber(s:sub(3,4), 16),
|
|
||||||
tonumber(s:sub(5,6), 16)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.to_string( self, c )
|
|
||||||
return string.format(
|
|
||||||
"%02x%02x%02x",
|
|
||||||
math.floor(c[1]),
|
|
||||||
math.floor(c[2]),
|
|
||||||
math.floor(c[3])
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.defined( self, i )
|
|
||||||
local t = {
|
|
||||||
{230, 25, 75},
|
|
||||||
{245, 130, 48},
|
|
||||||
{255, 225, 25},
|
|
||||||
{60, 180, 75},
|
|
||||||
{70, 240, 240},
|
|
||||||
{0, 130, 200},
|
|
||||||
{0, 0, 128},
|
|
||||||
{170, 110, 40}
|
|
||||||
}
|
|
||||||
return string.format(
|
|
||||||
"%02x%02x%02x",
|
|
||||||
t[(i-1) % #t + 1][1], t[(i-1) % #t +1][2], t[(i-1) % #t + 1][3] )
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.random( self )
|
|
||||||
local r = math.random(255)
|
|
||||||
local g = math.random(255)
|
|
||||||
local min = 0
|
|
||||||
local max = 255
|
|
||||||
|
|
||||||
if ( r + g ) < 255 then
|
|
||||||
min = 255 - r - g
|
|
||||||
else
|
|
||||||
max = 511 - r - g
|
|
||||||
end
|
|
||||||
|
|
||||||
local b = min + math.floor( math.random() * ( max - min ) )
|
|
||||||
|
|
||||||
return { r, g, b }
|
|
||||||
end
|
|
||||||
|
|
||||||
function Instance.faded( self, fg, opts )
|
|
||||||
opts = opts or {}
|
|
||||||
opts.background = opts.background or { 255, 255, 255 }
|
|
||||||
opts.alpha = opts.alpha or 0.25
|
|
||||||
|
|
||||||
if type(opts.background) == "string" then
|
|
||||||
opts.background = _string_to_color(opts.background)
|
|
||||||
end
|
|
||||||
|
|
||||||
local bg = opts.background
|
|
||||||
|
|
||||||
return {
|
|
||||||
( opts.alpha * fg[1] ) + ( ( 1.0 - opts.alpha ) * bg[1] ),
|
|
||||||
( opts.alpha * fg[2] ) + ( ( 1.0 - opts.alpha ) * bg[2] ),
|
|
||||||
( opts.alpha * fg[3] ) + ( ( 1.0 - opts.alpha ) * bg[3] )
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,178 +0,0 @@
|
||||||
-- Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.apcups",package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("APC UPS")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
|
|
||||||
local lu = require("luci.util")
|
|
||||||
local rv = { }
|
|
||||||
|
|
||||||
-- Types and instances supported by APC UPS
|
|
||||||
-- e.g. ups_types -> { 'timeleft', 'charge', 'percent', 'voltage' }
|
|
||||||
-- e.g. ups_inst['voltage'] -> { 'input', 'battery' }
|
|
||||||
|
|
||||||
local ups_types = graph.tree:data_types( plugin, plugin_instance )
|
|
||||||
|
|
||||||
local ups_inst = {}
|
|
||||||
for _, t in ipairs(ups_types) do
|
|
||||||
ups_inst[t] = graph.tree:data_instances( plugin, plugin_instance, t )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if hash table or array is empty or nil-filled
|
|
||||||
|
|
||||||
local function empty( t )
|
|
||||||
for _, v in pairs(t) do
|
|
||||||
if type(v) then return false end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Append graph definition but only types/instances which are
|
|
||||||
-- supported and available to the plugin and UPS.
|
|
||||||
|
|
||||||
local function add_supported( t, defs )
|
|
||||||
local def_inst = defs['data']['instances']
|
|
||||||
|
|
||||||
if type(def_inst) == "table" then
|
|
||||||
for k, v in pairs( def_inst ) do
|
|
||||||
if lu.contains( ups_types, k) then
|
|
||||||
for j = #v, 1, -1 do
|
|
||||||
if not lu.contains( ups_inst[k], v[j] ) then
|
|
||||||
table.remove( v, j )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #v == 0 then
|
|
||||||
def_inst[k] = nil -- can't assign v: immutable
|
|
||||||
end
|
|
||||||
else
|
|
||||||
def_inst[k] = nil -- can't assign v: immutable
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if empty(def_inst) then return end
|
|
||||||
end
|
|
||||||
table.insert( t, defs )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Graph definitions for APC UPS measurements MUST use only 'instances':
|
|
||||||
-- e.g. instances = { voltage = { "input", "output" } }
|
|
||||||
|
|
||||||
local voltagesdc = {
|
|
||||||
title = "%H: Voltages on APC UPS - Battery",
|
|
||||||
vlabel = "Volts DC",
|
|
||||||
alt_autoscale = true,
|
|
||||||
number_format = "%5.1lfV",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
voltage = { "battery" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
voltage = { title = "Battery voltage", noarea=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, voltagesdc )
|
|
||||||
|
|
||||||
local voltagesac = {
|
|
||||||
title = "%H: Voltages on APC UPS - AC",
|
|
||||||
vlabel = "Volts AC",
|
|
||||||
alt_autoscale = true,
|
|
||||||
number_format = "%5.1lfV",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
voltage = { "input", "output" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true },
|
|
||||||
voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, voltagesac )
|
|
||||||
|
|
||||||
local percentload = {
|
|
||||||
title = "%H: Load on APC UPS ",
|
|
||||||
vlabel = "Percent",
|
|
||||||
y_min = "0",
|
|
||||||
y_max = "100",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
percent = { "load" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
percent_load = { color = "00ff00", title = "Load level" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, percentload )
|
|
||||||
|
|
||||||
local charge_percent = {
|
|
||||||
title = "%H: Battery charge on APC UPS ",
|
|
||||||
vlabel = "Percent",
|
|
||||||
y_min = "0",
|
|
||||||
y_max = "100",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
charge = { "" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
charge = { color = "00ff0b", title = "Charge level" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, charge_percent )
|
|
||||||
|
|
||||||
local temperature = {
|
|
||||||
title = "%H: Battery temperature on APC UPS ",
|
|
||||||
vlabel = "\176C",
|
|
||||||
number_format = "%5.1lf\176C",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
temperature = { "" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
temperature = { color = "ffb000", title = "Battery temperature" } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, temperature )
|
|
||||||
|
|
||||||
local timeleft = {
|
|
||||||
title = "%H: Time left on APC UPS ",
|
|
||||||
vlabel = "Minutes",
|
|
||||||
number_format = "%.1lfm",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
timeleft = { "" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
timeleft = { color = "0000ff", title = "Time left" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, timeleft )
|
|
||||||
|
|
||||||
local frequency = {
|
|
||||||
title = "%H: Incoming line frequency on APC UPS ",
|
|
||||||
vlabel = "Hz",
|
|
||||||
number_format = "%5.0lfhz",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
frequency = { "input" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
frequency_input = { color = "000fff", title = "Line frequency" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add_supported( rv, frequency )
|
|
||||||
|
|
||||||
return rv
|
|
||||||
end
|
|
|
@ -1,32 +0,0 @@
|
||||||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.conntrack",package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Conntrack")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Conntrack entries",
|
|
||||||
vlabel = "Count",
|
|
||||||
number_format = "%5.0lf",
|
|
||||||
data = {
|
|
||||||
-- collectd 5.5+: specify "" to exclude "max" instance
|
|
||||||
instances = {
|
|
||||||
conntrack = { "" }
|
|
||||||
},
|
|
||||||
sources = {
|
|
||||||
conntrack = { "value" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
conntrack = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Tracked connections"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,27 +0,0 @@
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.contextswitch",package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Context Switches")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Context switches",
|
|
||||||
alt_autoscale = true,
|
|
||||||
vlabel = "Switches/s",
|
|
||||||
number_format = "%5.0lf",
|
|
||||||
data = {
|
|
||||||
types = { "contextswitch" },
|
|
||||||
sources = {
|
|
||||||
contextswitch = { "value" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
contextswitch = { color = "0000ff", title = "Context switches", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,169 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.cpu",package.seeall)
|
|
||||||
|
|
||||||
local uci = require("luci.model.uci").cursor()
|
|
||||||
local reportbystate = uci:get("luci_statistics", "collectd_cpu", "ReportByState") or "0"
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Processor")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
local p = {}
|
|
||||||
|
|
||||||
local title = "%H: Processor usage"
|
|
||||||
if #plugin_instance > 0 then
|
|
||||||
title = "%H: Processor usage on core #%pi"
|
|
||||||
end
|
|
||||||
|
|
||||||
if reportbystate == "1" then
|
|
||||||
local cpu = {
|
|
||||||
title = title,
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
vlabel = "Jiffies",
|
|
||||||
number_format = "%5.1lf",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
cpu = {
|
|
||||||
"idle",
|
|
||||||
"interrupt",
|
|
||||||
"nice",
|
|
||||||
"softirq",
|
|
||||||
"steal",
|
|
||||||
"system",
|
|
||||||
"user",
|
|
||||||
"wait"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
cpu_idle = {
|
|
||||||
color = "ffffff",
|
|
||||||
title = "Idle"
|
|
||||||
},
|
|
||||||
cpu_interrupt = {
|
|
||||||
color = "a000a0",
|
|
||||||
title = "Interrupt"
|
|
||||||
},
|
|
||||||
cpu_nice = {
|
|
||||||
color = "00e000",
|
|
||||||
title = "Nice"
|
|
||||||
},
|
|
||||||
cpu_softirq = {
|
|
||||||
color = "ff00ff",
|
|
||||||
title = "Softirq"
|
|
||||||
},
|
|
||||||
cpu_steal = {
|
|
||||||
color = "000000",
|
|
||||||
title = "Steal"
|
|
||||||
},
|
|
||||||
cpu_system = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "System"
|
|
||||||
},
|
|
||||||
cpu_user = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "User"
|
|
||||||
},
|
|
||||||
cpu_wait = {
|
|
||||||
color = "ffb000",
|
|
||||||
title = "Wait"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local percent = {
|
|
||||||
title = title,
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
vlabel = "Percent",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
percent = {
|
|
||||||
"idle",
|
|
||||||
"interrupt",
|
|
||||||
"nice",
|
|
||||||
"softirq",
|
|
||||||
"steal",
|
|
||||||
"system",
|
|
||||||
"user",
|
|
||||||
"wait"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
percent_idle = {
|
|
||||||
color = "ffffff",
|
|
||||||
title = "Idle"
|
|
||||||
},
|
|
||||||
percent_interrupt = {
|
|
||||||
color = "a000a0",
|
|
||||||
title = "Interrupt"
|
|
||||||
},
|
|
||||||
percent_nice = {
|
|
||||||
color = "00e000",
|
|
||||||
title = "Nice"
|
|
||||||
},
|
|
||||||
percent_softirq = {
|
|
||||||
color = "ff00ff",
|
|
||||||
title = "Softirq"
|
|
||||||
},
|
|
||||||
percent_steal = {
|
|
||||||
color = "000000",
|
|
||||||
title = "Steal"
|
|
||||||
},
|
|
||||||
percent_system = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "System"
|
|
||||||
},
|
|
||||||
percent_user = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "User"
|
|
||||||
},
|
|
||||||
percent_wait = {
|
|
||||||
color = "ffb000",
|
|
||||||
title = "Wait"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local types = graph.tree:data_types( plugin, plugin_instance )
|
|
||||||
|
|
||||||
for _, t in ipairs(types) do
|
|
||||||
if t == "cpu" then
|
|
||||||
p[#p+1] = cpu
|
|
||||||
end
|
|
||||||
|
|
||||||
if t == "percent" then
|
|
||||||
p[#p+1] = percent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
p = {
|
|
||||||
title = title,
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
vlabel = "Percent",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
percent = {
|
|
||||||
"active",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
percent_active = {
|
|
||||||
color = "00e000",
|
|
||||||
title = "Active"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return p
|
|
||||||
end
|
|
|
@ -1,61 +0,0 @@
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.cpufreq",package.seeall)
|
|
||||||
|
|
||||||
local uci = require("luci.model.uci").cursor()
|
|
||||||
local extraitems = uci:get("luci_statistics", "collectd_cpufreq", "ExtraItems") or nil
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("CPU Frequency")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
local cpufreq = {
|
|
||||||
title = "%H: Processor frequency - core %pi",
|
|
||||||
alt_autoscale = true,
|
|
||||||
vlabel = "Frequency (Hz)",
|
|
||||||
number_format = "%3.2lf%s",
|
|
||||||
data = {
|
|
||||||
types = {"cpufreq" },
|
|
||||||
options = {
|
|
||||||
cpufreq = { color = "ff0000", title = "Frequency" },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if extraitems then
|
|
||||||
|
|
||||||
local transitions = {
|
|
||||||
title = "%H: Frequency transitions - core %pi",
|
|
||||||
alt_autoscale = true,
|
|
||||||
vlabel = "Transitions",
|
|
||||||
number_format = "%3.2lf%s",
|
|
||||||
data = {
|
|
||||||
types = { "transitions" },
|
|
||||||
options = {
|
|
||||||
transitions = { color = "0000ff", title = "Transitions", noarea=true },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local percentage = {
|
|
||||||
title = "%H: Frequency distribution - core %pi",
|
|
||||||
alt_autoscale = true,
|
|
||||||
vlabel = "Percent",
|
|
||||||
number_format = "%5.2lf%%",
|
|
||||||
ordercolor = true,
|
|
||||||
data = {
|
|
||||||
types = { "percent" },
|
|
||||||
options = {
|
|
||||||
percent = { title = "%di kHz", negweight = true },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { cpufreq, percentage, transitions }
|
|
||||||
else
|
|
||||||
return { cpufreq }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
-- Copyright 2018 Chizhong Jin <pjincz@gmail.com>
|
|
||||||
-- Licensed to the public under the BSD 3-clause license
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.curl", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("cUrl")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: cUrl Response Time for #%pi",
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
vlabel = "Response Time",
|
|
||||||
number_format = "%5.1lf%Ss",
|
|
||||||
data = {
|
|
||||||
types = { "response_time" },
|
|
||||||
options = {
|
|
||||||
response_time = {
|
|
||||||
title = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,90 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.df", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Disk Space Usage")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
local df_complex = {
|
|
||||||
title = "%H: Disk space usage on %pi",
|
|
||||||
vlabel = "Bytes",
|
|
||||||
number_format = "%5.1lf%sB",
|
|
||||||
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
df_complex = { "free", "used", "reserved" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
df_complex_free = {
|
|
||||||
color = "00ff00",
|
|
||||||
overlay = false,
|
|
||||||
title = "free"
|
|
||||||
},
|
|
||||||
|
|
||||||
df_complex_used = {
|
|
||||||
color = "ff0000",
|
|
||||||
overlay = false,
|
|
||||||
title = "used"
|
|
||||||
},
|
|
||||||
|
|
||||||
df_complex_reserved = {
|
|
||||||
color = "0000ff",
|
|
||||||
overlay = false,
|
|
||||||
title = "reserved"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local percent_bytes = {
|
|
||||||
title = "%H: Disk space usage on %pi",
|
|
||||||
vlabel = "Percent",
|
|
||||||
number_format = "%5.2lf %%",
|
|
||||||
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
percent_bytes = { "free", "used", "reserved" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
percent_bytes_free = {
|
|
||||||
color = "00ff00",
|
|
||||||
overlay = false,
|
|
||||||
title = "free"
|
|
||||||
},
|
|
||||||
|
|
||||||
percent_bytes_used = {
|
|
||||||
color = "ff0000",
|
|
||||||
overlay = false,
|
|
||||||
title = "used"
|
|
||||||
},
|
|
||||||
|
|
||||||
percent_bytes_reserved = {
|
|
||||||
color = "0000ff",
|
|
||||||
overlay = false,
|
|
||||||
title = "reserved"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local types = graph.tree:data_types( plugin, plugin_instance )
|
|
||||||
|
|
||||||
local p = {}
|
|
||||||
for _, t in ipairs(types) do
|
|
||||||
if t == "percent_bytes" then
|
|
||||||
p[#p+1] = percent_bytes
|
|
||||||
end
|
|
||||||
|
|
||||||
if t == "df_complex" then
|
|
||||||
p[#p+1] = df_complex
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return p
|
|
||||||
end
|
|
|
@ -1,67 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.disk", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Disk Usage")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
title = "%H: Disk I/O operations on %pi",
|
|
||||||
vlabel = "Operations/s",
|
|
||||||
number_format = "%5.1lf%sOp/s",
|
|
||||||
|
|
||||||
data = {
|
|
||||||
types = { "disk_ops" },
|
|
||||||
sources = {
|
|
||||||
disk_ops = { "read", "write" },
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
disk_ops__read = {
|
|
||||||
title = "Reads",
|
|
||||||
color = "00ff00",
|
|
||||||
flip = false
|
|
||||||
},
|
|
||||||
|
|
||||||
disk_ops__write = {
|
|
||||||
title = "Writes",
|
|
||||||
color = "ff0000",
|
|
||||||
flip = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%H: Disk I/O bandwidth on %pi",
|
|
||||||
vlabel = "Bytes/s",
|
|
||||||
number_format = "%5.1lf%sB/s",
|
|
||||||
|
|
||||||
detail = true,
|
|
||||||
|
|
||||||
data = {
|
|
||||||
types = { "disk_octets" },
|
|
||||||
sources = {
|
|
||||||
disk_octets = { "read", "write" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
disk_octets__read = {
|
|
||||||
title = "Read",
|
|
||||||
color = "00ff00",
|
|
||||||
flip = false
|
|
||||||
},
|
|
||||||
disk_octets__write = {
|
|
||||||
title = "Write",
|
|
||||||
color = "ff0000",
|
|
||||||
flip = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,75 +0,0 @@
|
||||||
-- Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.dns", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("DNS")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
|
|
||||||
local traffic = {
|
|
||||||
title = "%H: DNS traffic", vlabel = "Bit/s",
|
|
||||||
|
|
||||||
data = {
|
|
||||||
sources = {
|
|
||||||
dns_octets = { "queries", "responses" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
dns_octets__responses = {
|
|
||||||
total = true,
|
|
||||||
color = "00ff00",
|
|
||||||
title = "Responses"
|
|
||||||
},
|
|
||||||
|
|
||||||
dns_octets__queries = {
|
|
||||||
total = true,
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Queries"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local opcode_query = {
|
|
||||||
title = "%H: DNS Opcode Query", vlabel = "Queries/s",
|
|
||||||
data = {
|
|
||||||
instances = { dns_opcode = { "Query" } },
|
|
||||||
options = {
|
|
||||||
dns_opcode_Query_value = {
|
|
||||||
total = true,
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Queries/s"
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local qtype = {
|
|
||||||
title = "%H: DNS QType", vlabel = "Queries/s",
|
|
||||||
data = {
|
|
||||||
sources = { dns_qtype = { "" } },
|
|
||||||
options = {
|
|
||||||
dns_qtype_AAAA_ = { title = "AAAA", noarea = true, total = true },
|
|
||||||
dns_qtype_A_ = { title = "A", noarea = true, total = true },
|
|
||||||
dns_qtype_A6_ = { title = "A6", noarea = true, total = true },
|
|
||||||
dns_qtype_TXT_ = { title = "TXT", noarea = true, total = true },
|
|
||||||
dns_qtype_MX_ = { title = "MX", noarea = true, total = true },
|
|
||||||
dns_qtype_NS_ = { title = "NS", noarea = true, total = true },
|
|
||||||
dns_qtype_ANY_ = { title = "ANY", noarea = true, total = true },
|
|
||||||
dns_qtype_CNAME_= { title = "CNAME", noarea = true, total = true },
|
|
||||||
dns_qtype_SOA_ = { title = "SOA", noarea = true, total = true },
|
|
||||||
dns_qtype_SRV_ = { title = "SRV", noarea = true, total = true },
|
|
||||||
dns_qtype_PTR_ = { title = "PTR", noarea = true, total = true },
|
|
||||||
dns_qtype_RP_ = { title = "RP", noarea = true, total = true },
|
|
||||||
dns_qtype_MAILB_= { title = "MAILB", noarea = true, total = true },
|
|
||||||
dns_qtype_IXFR_ = { title = "IXFR", noarea = true, total = true },
|
|
||||||
dns_qtype_HINFO_= { title = "HINFO", noarea = true, total = true },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { traffic, opcode_query, qtype }
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
-- Copyright 2015 Hannu Nyman <hannu.nyman@iki.fi>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.entropy", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Entropy")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Available entropy",
|
|
||||||
vlabel = "bits",
|
|
||||||
number_format = "%4.0lf",
|
|
||||||
data = {
|
|
||||||
types = { "entropy" },
|
|
||||||
options = { entropy = { title = "Entropy %di" } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.interface", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Interfaces")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
|
|
||||||
--
|
|
||||||
-- traffic diagram
|
|
||||||
--
|
|
||||||
local traffic = {
|
|
||||||
|
|
||||||
-- draw this diagram for each plugin instance
|
|
||||||
per_instance = true,
|
|
||||||
title = "%H: Transfer on %pi",
|
|
||||||
vlabel = "Bytes/s",
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- defined sources for data types, if omitted assume a single DS named "value" (optional)
|
|
||||||
sources = {
|
|
||||||
if_octets = { "tx", "rx" }
|
|
||||||
},
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
if_octets__tx = {
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "00ff00", -- tx is green
|
|
||||||
title = "Bytes (TX)"
|
|
||||||
},
|
|
||||||
|
|
||||||
if_octets__rx = {
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "0000ff", -- rx is blue
|
|
||||||
title = "Bytes (RX)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- packet diagram
|
|
||||||
--
|
|
||||||
local packets = {
|
|
||||||
|
|
||||||
-- draw this diagram for each plugin instance
|
|
||||||
per_instance = true,
|
|
||||||
title = "%H: Packets on %pi",
|
|
||||||
vlabel = "Packets/s",
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- data type order
|
|
||||||
types = { "if_packets", "if_errors" },
|
|
||||||
|
|
||||||
-- defined sources for data types
|
|
||||||
sources = {
|
|
||||||
if_packets = { "tx", "rx" },
|
|
||||||
if_errors = { "tx", "rx" }
|
|
||||||
},
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
-- processed packets (tx DS)
|
|
||||||
if_packets__tx = {
|
|
||||||
weight = 1,
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "00ff00", -- processed tx is green
|
|
||||||
title = "Processed (TX)"
|
|
||||||
},
|
|
||||||
|
|
||||||
-- processed packets (rx DS)
|
|
||||||
if_packets__rx = {
|
|
||||||
weight = 2,
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "0000ff", -- processed rx is blue
|
|
||||||
title = "Processed (RX)"
|
|
||||||
},
|
|
||||||
|
|
||||||
-- packet errors (tx DS)
|
|
||||||
if_errors__tx = {
|
|
||||||
weight = 0,
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
total = true, -- report total amount of packets
|
|
||||||
color = "ff5500", -- tx errors are orange
|
|
||||||
title = "Errors (TX)"
|
|
||||||
},
|
|
||||||
|
|
||||||
-- packet errors (rx DS)
|
|
||||||
if_errors__rx = {
|
|
||||||
weight = 3,
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of packets
|
|
||||||
color = "ff0000", -- rx errors are red
|
|
||||||
title = "Errors (RX)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { traffic, packets }
|
|
||||||
end
|
|
|
@ -1,45 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.iptables", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Firewall")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
title = "%H: Firewall: Processed bytes in %pi",
|
|
||||||
vlabel = "Bytes/s",
|
|
||||||
number_format = "%5.1lf%sB/s",
|
|
||||||
totals_format = "%5.1lf%sB",
|
|
||||||
data = {
|
|
||||||
types = { "ipt_bytes" },
|
|
||||||
options = {
|
|
||||||
ipt_bytes = {
|
|
||||||
total = true,
|
|
||||||
title = "%di"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%H: Firewall: Processed packets in %pi",
|
|
||||||
vlabel = "Packets/s",
|
|
||||||
number_format = "%5.1lf P/s",
|
|
||||||
totals_format = "%5.1lf%s",
|
|
||||||
data = {
|
|
||||||
types = { "ipt_packets" },
|
|
||||||
options = {
|
|
||||||
ipt_packets = {
|
|
||||||
total = true,
|
|
||||||
title = "%di"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.irq", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Interrupts")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Interrupts", vlabel = "Issues/s",
|
|
||||||
number_format = "%5.0lf", data = {
|
|
||||||
types = { "irq" },
|
|
||||||
options = {
|
|
||||||
irq = { title = "IRQ %di", noarea = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,96 +0,0 @@
|
||||||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.iwinfo", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Wireless")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
|
|
||||||
--
|
|
||||||
-- signal/noise diagram
|
|
||||||
--
|
|
||||||
local snr = {
|
|
||||||
title = "%H: Signal and noise on %pi",
|
|
||||||
vlabel = "dBm",
|
|
||||||
number_format = "%5.1lf dBm",
|
|
||||||
data = {
|
|
||||||
types = { "signal_noise", "signal_power" },
|
|
||||||
options = {
|
|
||||||
signal_power = {
|
|
||||||
title = "Signal",
|
|
||||||
overlay = true,
|
|
||||||
color = "0000ff"
|
|
||||||
},
|
|
||||||
signal_noise = {
|
|
||||||
title = "Noise",
|
|
||||||
overlay = true,
|
|
||||||
color = "ff0000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- signal quality diagram
|
|
||||||
--
|
|
||||||
local quality = {
|
|
||||||
title = "%H: Signal quality on %pi",
|
|
||||||
vlabel = "Quality",
|
|
||||||
number_format = "%3.0lf",
|
|
||||||
data = {
|
|
||||||
types = { "signal_quality" },
|
|
||||||
options = {
|
|
||||||
signal_quality = {
|
|
||||||
title = "Quality",
|
|
||||||
noarea = true,
|
|
||||||
color = "0000ff"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- phy rate diagram
|
|
||||||
--
|
|
||||||
local bitrate = {
|
|
||||||
title = "%H: Average phy rate on %pi",
|
|
||||||
vlabel = "MBit/s",
|
|
||||||
number_format = "%5.1lf%sBit/s",
|
|
||||||
data = {
|
|
||||||
types = { "bitrate" },
|
|
||||||
options = {
|
|
||||||
bitrate = {
|
|
||||||
title = "Rate",
|
|
||||||
color = "00ff00"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
-- associated stations
|
|
||||||
--
|
|
||||||
local stations = {
|
|
||||||
title = "%H: Associated stations on %pi",
|
|
||||||
vlabel = "Stations",
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
number_format = "%3.0lf",
|
|
||||||
data = {
|
|
||||||
types = { "stations" },
|
|
||||||
options = {
|
|
||||||
stations = {
|
|
||||||
title = "Stations",
|
|
||||||
color = "0000ff"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { snr, quality, bitrate, stations }
|
|
||||||
end
|
|
|
@ -1,43 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.load", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("System Load")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Load", vlabel = "Load",
|
|
||||||
y_min = "0",
|
|
||||||
units_exponent = "0",
|
|
||||||
number_format = "%5.2lf", data = {
|
|
||||||
sources = {
|
|
||||||
load = { "shortterm", "midterm", "longterm" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
load__shortterm = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "1 minute",
|
|
||||||
noarea = true,
|
|
||||||
weight = 3
|
|
||||||
},
|
|
||||||
load__midterm = {
|
|
||||||
color = "ff6600",
|
|
||||||
title = "5 minutes",
|
|
||||||
overlay = true,
|
|
||||||
weight = 1
|
|
||||||
},
|
|
||||||
load__longterm = {
|
|
||||||
color = "ffaa00",
|
|
||||||
title = "15 minutes",
|
|
||||||
overlay = true,
|
|
||||||
weight = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,99 +0,0 @@
|
||||||
-- Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.memory",package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Memory")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
local p = {}
|
|
||||||
|
|
||||||
local memory = {
|
|
||||||
title = "%H: Memory usage",
|
|
||||||
vlabel = "MB",
|
|
||||||
number_format = "%5.1lf%s",
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
memory = {
|
|
||||||
"free",
|
|
||||||
"buffered",
|
|
||||||
"cached",
|
|
||||||
"used"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
memory_buffered = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Buffered"
|
|
||||||
},
|
|
||||||
memory_cached = {
|
|
||||||
color = "ff00ff",
|
|
||||||
title = "Cached"
|
|
||||||
},
|
|
||||||
memory_used = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "Used"
|
|
||||||
},
|
|
||||||
memory_free = {
|
|
||||||
color = "00ff00",
|
|
||||||
title = "Free"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local percent = {
|
|
||||||
title = "%H: Memory usage",
|
|
||||||
vlabel = "Percent",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
y_min = "0",
|
|
||||||
alt_autoscale_max = true,
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
percent = {
|
|
||||||
"free",
|
|
||||||
"buffered",
|
|
||||||
"cached",
|
|
||||||
"used"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
percent_buffered = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Buffered"
|
|
||||||
},
|
|
||||||
percent_cached = {
|
|
||||||
color = "ff00ff",
|
|
||||||
title = "Cached"
|
|
||||||
},
|
|
||||||
percent_used = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "Used"
|
|
||||||
},
|
|
||||||
percent_free = {
|
|
||||||
color = "00ff00",
|
|
||||||
title = "Free"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local types = graph.tree:data_types( plugin, plugin_instance )
|
|
||||||
|
|
||||||
for _, t in ipairs(types) do
|
|
||||||
if t == "percent" then
|
|
||||||
p[#p+1] = percent
|
|
||||||
end
|
|
||||||
|
|
||||||
if t == "memory" then
|
|
||||||
p[#p+1] = memory
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return p
|
|
||||||
end
|
|
|
@ -1,210 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.netlink", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Netlink")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
|
|
||||||
--
|
|
||||||
-- traffic diagram
|
|
||||||
--
|
|
||||||
local traffic = {
|
|
||||||
title = "%H: Netlink - Transfer on %pi",
|
|
||||||
vlabel = "Bytes/s",
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- defined sources for data types, if omitted assume a single DS named "value" (optional)
|
|
||||||
sources = {
|
|
||||||
if_octets = { "tx", "rx" }
|
|
||||||
},
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
if_octets__tx = {
|
|
||||||
title = "Bytes (TX)",
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "00ff00" -- tx is green
|
|
||||||
},
|
|
||||||
|
|
||||||
if_octets__rx = {
|
|
||||||
title = "Bytes (RX)",
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "0000ff" -- rx is blue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
-- packet diagram
|
|
||||||
--
|
|
||||||
local packets = {
|
|
||||||
title = "%H: Netlink - Packets on %pi",
|
|
||||||
vlabel = "Packets/s", detail = true,
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- data type order
|
|
||||||
types = { "if_packets", "if_dropped", "if_errors" },
|
|
||||||
|
|
||||||
-- defined sources for data types
|
|
||||||
sources = {
|
|
||||||
if_packets = { "tx", "rx" },
|
|
||||||
if_dropped = { "tx", "rx" },
|
|
||||||
if_errors = { "tx", "rx" }
|
|
||||||
},
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
-- processed packets (tx DS)
|
|
||||||
if_packets__tx = {
|
|
||||||
weight = 2,
|
|
||||||
title = "Total (TX)",
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "00ff00" -- processed tx is green
|
|
||||||
},
|
|
||||||
|
|
||||||
-- processed packets (rx DS)
|
|
||||||
if_packets__rx = {
|
|
||||||
weight = 3,
|
|
||||||
title = "Total (RX)",
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "0000ff" -- processed rx is blue
|
|
||||||
},
|
|
||||||
|
|
||||||
-- dropped packets (tx DS)
|
|
||||||
if_dropped__tx = {
|
|
||||||
weight = 1,
|
|
||||||
title = "Dropped (TX)",
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "660055" -- dropped tx is ... dunno ;)
|
|
||||||
},
|
|
||||||
|
|
||||||
-- dropped packets (rx DS)
|
|
||||||
if_dropped__rx = {
|
|
||||||
weight = 4,
|
|
||||||
title = "Dropped (RX)",
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of bytes
|
|
||||||
color = "ff00ff" -- dropped rx is violett
|
|
||||||
},
|
|
||||||
|
|
||||||
-- packet errors (tx DS)
|
|
||||||
if_errors__tx = {
|
|
||||||
weight = 0,
|
|
||||||
title = "Errors (TX)",
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
total = true, -- report total amount of packets
|
|
||||||
color = "ff5500" -- tx errors are orange
|
|
||||||
},
|
|
||||||
|
|
||||||
-- packet errors (rx DS)
|
|
||||||
if_errors__rx = {
|
|
||||||
weight = 5,
|
|
||||||
title = "Errors (RX)",
|
|
||||||
overlay = true, -- don't summarize
|
|
||||||
flip = true, -- flip rx line
|
|
||||||
total = true, -- report total amount of packets
|
|
||||||
color = "ff0000" -- rx errors are red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
-- multicast diagram
|
|
||||||
--
|
|
||||||
local multicast = {
|
|
||||||
title = "%H: Netlink - Multicast on %pi",
|
|
||||||
vlabel = "Packets/s", detail = true,
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- data type order
|
|
||||||
types = { "if_multicast" },
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
-- multicast packets
|
|
||||||
if_multicast = {
|
|
||||||
title = "Packets",
|
|
||||||
total = true, -- report total amount of packets
|
|
||||||
color = "0000ff" -- multicast is blue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
-- collision diagram
|
|
||||||
--
|
|
||||||
local collisions = {
|
|
||||||
title = "%H: Netlink - Collisions on %pi",
|
|
||||||
vlabel = "Collisions/s", detail = true,
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- data type order
|
|
||||||
types = { "if_collisions" },
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
-- collision rate
|
|
||||||
if_collisions = {
|
|
||||||
title = "Collisions",
|
|
||||||
total = true, -- report total amount of packets
|
|
||||||
color = "ff0000" -- collsions are red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
-- error diagram
|
|
||||||
--
|
|
||||||
local errors = {
|
|
||||||
title = "%H: Netlink - Errors on %pi",
|
|
||||||
vlabel = "Errors/s", detail = true,
|
|
||||||
|
|
||||||
-- diagram data description
|
|
||||||
data = {
|
|
||||||
-- data type order
|
|
||||||
types = { "if_tx_errors", "if_rx_errors" },
|
|
||||||
|
|
||||||
-- data type instances
|
|
||||||
instances = {
|
|
||||||
if_tx_errors = { "aborted", "carrier", "fifo", "heartbeat", "window" },
|
|
||||||
if_rx_errors = { "length", "missed", "over", "crc", "fifo", "frame" }
|
|
||||||
},
|
|
||||||
|
|
||||||
-- special options for single data lines
|
|
||||||
options = {
|
|
||||||
if_tx_errors_aborted_value = { total = true, color = "ffff00", title = "Aborted (TX)" },
|
|
||||||
if_tx_errors_carrier_value = { total = true, color = "ffcc00", title = "Carrier (TX)" },
|
|
||||||
if_tx_errors_fifo_value = { total = true, color = "ff9900", title = "Fifo (TX)" },
|
|
||||||
if_tx_errors_heartbeat_value = { total = true, color = "ff6600", title = "Heartbeat (TX)" },
|
|
||||||
if_tx_errors_window_value = { total = true, color = "ff3300", title = "Window (TX)" },
|
|
||||||
|
|
||||||
if_rx_errors_length_value = { flip = true, total = true, color = "ff0000", title = "Length (RX)" },
|
|
||||||
if_rx_errors_missed_value = { flip = true, total = true, color = "ff0033", title = "Missed (RX)" },
|
|
||||||
if_rx_errors_over_value = { flip = true, total = true, color = "ff0066", title = "Over (RX)" },
|
|
||||||
if_rx_errors_crc_value = { flip = true, total = true, color = "ff0099", title = "CRC (RX)" },
|
|
||||||
if_rx_errors_fifo_value = { flip = true, total = true, color = "ff00cc", title = "Fifo (RX)" },
|
|
||||||
if_rx_errors_frame_value = { flip = true, total = true, color = "ff00ff", title = "Frame (RX)" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { traffic, packets, multicast, collisions, errors }
|
|
||||||
end
|
|
|
@ -1,130 +0,0 @@
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.nut",package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("UPS")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
local voltages_ac = {
|
|
||||||
title = "%H: AC voltages on UPS \"%pi\"",
|
|
||||||
vlabel = "V",
|
|
||||||
number_format = "%5.1lfV",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
voltage = { "input", "output" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true },
|
|
||||||
voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local voltages_dc = {
|
|
||||||
title = "%H: Battery voltage on UPS \"%pi\"",
|
|
||||||
vlabel = "V",
|
|
||||||
number_format = "%5.1lfV",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
voltage = { "battery" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
voltage = { color = "0000ff", title = "Battery voltage", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local currents = {
|
|
||||||
title = "%H: Current on UPS \"%pi\"",
|
|
||||||
vlabel = "A",
|
|
||||||
number_format = "%5.3lfA",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
current = { "battery", "output" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
current_output = { color = "00e000", title = "Output current", noarea=true, overlay=true },
|
|
||||||
current_battery = { color = "0000ff", title = "Battery current", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local percentage = {
|
|
||||||
title = "%H: Battery charge/load on UPS \"%pi\"",
|
|
||||||
vlabel = "Percent",
|
|
||||||
y_min = "0",
|
|
||||||
y_max = "100",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
percent = { "charge", "load" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
percent_charge = { color = "00ff00", title = "Charge level", noarea=true, overlay=true },
|
|
||||||
percent_load = { color = "ff0000", title = "Load", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Note: This is in ISO8859-1 for rrdtool. Welcome to the 20th century.
|
|
||||||
local temperature = {
|
|
||||||
title = "%H: Battery temperature on UPS \"%pi\"",
|
|
||||||
vlabel = "\176C",
|
|
||||||
number_format = "%5.1lf\176C",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
temperature = "battery"
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
temperature_battery = { color = "ffb000", title = "Battery temperature", noarea=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local timeleft = {
|
|
||||||
title = "%H: Time left on UPS \"%pi\"",
|
|
||||||
vlabel = "Minutes",
|
|
||||||
number_format = "%.1lfm",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
timeleft = { "battery" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
timeleft_battery = { color = "0000ff", title = "Time left", transform_rpn = "60,/", noarea=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local power = {
|
|
||||||
title = "%H: Power on UPS \"%pi\"",
|
|
||||||
vlabel = "Power",
|
|
||||||
number_format = "%5.1lf%%",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
power = { "ups" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
power_ups = { color = "00ff00", title = "Power level" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local frequencies = {
|
|
||||||
title = "%H: Frequencies on UPS \"%pi\"",
|
|
||||||
vlabel = "Hz",
|
|
||||||
number_format = "%5.1lfHz",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
frequency = { "input", "output" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
frequency_output = { color = "00e000", title = "Output frequency", noarea=true, overlay=true },
|
|
||||||
frequency_input = { color = "ffb000", title = "Input frequency", noarea=true, overlay=true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { voltages_ac, voltages_dc, currents, percentage, temperature, timeleft, power, frequencies }
|
|
||||||
end
|
|
|
@ -1,140 +0,0 @@
|
||||||
-- Copyright 2011 Manuel Munz <freifunk at somakoma dot de>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.olsrd", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("OLSRd")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
local g = { }
|
|
||||||
|
|
||||||
if plugin_instance == "routes" then
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
-- diagram data description
|
|
||||||
title = "%H: Total amount of OLSR routes", vlabel = "n",
|
|
||||||
number_format = "%5.0lf", data = {
|
|
||||||
types = { "routes" },
|
|
||||||
options = {
|
|
||||||
routes = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "Total number of routes"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
title = "%H: Average route ETX", vlabel = "ETX", detail = true,
|
|
||||||
number_format = "%5.1lf",data = {
|
|
||||||
instances = { "average" }, -- falls es irgendwann mal welche pro ip gibt, wie bei links, dann werden die hier excludiert
|
|
||||||
types = { "route_etx" },
|
|
||||||
options = {
|
|
||||||
route_etx = {
|
|
||||||
title = "Average route ETX"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
title = "%H: Average route metric", vlabel = "metric", detail = true,
|
|
||||||
number_format = "%5.1lf", data = {
|
|
||||||
instances = { "average" }, -- falls es irgendwann mal welche pro ip gibt, wie bei links, dann werden die hier excludiert
|
|
||||||
types = { "route_metric" },
|
|
||||||
options = {
|
|
||||||
route_metric = {
|
|
||||||
title = "Average route metric"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
elseif plugin_instance == "links" then
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
-- diagram data description
|
|
||||||
title = "%H: Total amount of OLSR neighbours", vlabel = "n",
|
|
||||||
number_format = "%5.0lf", data = {
|
|
||||||
instances = { "" },
|
|
||||||
types = { "links" },
|
|
||||||
options = {
|
|
||||||
links = {
|
|
||||||
color = "00ff00",
|
|
||||||
title = "Number of neighbours"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local instances = graph.tree:data_instances(plugin, plugin_instance, "signal_quality")
|
|
||||||
table.sort(instances)
|
|
||||||
|
|
||||||
-- define one diagram per host, containing the rx and lq values
|
|
||||||
local i
|
|
||||||
for i = 1, #instances, 2 do
|
|
||||||
local dsn1 = "signal_quality_%s_value" % instances[i]:gsub("[^%w]+", "_")
|
|
||||||
local dsn2 = "signal_quality_%s_value" % instances[i+1]:gsub("[^%w]+", "_")
|
|
||||||
local host = instances[i]:match("^[^%-]+%-([^%-]+)%-.+")
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
title = "%H: Signal Quality" .. " (" .. (host or "avg") ..")", vlabel = "ETX",
|
|
||||||
number_format = "%5.2lf", detail = true,
|
|
||||||
data = {
|
|
||||||
types = { "signal_quality" },
|
|
||||||
|
|
||||||
instances = {
|
|
||||||
signal_quality = { instances[i], instances[i+1] },
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
[dsn1] = {
|
|
||||||
color = "00ff00",
|
|
||||||
title = "LQ (%s)" % (host or "avg"),
|
|
||||||
},
|
|
||||||
[dsn2] = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "NLQ (%s)" % (host or "avg"),
|
|
||||||
flip = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif plugin_instance == "topology" then
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
title= "%H: Total amount of OLSR links", vlabel = "n",
|
|
||||||
number_format = "%5.0lf", data = {
|
|
||||||
instances = { "" },
|
|
||||||
types = { "links" },
|
|
||||||
options = {
|
|
||||||
links = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Total number of links"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g[#g+1] = {
|
|
||||||
title= "%H: Average signal quality", vlabel = "n",
|
|
||||||
number_format = "%5.2lf", detail = true,
|
|
||||||
data = {
|
|
||||||
instances = { "average" }, -- exclude possible per-ip stuff
|
|
||||||
types = { "signal_quality" },
|
|
||||||
options = {
|
|
||||||
signal_quality = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "Average signal quality"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return g
|
|
||||||
end
|
|
|
@ -1,52 +0,0 @@
|
||||||
-- Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.openvpn", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("OpenVPN")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
local inst = plugin_instance:gsub("^openvpn%.(.+)%.status$", "%1")
|
|
||||||
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
title = "%%H: OpenVPN \"%s\" - Traffic" % inst,
|
|
||||||
vlabel = "Bytes/s",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
if_octets = { "traffic", "overhead" }
|
|
||||||
},
|
|
||||||
sources = {
|
|
||||||
if_octets = { "tx", "rx" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
if_octets_traffic_tx = { weight = 0, title = "Bytes (TX)", total = true, color = "00ff00" },
|
|
||||||
if_octets_overhead_tx = { weight = 1, title = "Overhead (TX)", total = true, color = "ff9900" },
|
|
||||||
if_octets_overhead_rx = { weight = 2, title = "Overhead (RX)", total = true, flip = true, color = "ff00ff" },
|
|
||||||
if_octets_traffic_rx = { weight = 3, title = "Bytes (RX)", total = true, flip = true, color = "0000ff" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%%H: OpenVPN \"%s\" - Compression" % inst,
|
|
||||||
vlabel = "Bytes/s",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
compression = { "data_out", "data_in" }
|
|
||||||
},
|
|
||||||
sources = {
|
|
||||||
compression = { "uncompressed", "compressed" }
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
compression_data_out_uncompressed = { weight = 0, title = "Uncompressed (TX)", total = true, color = "00ff00" },
|
|
||||||
compression_data_out_compressed = { weight = 1, title = "Compressed (TX)", total = true, color = "008800" },
|
|
||||||
compression_data_in_compressed = { weight = 2, title = "Compressed (RX)", total = true, flip = true, color = "000088" },
|
|
||||||
compression_data_in_uncompressed = { weight = 3, title = "Uncompressed (RX)", total = true, flip = true, color = "0000ff" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,70 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.ping", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Ping")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
local ping = {
|
|
||||||
title = "%H: ICMP Round Trip Time",
|
|
||||||
vlabel = "ms",
|
|
||||||
number_format = "%5.1lf ms",
|
|
||||||
data = {
|
|
||||||
sources = {
|
|
||||||
ping = {
|
|
||||||
"value"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
ping__value = {
|
|
||||||
noarea = true,
|
|
||||||
overlay = true,
|
|
||||||
title = "%di"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local droprate = {
|
|
||||||
title = "%H: ICMP Drop Rate",
|
|
||||||
vlabel = "%",
|
|
||||||
number_format = "%5.2lf %%",
|
|
||||||
data = {
|
|
||||||
types = {
|
|
||||||
"ping_droprate"
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
ping_droprate = {
|
|
||||||
noarea = true,
|
|
||||||
overlay = true,
|
|
||||||
title = "%di",
|
|
||||||
transform_rpn = "100,*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local stddev = {
|
|
||||||
title = "%H: ICMP Standard Deviation",
|
|
||||||
vlabel = "ms",
|
|
||||||
number_format = "%5.1lf ms",
|
|
||||||
data = {
|
|
||||||
types = {
|
|
||||||
"ping_stddev"
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
ping_stddev = {
|
|
||||||
noarea = true,
|
|
||||||
overlay = true,
|
|
||||||
title = "%di"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ping, droprate, stddev }
|
|
||||||
end
|
|
|
@ -1,121 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.processes", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Processes")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
if plugin_instance == "" then
|
|
||||||
return {
|
|
||||||
title = "%H: Processes",
|
|
||||||
vlabel = "Processes/s",
|
|
||||||
data = {
|
|
||||||
instances = {
|
|
||||||
ps_state = {
|
|
||||||
"sleeping", "running", "paging",
|
|
||||||
"blocked", "stopped", "zombies"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
ps_state_sleeping = { color = "0000ff", title = "Sleeping" },
|
|
||||||
ps_state_running = { color = "008000", title = "Running" },
|
|
||||||
ps_state_paging = { color = "ffff00", title = "Paging" },
|
|
||||||
ps_state_blocked = { color = "ff5000", title = "Blocked" },
|
|
||||||
ps_state_stopped = { color = "555555", title = "Stopped" },
|
|
||||||
ps_state_zombies = { color = "ff0000", title = "Zombies" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
title = "%H: CPU time used by %pi",
|
|
||||||
vlabel = "Jiffies",
|
|
||||||
data = {
|
|
||||||
sources = {
|
|
||||||
ps_cputime = { "syst", "user" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
ps_cputime__user = {
|
|
||||||
color = "0000ff",
|
|
||||||
title = "User",
|
|
||||||
overlay = true
|
|
||||||
},
|
|
||||||
|
|
||||||
ps_cputime__syst = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "System",
|
|
||||||
overlay = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%H: Threads and processes belonging to %pi",
|
|
||||||
vlabel = "Count",
|
|
||||||
detail = true,
|
|
||||||
data = {
|
|
||||||
sources = {
|
|
||||||
ps_count = { "threads", "processes" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
ps_count__threads = { color = "00ff00", title = "Threads" },
|
|
||||||
ps_count__processes = { color = "0000bb", title = "Processes" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%H: Page faults in %pi",
|
|
||||||
vlabel = "Page faults",
|
|
||||||
detail = true,
|
|
||||||
data = {
|
|
||||||
sources = {
|
|
||||||
ps_pagefaults = { "minflt", "majflt" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
ps_pagefaults__minflt = { color = "0000ff", title = "Minor" },
|
|
||||||
ps_pagefaults__majflt = { color = "ff0000", title = "Major" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%H: Resident segment size (RSS) of %pi",
|
|
||||||
vlabel = "Bytes",
|
|
||||||
detail = true,
|
|
||||||
number_format = "%5.1lf%sB",
|
|
||||||
data = {
|
|
||||||
types = { "ps_rss" },
|
|
||||||
|
|
||||||
options = {
|
|
||||||
ps_rss = { color = "0000ff", title = "Resident segment" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title = "%H: Virtual memory size (VSZ) of %pi",
|
|
||||||
vlabel = "Bytes",
|
|
||||||
detail = true,
|
|
||||||
number_format = "%5.1lf%sB",
|
|
||||||
data = {
|
|
||||||
types = { "ps_vm" },
|
|
||||||
|
|
||||||
options = {
|
|
||||||
ps_vm = { color = "0000ff", title = "Virtual memory" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,29 +0,0 @@
|
||||||
-- Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.sensors", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Sensors")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance )
|
|
||||||
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
per_instance = true,
|
|
||||||
title = "%H: %pi - %di",
|
|
||||||
vlabel = "\176C",
|
|
||||||
number_format = "%4.1lf\176C",
|
|
||||||
data = {
|
|
||||||
types = { "temperature" },
|
|
||||||
options = {
|
|
||||||
temperature__value = {
|
|
||||||
color = "ff0000",
|
|
||||||
title = "Temperature"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,30 +0,0 @@
|
||||||
-- Copyright 2013 Freifunk Augsburg / Michael Wendland <michael@michiwend.com>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.splash_leases", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Splash Leases")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Splash Leases",
|
|
||||||
vlabel = "Active Clients",
|
|
||||||
y_min = "0",
|
|
||||||
number_format = "%5.1lf",
|
|
||||||
data = {
|
|
||||||
sources = {
|
|
||||||
splash_leases = { "leased", "whitelisted", "blacklisted" }
|
|
||||||
},
|
|
||||||
|
|
||||||
options = {
|
|
||||||
splash_leases__leased = { color = "00CC00", title = "Leased", overlay = false },
|
|
||||||
splash_leases__whitelisted = { color = "0000FF", title = "Whitelisted", overlay = false },
|
|
||||||
splash_leases__blacklisted = { color = "FF0000", title = "Blacklisted", overlay = false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,30 +0,0 @@
|
||||||
-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.tcpconns", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("TCP Connections")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: TCP connections to port %pi",
|
|
||||||
vlabel = "Connections/s",
|
|
||||||
number_format = "%5.0lf",
|
|
||||||
data = {
|
|
||||||
types = { "tcp_connections" },
|
|
||||||
instances = {
|
|
||||||
tcp_connections = {
|
|
||||||
"SYN_SENT", "SYN_RECV", "LISTEN", "ESTABLISHED",
|
|
||||||
"LAST_ACK", "TIME_WAIT", "CLOSING", "CLOSE_WAIT",
|
|
||||||
"CLOSED", "FIN_WAIT1", "FIN_WAIT2"
|
|
||||||
},
|
|
||||||
options = {
|
|
||||||
load__ESTABLISHED = { title = "%di", noarea = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
|
@ -1,24 +0,0 @@
|
||||||
-- Licensed to the public under the Apache License 2.0.
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.thermal",package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Thermal")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Temperature of %pi",
|
|
||||||
alt_autoscale = true,
|
|
||||||
vlabel = "Celsius",
|
|
||||||
number_format = "%3.1lf%s",
|
|
||||||
data = {
|
|
||||||
types = { "temperature" },
|
|
||||||
options = {
|
|
||||||
temperature = { color = "ff0000", title = "Temperature", noarea=true },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
--[[
|
|
||||||
|
|
||||||
Copyright 2013 Thomas Endt <tmo26@gmx.de>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
]]--
|
|
||||||
|
|
||||||
module("luci.statistics.rrdtool.definitions.uptime", package.seeall)
|
|
||||||
|
|
||||||
function item()
|
|
||||||
return luci.i18n.translate("Uptime")
|
|
||||||
end
|
|
||||||
|
|
||||||
function rrdargs( graph, plugin, plugin_instance, dtype )
|
|
||||||
|
|
||||||
return {
|
|
||||||
title = "%H: Uptime", vlabel = "seconds",
|
|
||||||
number_format = "%5.0lf%s", data = {
|
|
||||||
types = { "uptime" },
|
|
||||||
options = {
|
|
||||||
uptime = { title = "Uptime %di", noarea = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<%#
|
|
||||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
|
||||||
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
Licensed to the public under the Apache License 2.0.
|
|
||||||
-%>
|
|
||||||
|
|
||||||
<%+header%>
|
|
||||||
|
|
||||||
<h2 name="content"><%:Statistics%></h2>
|
|
||||||
|
|
||||||
<p><%_The statistics package uses <a href="https://collectd.org/">Collectd</a>
|
|
||||||
to gather data and <a href="http://oss.oetiker.ch/rrdtool/">RRDtool</a> to
|
|
||||||
render diagram images.%></p>
|
|
||||||
|
|
||||||
<p><%_You can install additional collectd-mod-* plugins to enable more statistics.%></p>
|
|
||||||
|
|
||||||
<%+footer%>
|
|
|
@ -1,38 +0,0 @@
|
||||||
<%#
|
|
||||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
|
||||||
Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
|
|
||||||
Licensed to the public under the Apache License 2.0.
|
|
||||||
-%>
|
|
||||||
|
|
||||||
<%+header%>
|
|
||||||
|
|
||||||
<h2 name="content"><%:Statistics%></h2>
|
|
||||||
|
|
||||||
<form action="" method="get">
|
|
||||||
<select name="host">
|
|
||||||
<% for i, host in ipairs(hosts) do %>
|
|
||||||
<option<% if host == current_host then %> selected="selected"<% end %>><%=pcdata(host)%></option>
|
|
||||||
<% end %>
|
|
||||||
</select>
|
|
||||||
<input class="cbi-button cbi-button-apply" type="submit" name="submit" value="<%:Display Host »%>" />
|
|
||||||
<select name="timespan">
|
|
||||||
<% for i, span in ipairs(timespans) do %>
|
|
||||||
<option<% if span == current_timespan then %> selected="selected"<% end %>><%=span%></option>
|
|
||||||
<% end %>
|
|
||||||
</select>
|
|
||||||
<input class="cbi-button cbi-button-apply" type="submit" name="submit" value="<%:Display timespan »%>" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<div style="text-align: center">
|
|
||||||
<% for i, img in ipairs(images) do %>
|
|
||||||
<img src="<%=REQUEST_URI%>?img=<%=img%>&host=<%=current_host%>" />
|
|
||||||
<br />
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%+footer%>
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"admin/statistics": {
|
||||||
|
"title": "Statistics",
|
||||||
|
"order": 80,
|
||||||
|
"action": {
|
||||||
|
"type": "firstchild"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"uci": { "luci_statistics": true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"admin/statistics/graphs": {
|
||||||
|
"title": "Graphs",
|
||||||
|
"order": 10,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "statistics/graphs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"admin/statistics/collectd": {
|
||||||
|
"title": "Setup",
|
||||||
|
"order": 20,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "statistics/collectd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue