1 -- Authors: Sadrul Habib Chowdhury <imadil@gmail.com>
2 -- License: Public domain
3 -- Last Changed: Unknown
5 -- statusd_netmon.lua: monitor the speed of a network interface
7 -- Thanx to Tuomo for pointing out a problem in the previous script.
9 -- In case this doesn't work for someone, do let me know :)
12 -- Sadrul Habib Chowdhury (Adil)
13 -- imadil at gmail dot com
15 -- Support for per-stat monitors and thresholds added by Jeremy
19 -- Monitor values available with this monitor:
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
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.
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
71 local settings
= table.join(statusd
.get_config("netmon"), statusd_netmon
)
74 -- tokenize the string
76 local function tokenize(str
)
81 for k
in string.gfind(str
, '(%w+)') do
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')
101 return tonumber(connections
)
105 -- calculate the average
107 local function calc_avg(lin
, lout
)
108 if counter
== settings
.avg_sec
then
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()
130 for s
in io
.lines('/proc/net/dev') do
131 local f
= string.find(s
, settings
.device
)
133 local t
= tokenize(s
)
134 return t
[positions
[0]]
, t
[positions
[1]]
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
149 elseif imp
and val
> imp
then
156 -- update the netmon monitor
158 local function update_netmon_info()
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")
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()
196 output
= "[" .. tostring(count
) .. "] " .. output
198 statusd
.inform("netmon_count", tostring(count
))
199 statusd
.inform("netmon_count_hint",
200 get_hint("count", count
))
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')
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
)
239 if t
[i
] == "bytes" then
248 if t
[i
] == "bytes" then
254 if not positions
[0] or not positions
[1] then
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
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")
283 statusd
.inform("netmon", "oops")
284 statusd
.inform("netmon_hint", "critical")
288 init_netmon_monitor()