From 4a80f37832a692f627b5e02bc8cdfb2efd9909e3 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sun, 25 May 2008 17:47:38 +0000 Subject: [PATCH] * ffluci/statistics: diagram model updates, added ping to genconfig, fixed random() in colors.lua and added support for multiple diagrams per diagram controller --- .../luci-statistics/root/usr/bin/stat-genconfig | 6 + .../luci-statistics/src/statistics/rrdtool.lua | 171 +++++++++++---------- .../src/statistics/rrdtool/colors.lua | 14 +- .../src/statistics/rrdtool/definitions/cpu/cpu.lua | 2 +- .../src/statistics/rrdtool/definitions/netlink.lua | 163 ++++++++++++++++++++ .../statistics/rrdtool/definitions/ping/ping.lua | 23 +++ .../statistics/rrdtool/definitions/wireless.lua | 2 +- .../src/view/public_statistics/graph.htm | 2 +- 8 files changed, 296 insertions(+), 87 deletions(-) create mode 100644 applications/luci-statistics/src/statistics/rrdtool/definitions/netlink.lua create mode 100644 applications/luci-statistics/src/statistics/rrdtool/definitions/ping/ping.lua diff --git a/applications/luci-statistics/root/usr/bin/stat-genconfig b/applications/luci-statistics/root/usr/bin/stat-genconfig index cd707c6b2..39532ca07 100755 --- a/applications/luci-statistics/root/usr/bin/stat-genconfig +++ b/applications/luci-statistics/root/usr/bin/stat-genconfig @@ -294,6 +294,12 @@ plugins = { network = config_network, + ping = { + { "TTL" }, + { }, + { "Hosts" } + }, + processes = { { }, { }, diff --git a/applications/luci-statistics/src/statistics/rrdtool.lua b/applications/luci-statistics/src/statistics/rrdtool.lua index 56894eb6c..97772cc38 100644 --- a/applications/luci-statistics/src/statistics/rrdtool.lua +++ b/applications/luci-statistics/src/statistics/rrdtool.lua @@ -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,93 +97,93 @@ 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 } - 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 @@ -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 diff --git a/applications/luci-statistics/src/statistics/rrdtool/colors.lua b/applications/luci-statistics/src/statistics/rrdtool/colors.lua index f1cec1f22..cd1e52d19 100644 --- a/applications/luci-statistics/src/statistics/rrdtool/colors.lua +++ b/applications/luci-statistics/src/statistics/rrdtool/colors.lua @@ -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 ) ) diff --git a/applications/luci-statistics/src/statistics/rrdtool/definitions/cpu/cpu.lua b/applications/luci-statistics/src/statistics/rrdtool/definitions/cpu/cpu.lua index fad7fd2a4..557c5dafe 100644 --- a/applications/luci-statistics/src/statistics/rrdtool/definitions/cpu/cpu.lua +++ b/applications/luci-statistics/src/statistics/rrdtool/definitions/cpu/cpu.lua @@ -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', diff --git a/applications/luci-statistics/src/statistics/rrdtool/definitions/netlink.lua b/applications/luci-statistics/src/statistics/rrdtool/definitions/netlink.lua new file mode 100644 index 000000000..de3924dc7 --- /dev/null +++ b/applications/luci-statistics/src/statistics/rrdtool/definitions/netlink.lua @@ -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 diff --git a/applications/luci-statistics/src/statistics/rrdtool/definitions/ping/ping.lua b/applications/luci-statistics/src/statistics/rrdtool/definitions/ping/ping.lua new file mode 100644 index 000000000..48a5673ad --- /dev/null +++ b/applications/luci-statistics/src/statistics/rrdtool/definitions/ping/ping.lua @@ -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 diff --git a/applications/luci-statistics/src/statistics/rrdtool/definitions/wireless.lua b/applications/luci-statistics/src/statistics/rrdtool/definitions/wireless.lua index 016f1f465..5b3acc51f 100644 --- a/applications/luci-statistics/src/statistics/rrdtool/definitions/wireless.lua +++ b/applications/luci-statistics/src/statistics/rrdtool/definitions/wireless.lua @@ -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', diff --git a/applications/luci-statistics/src/view/public_statistics/graph.htm b/applications/luci-statistics/src/view/public_statistics/graph.htm index d0da883d6..093d76d0e 100644 --- a/applications/luci-statistics/src/view/public_statistics/graph.htm +++ b/applications/luci-statistics/src/view/public_statistics/graph.htm @@ -1,6 +1,6 @@ <%+header%> -

Statistik (<%=request%>)

+

Statistik

<% for i, img in ipairs(images) do %> " /> -- 2.11.0