File: statusd_netmon.lua

package info (click to toggle)
ion3-scripts 20050418-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 300 kB
  • ctags: 153
  • sloc: makefile: 18
file content (194 lines) | stat: -rw-r--r-- 4,668 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
-- statusd_netmon.lua: monitor the speed of a network interface
--
-- Thanx to Tuomo for pointing out a problem in the previous script.
-- 
-- In case this doesn't work for someone, do let me know :)
--
-- Author
-- Sadrul Habib Chowdhury (Adil)
-- imadil at gmail dot com

local defaults = {
    device = "eth0",
    show_avg = 1,       -- show average stat?
    avg_sec = 60,       -- default, shows average of 1 minute
    show_count = 0,     -- show tcp connection count?
    interval = 1*1000   -- update every second
}

local timer = nil       -- the timer
local positions = {}    -- positions where the entries will be
local last = {}         -- the last readings
local history_in = {}   -- history to calculate the average
local history_out = {}
local total_in, total_out = 0, 0
local counter = 0       --

local settings = table.join(statusd.get_config("netmon"), defaults)

--
-- tokenize the string
--
local function tokenize(str)
    local ret = {}
    local i = 0
    local k = nil

    for k in string.gfind(str, '(%w+)') do
        ret[i] = k
        i = i + 1
    end
    return ret
end

-- 
-- get the connection count
--
local function get_connection_count()
    -- local f = io.popen('netstat -st | grep -e "[0-9]\\+ connections established" | sed s/"[ ]\\+\\([0-9]\\+\\) connections established"/\\\\1/', 'r')
    local f = io.popen('netstat -st | grep "connections established"', 'r')
    if not f then return 'q' end

    local ret = f:read('*a')
    ret = string.gsub(ret, '%s*(%d+).+', '%1')
    f:close()
    return tostring(ret)
end

--
-- calculate the average
--
local function calc_avg(lin, lout)
    if counter == settings.avg_sec then
        counter = 0
    end

    total_in = total_in - history_in[counter] + lin
    history_in[counter] = lin

    total_out = total_out - history_out[counter] + lout
    history_out[counter] = lout

    counter = counter + 1

    return string.format("%.1fK/%.1fK", total_in/settings.avg_sec, total_out/settings.avg_sec)
end

--
-- parse the information
--
local function parse_netmon_info()
    local s
    local lin, lout

    for s in io.lines('/proc/net/dev') do
        local f = string.find(s, settings.device)
        if f then
            local t = tokenize(s)
            return t[positions[0]], t[positions[1]]
       end
    end
    return nil, nil
end

--
-- update the netmon monitor
--
local function update_netmon_info()
    local s
    local lin, lout

    lin, lout = parse_netmon_info()
    if not lin or not lout then
        -- you should never reach here
        statusd.inform("netmon", "oops")
        statusd.inform("netmon_hint", "critical")
        return
    end

    last[0], lin = lin, lin - last[0]
    last[1], lout = lout, lout - last[1]

    local output = string.format("%.1fK/%.1fK", lin/1024, lout/1024)

    if settings.show_avg == 1 then
        output = output .. " (" .. calc_avg(lin/1024, lout/1024) .. ")"
    end
    if settings.show_count == 1 then
        output = "[" .. get_connection_count().."] " .. output
    end
    statusd.inform("netmon", output)
    timer:set(settings.interval, update_netmon_info)
end

--
-- is everything ok to begin with?
--
local function sanity_check()
    local f = io.open('/proc/net/dev', 'r')
    local e

    if not f then
        return false
    end

    local s = f:read('*line')
    s = f:read('*line')         -- the second line, which should give
                                -- us the positions of the info we seek

    local t = tokenize(s)
    local n = table.getn(t)
    local i = 0

    for i = 0,n do
        if t[i] == "bytes" then
            positions[0] = i
            break
        end
    end

    i = positions[0] + 1

    for i=i,n do
        if t[i] == "bytes" then
            positions[1] = i
            break
        end
    end

    if not positions[0] or not positions[1] then
        return false
    end

    s = f:read('*a')        -- read the whole file
    if not string.find(s, settings.device) then
        return false        -- the device does not exist
    end
    
    return true
end

--
-- start the timer
-- 
local function init_netmon_monitor()
    if sanity_check() then
        timer = statusd.create_timer()
        last[0], last[1] = parse_netmon_info()
        
        if settings.show_avg == 1 then
            for i=0,settings.avg_sec-1 do
                history_in[i], history_out[i] = 0, 0
            end
        end
        
        statusd.inform("netmon_template", "xxxxxxxxxxxxxxxxxxxxxxx")
        update_netmon_info()
    else
        statusd.inform("netmon", "oops")
        statusd.inform("netmon_hint", "critical")
    end
end

init_netmon_monitor()