summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-statistics/src/statistics/rrdtool.lua
diff options
context:
space:
mode:
Diffstat (limited to 'applications/luci-statistics/src/statistics/rrdtool.lua')
-rw-r--r--applications/luci-statistics/src/statistics/rrdtool.lua171
1 files changed, 94 insertions, 77 deletions
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