Include notionflux in the main repo instead of its own submodule
[notion/jeffpc.git] / contrib / statusd / statusd_netmon.lua
blob116ca7deed54c428347a0c2b129fd9f6d1fb6472
1 -- Authors: Sadrul Habib Chowdhury <imadil@gmail.com>
2 -- License: Public domain
3 -- Last Changed: Unknown
4 --
5 -- statusd_netmon.lua: monitor the speed of a network interface
6 --
7 -- Thanx to Tuomo for pointing out a problem in the previous script.
8 --
9 -- In case this doesn't work for someone, do let me know :)
11 -- Author
12 -- Sadrul Habib Chowdhury (Adil)
13 -- imadil at gmail dot com
15 -- Support for per-stat monitors and thresholds added by Jeremy
16 -- Hankins.
19 -- Monitor values available with this monitor:
21 -- netmon
22 -- netmon_kbsin
23 -- netmon_kbsout
24 -- netmon_avgin
25 -- netmon_avgout
26 -- netmon_count
28 -- To use the average values or the count you need show_avg and
29 -- show_count turned on, respectively. If you want the default format
30 -- (which you get with %netmon) but with colors for important and
31 -- critical thresholds, try:
33 -- %netmon_kbsin/%netmon_kbsout (%netmon_avgin/%netmon_avgout)
35 if not statusd_netmon then
36 statusd_netmon = {
37 device = "eth0",
38 show_avg = 1, -- show average stat?
39 avg_sec = 60, -- default, shows average of 1 minute
40 show_count = 0, -- show tcp connection count?
41 interval = 1*1000, -- update every second
43 -- Threshold information. These values should likely be tweaked to
44 -- suit local conditions.
45 important = {
46 kbsin = 1/10,
47 kbsout = 1/10,
48 avgin = 1/10,
49 avgout = 1/10,
50 count = 4,
53 critical = {
54 kbsin = 30,
55 kbsout = 30,
56 avgin = 5,
57 avgout = 5,
58 count = 50,
61 end
63 local timer = nil -- the timer
64 local positions = {} -- positions where the entries will be
65 local last = {} -- the last readings
66 local history_in = {} -- history to calculate the average
67 local history_out = {}
68 local total_in, total_out = 0, 0
69 local counter = 0 --
71 local settings = table.join(statusd.get_config("netmon"), statusd_netmon)
74 -- tokenize the string
76 local function tokenize(str)
77 local ret = {}
78 local i = 0
79 local k = nil
81 for k in string.gfind(str, '(%w+)') do
82 ret[i] = k
83 i = i + 1
84 end
85 return ret
86 end
88 --
89 -- get the connection count
91 local function get_connection_count()
92 local f = io.popen('netstat -st', 'r')
93 if not f then return nil end
95 local output = f:read('*a')
96 if string.len(output) == 0 then return nil end
98 local s, e, connections =
99 string.find(output, '%s+(%d+)%s+connections established%s')
100 f:close()
101 return tonumber(connections)
105 -- calculate the average
107 local function calc_avg(lin, lout)
108 if counter == settings.avg_sec then
109 counter = 0
112 total_in = total_in - history_in[counter] + lin
113 history_in[counter] = lin
115 total_out = total_out - history_out[counter] + lout
116 history_out[counter] = lout
118 counter = counter + 1
120 return total_in/settings.avg_sec, total_out/settings.avg_sec
124 -- parse the information
126 local function parse_netmon_info()
127 local s
128 local lin, lout
130 for s in io.lines('/proc/net/dev') do
131 local f = string.find(s, settings.device)
132 if f then
133 local t = tokenize(s)
134 return t[positions[0]], t[positions[1]]
137 return nil, nil
141 -- Return a hint value for the given meter
143 local function get_hint(meter, val)
144 local hint = "normal"
145 local crit = settings.critical[meter]
146 local imp = settings.important[meter]
147 if crit and val > crit then
148 hint = "critical"
149 elseif imp and val > imp then
150 hint = "important"
152 return hint
156 -- update the netmon monitor
158 local function update_netmon_info()
159 local s
160 local lin, lout
162 local function fmt(num)
163 return(string.format("%.1fK", num))
166 lin, lout = parse_netmon_info()
167 if not lin or not lout then
168 -- you should never reach here
169 statusd.inform("netmon", "oops")
170 statusd.inform("netmon_hint", "critical")
171 return
174 last[0], lin = lin, lin - last[0]
175 last[1], lout = lout, lout - last[1]
177 local kbsin = lin/1024
178 local kbsout = lout/1024
180 local output = string.format("%.1fK/%.1fK", kbsin, kbsout)
182 if settings.show_avg == 1 then
183 local avgin, avgout = calc_avg(lin/1024, lout/1024)
184 output = output .. string.format(" (%.1fK/%.1fK)", avgin, avgout)
186 statusd.inform("netmon_avgin", fmt(avgin))
187 statusd.inform("netmon_avgin_hint",
188 get_hint("avgin", avgin))
189 statusd.inform("netmon_avgout", fmt(avgout))
190 statusd.inform("netmon_avgout_hint",
191 get_hint("avgout", avgout))
193 if settings.show_count == 1 then
194 local count = get_connection_count()
195 if count then
196 output = "[" .. tostring(count) .. "] " .. output
198 statusd.inform("netmon_count", tostring(count))
199 statusd.inform("netmon_count_hint",
200 get_hint("count", count))
201 else
202 output = "[?] " .. output
203 statusd.inform("netmon_count", "?")
204 statusd.inform("netmon_count_hint", "critical")
208 statusd.inform("netmon_kbsin", fmt(kbsin))
209 statusd.inform("netmon_kbsin_hint",
210 get_hint("kbsin", kbsin))
211 statusd.inform("netmon_kbsout", fmt(kbsout))
212 statusd.inform("netmon_kbsout_hint",
213 get_hint("kbsout", kbsout))
214 statusd.inform("netmon", output)
216 timer:set(settings.interval, update_netmon_info)
220 -- is everything ok to begin with?
222 local function sanity_check()
223 local f = io.open('/proc/net/dev', 'r')
224 local e
226 if not f then
227 return false
230 local s = f:read('*line')
231 s = f:read('*line') -- the second line, which should give
232 -- us the positions of the info we seek
234 local t = tokenize(s)
235 local n = #(t)
236 local i = 0
238 for i = 0,n do
239 if t[i] == "bytes" then
240 positions[0] = i
241 break
245 i = positions[0] + 1
247 for i=i,n do
248 if t[i] == "bytes" then
249 positions[1] = i
250 break
254 if not positions[0] or not positions[1] then
255 return false
258 s = f:read('*a') -- read the whole file
259 if not string.find(s, settings.device) then
260 return false -- the device does not exist
263 return true
267 -- start the timer
269 local function init_netmon_monitor()
270 if sanity_check() then
271 timer = statusd.create_timer()
272 last[0], last[1] = parse_netmon_info()
274 if settings.show_avg == 1 then
275 for i=0,settings.avg_sec-1 do
276 history_in[i], history_out[i] = 0, 0
280 statusd.inform("netmon_template", "xxxxxxxxxxxxxxxxxxxxxxx")
281 update_netmon_info()
282 else
283 statusd.inform("netmon", "oops")
284 statusd.inform("netmon_hint", "critical")
288 init_netmon_monitor()