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
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 }
- end
+ -- remember images
+ table.insert( images, opts.image )
- 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 )
- -- 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
- -- 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 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
+ -- 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
+ -- 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 legend = string.format(
+ "%-" .. longest_name .. "s",
+ source.name
+ )
- local numfmt = opts.number_format or "%6.1lf"
+ local numfmt = opts.number_format or "%6.1lf"
- local line_color
- local area_color
+ 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
+ -- 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
- area_color = self.colors:to_string(
- self.colors:faded( area_color )
- )
+ -- 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
+
+ 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
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
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
--- /dev/null
+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