* ffluci/statistics: diagram model updates, added ping to genconfig, fixed random() in colors.lua and added support for multiple diagrams per diagram controller
This commit is contained in:
parent
32acc2cf98
commit
4a80f37832
8 changed files with 302 additions and 93 deletions
|
@ -294,6 +294,12 @@ plugins = {
|
|||
|
||||
network = config_network,
|
||||
|
||||
ping = {
|
||||
{ "TTL" },
|
||||
{ },
|
||||
{ "Hosts" }
|
||||
},
|
||||
|
||||
processes = {
|
||||
{ },
|
||||
{ },
|
||||
|
|
|
@ -66,7 +66,20 @@ function Graph._clearargs( self )
|
|||
end
|
||||
end
|
||||
|
||||
function Graph._forcelol( self, list )
|
||||
if type(list[1]) ~= "table" then
|
||||
return( { list } )
|
||||
end
|
||||
return( list )
|
||||
end
|
||||
|
||||
function Graph._rrdtool( self, png, rrd )
|
||||
|
||||
-- prepare directory
|
||||
local dir = png:gsub("/[^/]+$","")
|
||||
ffluci.fs.mkdir( dir, true )
|
||||
|
||||
-- construct commandline
|
||||
local cmdline = "rrdtool graph " .. png
|
||||
|
||||
for i, opt in ipairs(self.args) do
|
||||
|
@ -84,95 +97,95 @@ function Graph._rrdtool( self, png, rrd )
|
|||
end
|
||||
end
|
||||
|
||||
-- execute rrdtool
|
||||
local rrdtool = io.popen( cmdline )
|
||||
rrdtool:read("*a")
|
||||
rrdtool:close()
|
||||
end
|
||||
|
||||
function Graph._generic( self, optlist )
|
||||
function Graph._generic( self, opts )
|
||||
|
||||
local images = { }
|
||||
|
||||
if type(optlist[1]) ~= "table" then
|
||||
optlist = { optlist }
|
||||
-- remember images
|
||||
table.insert( images, opts.image )
|
||||
|
||||
-- insert provided addition rrd options
|
||||
self:_push( { "-t", opts.title or "Unknown title" } )
|
||||
self:_push( opts.rrd )
|
||||
|
||||
-- construct an array of safe instance names
|
||||
local inst_names = { }
|
||||
for i, source in ipairs(opts.sources) do
|
||||
inst_names[i] = i .. source.name:gsub("[^A-Za-z0-9%-_]","_")
|
||||
end
|
||||
|
||||
for i, opts in ipairs(optlist) do
|
||||
-- remember images
|
||||
table.insert( images, opts.image )
|
||||
|
||||
-- insert provided addition rrd options
|
||||
self:_push( { "-t", opts.title or "Unknown title" } )
|
||||
self:_push( opts.rrd )
|
||||
|
||||
-- construct an array of safe instance names
|
||||
local inst_names = { }
|
||||
for i, source in ipairs(opts.sources) do
|
||||
inst_names[i] = i .. source.name:gsub("[^A-Za-z0-9%-_]","_")
|
||||
-- create DEF statements for each instance, find longest instance name
|
||||
local longest_name = 0
|
||||
for i, source in ipairs(opts.sources) do
|
||||
if source.name:len() > longest_name then
|
||||
longest_name = source.name:len()
|
||||
end
|
||||
|
||||
-- create DEF statements for each instance, find longest instance name
|
||||
local longest_name = 0
|
||||
for i, source in ipairs(opts.sources) do
|
||||
if source.name:len() > longest_name then
|
||||
longest_name = source.name:len()
|
||||
end
|
||||
local ds = source.ds or "value"
|
||||
|
||||
self:_push( "DEF:" .. inst_names[i] .. "_min=" ..source.rrd .. ":value:MIN" )
|
||||
self:_push( "DEF:" .. inst_names[i] .. "_avg=" ..source.rrd .. ":value:AVERAGE" )
|
||||
self:_push( "DEF:" .. inst_names[i] .. "_max=" ..source.rrd .. ":value:MAX" )
|
||||
self:_push( "CDEF:" .. inst_names[i] .. "_nnl=" .. inst_names[i] .. "_avg,UN,0," .. inst_names[i] .. "_avg,IF" )
|
||||
end
|
||||
self:_push( "DEF:" .. inst_names[i] .. "_min=" ..source.rrd .. ":" .. ds .. ":MIN" )
|
||||
self:_push( "DEF:" .. inst_names[i] .. "_avg=" ..source.rrd .. ":" .. ds .. ":AVERAGE" )
|
||||
self:_push( "DEF:" .. inst_names[i] .. "_max=" ..source.rrd .. ":" .. ds .. ":MAX" )
|
||||
self:_push( "CDEF:" .. inst_names[i] .. "_nnl=" .. inst_names[i] .. "_avg,UN,0," .. inst_names[i] .. "_avg,IF" )
|
||||
end
|
||||
|
||||
-- create CDEF statement for last instance name
|
||||
self:_push( "CDEF:" .. inst_names[#inst_names] .. "_stk=" .. inst_names[#inst_names] .. "_nnl" )
|
||||
-- create CDEF statement for last instance name
|
||||
self:_push( "CDEF:" .. inst_names[#inst_names] .. "_stk=" .. inst_names[#inst_names] .. "_nnl" )
|
||||
|
||||
-- create CDEF statements for each instance
|
||||
for i, source in ipairs(inst_names) do
|
||||
if i > 1 then
|
||||
self:_push(
|
||||
"CDEF:" ..
|
||||
inst_names[1 + #inst_names - i] .. "_stk=" ..
|
||||
inst_names[1 + #inst_names - i] .. "_nnl," ..
|
||||
inst_names[2 + #inst_names - i] .. "_stk,+"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
-- create LINE and GPRINT statements for each instance
|
||||
for i, source in ipairs(opts.sources) do
|
||||
|
||||
local legend = string.format(
|
||||
"%-" .. longest_name .. "s",
|
||||
source.name
|
||||
-- create CDEF statements for each instance
|
||||
for i, source in ipairs(inst_names) do
|
||||
if i > 1 then
|
||||
self:_push(
|
||||
"CDEF:" ..
|
||||
inst_names[1 + #inst_names - i] .. "_stk=" ..
|
||||
inst_names[1 + #inst_names - i] .. "_nnl," ..
|
||||
inst_names[2 + #inst_names - i] .. "_stk,+"
|
||||
)
|
||||
|
||||
local numfmt = opts.number_format or "%6.1lf"
|
||||
|
||||
local line_color
|
||||
local area_color
|
||||
|
||||
if type(opts.colors[source.name]) == "string" then
|
||||
line_color = opts.colors[source.name]
|
||||
area_color = self.colors:from_string( line_color )
|
||||
else
|
||||
area_color = self.colors:random()
|
||||
line_color = self.colors:to_string( area_color )
|
||||
end
|
||||
|
||||
area_color = self.colors:to_string(
|
||||
self.colors:faded( area_color )
|
||||
)
|
||||
|
||||
self:_push( "AREA:" .. inst_names[i] .. "_stk#" .. area_color )
|
||||
self:_push( "LINE1:" .. inst_names[i] .. "_stk#" .. line_color .. ":" .. legend )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_min:MIN:" .. numfmt .. " Min" )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_avg:AVERAGE:" .. numfmt .. " Avg" )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_max:MAX:" .. numfmt .. " Max" )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_avg:LAST:" .. numfmt .. " Last\\l" )
|
||||
end
|
||||
end
|
||||
|
||||
-- create LINE and GPRINT statements for each instance
|
||||
for i, source in ipairs(opts.sources) do
|
||||
|
||||
local legend = string.format(
|
||||
"%-" .. longest_name .. "s",
|
||||
source.name
|
||||
)
|
||||
|
||||
local numfmt = opts.number_format or "%6.1lf"
|
||||
|
||||
local line_color
|
||||
local area_color
|
||||
|
||||
-- find color: 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 ) )
|
||||
|
||||
|
||||
self:_push( "AREA:" .. inst_names[i] .. "_stk#" .. area_color )
|
||||
self:_push( "LINE1:" .. inst_names[i] .. "_stk#" .. line_color .. ":" .. legend )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_min:MIN:" .. numfmt .. " Min" )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_avg:AVERAGE:" .. numfmt .. " Avg" )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_max:MAX:" .. numfmt .. " Max" )
|
||||
self:_push( "GPRINT:" .. inst_names[i] .. "_avg:LAST:" .. numfmt .. " Last\\l" )
|
||||
end
|
||||
|
||||
return images
|
||||
end
|
||||
|
||||
|
@ -186,14 +199,16 @@ function Graph.render( self, host, plugin, plugin_instance )
|
|||
local stat, def = pcall( require, plugin_def )
|
||||
|
||||
if stat and def and type(def.rrdargs) == "function" then
|
||||
for i, png in ipairs( self:_generic( def.rrdargs( self, host, plugin, plugin_instance, dtype ) ) ) do
|
||||
table.insert( pngs, png )
|
||||
for i, opts in ipairs( self:_forcelol( def.rrdargs( self, host, plugin, plugin_instance, dtype ) ) ) do
|
||||
for i, png in ipairs( self:_generic( opts ) ) do
|
||||
table.insert( pngs, png )
|
||||
|
||||
-- exec
|
||||
self:_rrdtool( png )
|
||||
-- exec
|
||||
self:_rrdtool( png )
|
||||
|
||||
-- clear args
|
||||
self:_clearargs()
|
||||
-- clear args
|
||||
self:_clearargs()
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
|
@ -205,14 +220,16 @@ function Graph.render( self, host, plugin, plugin_instance )
|
|||
local stat, def = pcall( require, dtype_def )
|
||||
|
||||
if stat and def and type(def.rrdargs) == "function" then
|
||||
for i, png in ipairs( self:_generic( def.rrdargs( self, host, plugin, plugin_instance, dtype ) ) ) do
|
||||
table.insert( pngs, png )
|
||||
for i, opts in ipairs( self:_forcelol( def.rrdargs( self, host, plugin, plugin_instance, dtype ) ) ) do
|
||||
for i, png in ipairs( self:_generic( opts ) ) do
|
||||
table.insert( pngs, png )
|
||||
|
||||
-- exec
|
||||
self:_rrdtool( png )
|
||||
-- exec
|
||||
self:_rrdtool( png )
|
||||
|
||||
-- clear args
|
||||
self:_clearargs()
|
||||
-- clear args
|
||||
self:_clearargs()
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
|
|
|
@ -24,15 +24,15 @@ function Instance.to_string( self, c )
|
|||
end
|
||||
|
||||
function Instance.random( self )
|
||||
local r = math.random(256)
|
||||
local g = math.random(256)
|
||||
local min = 1
|
||||
local max = 256
|
||||
local r = math.random(255)
|
||||
local g = math.random(255)
|
||||
local min = 0
|
||||
local max = 255
|
||||
|
||||
if ( r + g ) < 256 then
|
||||
min = 256 - r - g
|
||||
if ( r + g ) < 255 then
|
||||
min = 255 - r - g
|
||||
else
|
||||
max = 512 - r - g
|
||||
max = 511 - r - g
|
||||
end
|
||||
|
||||
local b = min + math.floor( math.random() * ( max - min ) )
|
||||
|
|
|
@ -7,7 +7,7 @@ function rrdargs( graph, host, plugin, plugin_instance, dtype )
|
|||
opts = { }
|
||||
opts.sources = { }
|
||||
opts.image = graph:mkpngpath( host, plugin, plugin_instance, dtype )
|
||||
opts.title = graph:mktitle( host, plugin, plugin_instance, dtype )
|
||||
opts.title = host .. ": Prozessorauslastung"
|
||||
opts.rrd = { "-v", "Percent" }
|
||||
opts.colors = {
|
||||
idle = 'ffffff',
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
module("ffluci.statistics.rrdtool.definitions.netlink", package.seeall)
|
||||
|
||||
function rrdargs( graph, host, plugin, plugin_instance )
|
||||
|
||||
local diagram_list = { }
|
||||
|
||||
-- diagram names
|
||||
local dtypes_names = {
|
||||
"Pakete",
|
||||
"Paketkollisionen",
|
||||
"Paketfehler",
|
||||
"Verkehr",
|
||||
"RX-Fehler",
|
||||
"TX-Fehler"
|
||||
}
|
||||
|
||||
-- diagram units
|
||||
local dtypes_units = {
|
||||
"Pakete/s",
|
||||
"Kollisionen/s",
|
||||
"Fehler/s", -- (?)
|
||||
"Bytes/s",
|
||||
"Fehler/s",
|
||||
"Fehler/s"
|
||||
}
|
||||
|
||||
-- data source overrides
|
||||
local dtypes_sources = {
|
||||
if_errors = { "rx", "tx" }, -- if_errors has rx and tx
|
||||
if_octets = { "rx", "tx" } -- if_octets has rx and tx
|
||||
}
|
||||
|
||||
-- diagram data types
|
||||
local dtypes_list = {
|
||||
|
||||
-- diagram 1: combined interface packet statistics
|
||||
{
|
||||
if_dropped = { "" }, -- packets/s
|
||||
if_multicast = { "" }, -- packets/s
|
||||
if_packets = { "" } -- packets/s
|
||||
},
|
||||
|
||||
-- diagram 2: interface collision statistics
|
||||
{
|
||||
if_collisions = { "" } -- collisions/s
|
||||
},
|
||||
|
||||
-- diagram 3: interface error statistics
|
||||
{
|
||||
if_errors = { "" } -- errors/s (?)
|
||||
},
|
||||
|
||||
-- diagram 4: interface traffic statistics
|
||||
{
|
||||
if_octets = { "" } -- bytes/s
|
||||
},
|
||||
|
||||
-- diagram 5: interface rx error statistics
|
||||
{
|
||||
if_rx_errors = { -- errors/s
|
||||
"length", "missed", "over", "crc", "fifo", "frame"
|
||||
}
|
||||
},
|
||||
|
||||
-- diagram 6: interface tx error statistics
|
||||
{
|
||||
if_tx_errors = { -- errors/s
|
||||
"aborted", "carrier", "fifo", "heartbeat", "window"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- diagram colors
|
||||
local dtypes_colors = {
|
||||
|
||||
-- diagram 1
|
||||
{
|
||||
if_dropped = "ff0000",
|
||||
if_multicast = "0000ff",
|
||||
if_packets = "00ff00"
|
||||
},
|
||||
|
||||
-- diagram 2
|
||||
{
|
||||
if_collisions = "ff0000"
|
||||
},
|
||||
|
||||
-- diagram 3
|
||||
{
|
||||
if_errors__tx_ = "ff0000",
|
||||
if_errors__rx_ = "ff5500"
|
||||
},
|
||||
|
||||
-- diagram 4
|
||||
{
|
||||
if_octets__tx_ = "00ff00",
|
||||
if_octets__rx_ = "0000ff"
|
||||
},
|
||||
|
||||
-- diagram 5
|
||||
{
|
||||
length = "0000ff",
|
||||
missed = "ff5500",
|
||||
over = "ff0066",
|
||||
crc = "ff0000",
|
||||
fifo = "00ff00",
|
||||
frame = "ffff00"
|
||||
},
|
||||
|
||||
-- diagram 6
|
||||
{
|
||||
aborted = "ff0000",
|
||||
carrier = "ffff00",
|
||||
fifo = "00ff00",
|
||||
heartbeat = "0000ff",
|
||||
window = "8800ff"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for i, name in ipairs(dtypes_names) do
|
||||
|
||||
local dtypes = dtypes_list[i]
|
||||
local opts = { }
|
||||
|
||||
opts.sources = { }
|
||||
opts.image = graph:mkpngpath( host, plugin, plugin_instance, "netlink" .. i )
|
||||
opts.title = host .. ": Netlink Statistiken - " .. name .. " auf " .. plugin_instance
|
||||
opts.rrd = { "-v", dtypes_units[i] }
|
||||
opts.colors = dtypes_colors[i]
|
||||
|
||||
for dtype, dinstances in pairs(dtypes) do
|
||||
for i, inst in ipairs(dinstances) do
|
||||
|
||||
local name = inst
|
||||
if name:len() == 0 then name = dtype end
|
||||
|
||||
-- check for data source override
|
||||
if dtypes_sources[dtype] then
|
||||
|
||||
-- has override
|
||||
for i, ds in ipairs(dtypes_sources[dtype]) do
|
||||
table.insert( opts.sources, {
|
||||
ds = ds, -- override
|
||||
name = name .. " (" .. ds .. ")",
|
||||
rrd = graph:mkrrdpath( host, plugin, plugin_instance, dtype, inst )
|
||||
} )
|
||||
end
|
||||
else
|
||||
-- no override, assume single "value" data source
|
||||
table.insert( opts.sources, {
|
||||
name = name,
|
||||
rrd = graph:mkrrdpath( host, plugin, plugin_instance, dtype, inst )
|
||||
} )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( diagram_list, opts )
|
||||
end
|
||||
|
||||
return diagram_list
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
module("ffluci.statistics.rrdtool.definitions.ping.ping", package.seeall)
|
||||
|
||||
function rrdargs( graph, host, plugin, plugin_instance, dtype )
|
||||
|
||||
dtype_instances = graph.tree:data_instances( plugin, plugin_instance, dtype )
|
||||
|
||||
opts = { }
|
||||
opts.sources = { }
|
||||
opts.image = graph:mkpngpath( host, plugin, plugin_instance, dtype )
|
||||
opts.title = host .. ": Pingzeiten"
|
||||
opts.rrd = { "-v", "Millisekunden" }
|
||||
opts.colors = { }
|
||||
|
||||
for i, inst in ipairs(dtype_instances) do
|
||||
opts.sources[i] = {
|
||||
ds = "ping",
|
||||
name = inst,
|
||||
rrd = graph:mkrrdpath( host, plugin, plugin_instance, dtype, inst )
|
||||
}
|
||||
end
|
||||
|
||||
return opts
|
||||
end
|
|
@ -7,7 +7,7 @@ function rrdargs( graph, host, plugin, plugin_instance )
|
|||
opts = { }
|
||||
opts.sources = { }
|
||||
opts.image = graph:mkpngpath( host, plugin, plugin_instance, "wireless" )
|
||||
opts.title = graph:mktitle( host, plugin, plugin_instance, "wireless" )
|
||||
opts.title = host .. ": WLAN Signal"
|
||||
opts.rrd = { "-v", "dBm" }
|
||||
opts.colors = {
|
||||
signal_power = '0000ff',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<%+header%>
|
||||
|
||||
<h1>Statistik (<%=request%>)</h1>
|
||||
<h1>Statistik</h1>
|
||||
|
||||
<% for i, img in ipairs(images) do %>
|
||||
<img src="<%=img:gsub("/tmp/rrdimg/OpenWrt","/img")%>" />
|
||||
|
|
Loading…
Reference in a new issue