applications/luci-statistics: avoid global vars, avoid nil indexing, get rid of count...
[project/luci.git] / applications / luci-statistics / luasrc / statistics / datatree.lua
1 --[[
2
3 Luci statistics - rrd data tree builder
4 (c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10                 http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 module("luci.statistics.datatree", package.seeall)
17
18 local util = require("luci.util")
19 local sys  = require("luci.sys")
20 local fs   = require("nixio.fs")
21 local uci  = require("luci.model.uci").cursor()
22 local sections = uci:get_all("luci_statistics")
23
24
25 Instance = util.class()
26
27 function Instance.__init__( self, host )
28         self._host    = host or sections.collectd.Hostname or sys.hostname()
29         self._libdir  = sections.collectd.PluginDir        or "/usr/lib/collectd"
30         self._rrddir  = sections.collectd_rrdtool.DataDir  or "/tmp/rrd"
31
32         self._libdir  = self._libdir:gsub("/$","")
33         self._rrddir  = self._rrddir:gsub("/$","")
34         self._plugins = { }
35
36         self:_scan()
37 end
38
39 function Instance._mkpath( self, plugin, pinstance )
40         local dir = self._rrddir .. "/" .. self._host
41
42         if type(plugin) == "string" and plugin:len() > 0 then
43                 dir = dir .. "/" .. plugin
44
45                 if type(pinstance) == "string" and pinstance:len() > 0 then
46                         dir = dir .. "-" .. pinstance
47                 end
48         end
49
50         return dir
51 end
52
53 function Instance._ls( self, ... )
54         local ditr = fs.dir(self:_mkpath(...))
55         if ditr then
56                 local dirs = { }
57                 while true do
58                         local d = ditr()
59                         if not d then break end
60                         dirs[#dirs+1] = d
61                 end
62                 return dirs
63         end
64 end
65
66 function Instance._notzero( self, table )
67         for k in pairs(table) do
68                 return true
69         end
70
71         return false
72 end
73
74 function Instance._scan( self )
75         local dirs = self:_ls()
76         if not dirs then
77                 return
78         end
79
80 --      for i, plugin in ipairs( dirs ) do
81 --              if plugin:match("%w+.so") then
82 --                      self._plugins[ plugin:gsub("%.so$", "") ] = { }
83 --              end
84 --      end
85
86         for _, dir in ipairs(dirs) do
87                 if dir ~= "." and dir ~= ".." and
88                    fs.stat(self:_mkpath(dir)).type == "dir"
89                 then
90                         local plugin = dir:gsub("%-.+$", "")
91                         if not self._plugins[plugin] then
92                                 self._plugins[plugin] = { }
93                         end
94                 end
95         end
96
97         for plugin, instances in pairs( self._plugins ) do
98
99                 local dirs = self:_ls()
100
101                 if type(dirs) == "table" then
102                         for i, dir in ipairs(dirs) do
103                                 if dir:find( plugin .. "%-" ) or dir == plugin then
104                                         local instance = ""
105
106                                         if dir ~= plugin then
107                                                 instance = dir:gsub( plugin .. "%-", "", 1 )
108                                         end
109
110                                         instances[instance] = { }
111                                 end
112                         end
113                 end
114
115                 for instance, data_instances in pairs( instances ) do
116
117                         dirs = self:_ls(plugin, instance)
118
119                         if type(dirs) == "table" then
120                                 for i, file in ipairs(dirs) do
121                                         if file:find("%.rrd") then
122                                                 file = file:gsub("%.rrd","")
123
124                                                 local data_type
125                                                 local data_instance
126
127                                                 if file:find("%-") then
128                                                         data_type     = file:gsub( "%-.+","" )
129                                                         data_instance = file:gsub( "[^%-]-%-", "", 1 )
130                                                 else
131                                                         data_type     = file
132                                                         data_instance = ""
133                                                 end
134
135                                                 if not data_instances[data_type] then
136                                                         data_instances[data_type] = { data_instance }
137                                                 else
138                                                         table.insert( data_instances[data_type], data_instance )
139                                                 end
140                                         end
141                                 end
142                         end
143                 end
144         end
145 end
146
147
148 function Instance.plugins( self )
149         local rv = { }
150
151         for plugin, val in pairs( self._plugins ) do
152                 if self:_notzero( val ) then
153                         table.insert( rv, plugin )
154                 end
155         end
156
157         return rv
158 end
159
160 function Instance.plugin_instances( self, plugin )
161         local rv = { }
162
163         for instance, val in pairs( self._plugins[plugin] ) do
164                 table.insert( rv, instance )
165         end
166
167         return rv
168 end
169
170 function Instance.data_types( self, plugin, instance )
171         local rv = { }
172         local p  = self._plugins[plugin]
173
174         if type(p) == "table" and type(p[instance]) == "table" then
175                 for type, val in pairs(p[instance]) do
176                         table.insert( rv, type )
177                 end
178         end
179
180         return rv
181 end
182
183 function Instance.data_instances( self, plugin, instance, dtype )
184         local rv = { }
185         local p  = self._plugins[plugin]
186
187         if type(p) == "table" and type(p[instance]) == "table" and type(p[instance][dtype]) == "table" then
188                 for i, instance in ipairs(p[instance][dtype]) do
189                         table.insert( rv, instance )
190                 end
191         end
192
193         return rv
194 end
195
196 function Instance.host_instances( self )
197         local hosts_path = fs.glob(self._rrddir..'/*')
198         local hosts = { }
199
200         if hosts_path then
201                 local path
202                 for path in hosts_path do
203                         hosts[#hosts+1] = fs.basename(path)
204                 end
205         end
206
207         return hosts
208 end
209