* ffluci/statistics: diagram model updates, added ping to genconfig, fixed random...
authorJo-Philipp Wich <jow@openwrt.org>
Sun, 25 May 2008 17:47:38 +0000 (17:47 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sun, 25 May 2008 17:47:38 +0000 (17:47 +0000)
applications/luci-statistics/root/usr/bin/stat-genconfig
applications/luci-statistics/src/statistics/rrdtool.lua
applications/luci-statistics/src/statistics/rrdtool/colors.lua
applications/luci-statistics/src/statistics/rrdtool/definitions/cpu/cpu.lua
applications/luci-statistics/src/statistics/rrdtool/definitions/netlink.lua [new file with mode: 0644]
applications/luci-statistics/src/statistics/rrdtool/definitions/ping/ping.lua [new file with mode: 0644]
applications/luci-statistics/src/statistics/rrdtool/definitions/wireless.lua
applications/luci-statistics/src/view/public_statistics/graph.htm

index cd707c6..39532ca 100755 (executable)
@@ -294,6 +294,12 @@ plugins = {
 
        network = config_network,
 
+       ping    = {
+               { "TTL" },
+               { },
+               { "Hosts" }
+       },
+
        processes = {
                { },
                { },
index 56894eb..97772cc 100644 (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,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
 
index f1cec1f..cd1e52d 100644 (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 ) )
index fad7fd2..557c5da 100644 (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',
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 (file)
index 0000000..de3924d
--- /dev/null
@@ -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 (file)
index 0000000..48a5673
--- /dev/null
@@ -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
index 016f1f4..5b3acc5 100644 (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',
index d0da883..093d76d 100644 (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")%>" />