* 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:
Jo-Philipp Wich 2008-05-25 17:47:38 +00:00
parent 32acc2cf98
commit 4a80f37832
8 changed files with 302 additions and 93 deletions

View file

@ -294,6 +294,12 @@ plugins = {
network = config_network,
ping = {
{ "TTL" },
{ },
{ "Hosts" }
},
processes = {
{ },
{ },

View file

@ -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

View file

@ -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 ) )

View file

@ -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',

View file

@ -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

View file

@ -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

View file

@ -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',

View file

@ -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")%>" />