File: statusd_sysmon.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 (202 lines) | stat: -rw-r--r-- 6,927 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
195
196
197
198
199
200
201
202
-- filename :   statusd_sysmon.lua
-- version  :   2.0
-- date     :   2005-03-29
-- 
-- system monitor for Ion3 WM statusbar
-- Written by Vladimir Chizhov < jagoterr *at* gmail *dot* com >
-- I'll apreciate any comments, bug reports and feature requests :)
--
-- Shows memory, swap and filesystem statistics, based on 'free' and 'df' commands output.
-- Allows lua-expression evaluation with the values.
--
-- This script can work not only as a Ion3 statusd monitor, but also as a standalone script.
-- If it works as a Ion statusd monitor, it reads user settings from statusd.

local defaults = {
    -- UPDATE INTERVAL
    -- 
    interval=10*1000,
    
    -- TEMPLATE STRING
    -- 
    -- COMMON:
    -- %%               - percents symbol (%)
    -- ${expression}    - evaluates lua expression
    --                    Shortly about expressions:
    --                      - may contain all macroses (of format %macros_name or
    --                      %{macros_name macros_params*})
    --                      - may contain global function calls
    --                      - may contain arithmetic, logical operations etc.
    --                      - there is a global function 'dpr' defined in this script
    --                      for decreasing double numbers' precision (see this
    --                      function comments for more information and the example templates)
    -- 
    -- RAM:
    -- %mem_total       - total available memory
    -- %mem_used        - used memory
    -- %mem_free        - free memory
    -- %mem_buffers     - buffered memory
    -- %mem_cached      - cached memory
    -- %mem_shared      - shared memory
    -- 
    -- SWAP:
    -- %swap_total       - total available swap space
    -- %swap_used        - used swap space
    -- %swap_free        - free swap space
    -- 
    -- FS (FileSystem):
    -- %{fs_total       mount_point}    - total available space on filesystem
    -- %{fs_used        mount_point}    - used space on filesystem
    -- %{fs_free        mount_point}    - free space on filesystem
    -- 
    -- TEMPLATE EXAMPLES:
    --
    -- simple swap statistics
    -- template = "swap used %swap_used of %swap_total"
    --
    -- used swap in percents with one sign after comma!
    -- how? so... try to understand, I think it's not very hard, if you read the previous comments
    -- template = "swap used by ${dpr (%swap_used / %swap_total * 100)}%%"
    --
    -- RAM used, excluding buffers and cached memory
    -- template = "RAM used: ${%mem_used - %mem_buffers - %mem_cached}"
    --
    -- root filesystem simple info
    -- note, that you should specify the actual mount point for filesystem, accordingly to /etc/mtab
    -- template = "/ used by %{fs_used /} of %{fs_total /}"
    --
    -- DEFAULT TEMPLATE:
    --
    template = "RAM: %mem_used / %mem_total MB (${dpr (%mem_used / %mem_total * 100, 1)} %%) * SWAP: %swap_used / %swap_total MB (${dpr (%swap_used / %swap_total * 100, 1)} %%) * /: %{fs_used /} / %{fs_total /} (${dpr (%{fs_used /} / %{fs_total /} * 100, 1)} %%)",

    -- DIMENSION for monitors
    -- 
    -- b - bytes
    -- k - kilobytes
    -- m - megabytes
    -- g - gigabytes
    -- 
    -- dimension for RAM and SWAP
    -- 
    mem_dimension   = "m",
    -- dimension for filesystems
    --
    fs_dimension    = "g",
}

local settings
if statusd ~= nil then
    settings = table.join (statusd.get_config ("sysmon"), defaults)
else
    settings = defaults
end

local factors = {
    b = 1,
    k = 1024,
    m = 1024^2,
    g = 1024^3,
}

local metrics = {}

-- --------------------------------------------------------------------------
-- Decreases the precision of the floating number
-- @param number    the number to decrease it's precision
-- @param signs_q   the quantity of signs after the comma to be left
function dpr (number, signs_q)
    local pattern = "%d+"
    if signs_q == nil then
        signs_q = 2
    end
    if signs_q ~= 0 then
        pattern = pattern.."%."
    end
    for i = 1, tonumber (signs_q)  do
        pattern = pattern.."%d"
    end
    return string.gsub (number, "("..pattern..")(.*)", "%1")
end

-- --------------------------------------------------------------------------
-- Retrieves information from 'free' command output
local function parse_free_command ()
    local f = io.popen ('free -'..settings.mem_dimension, 'r')
    local s = f:read('*a')
    f:close()
    local st, en
    
    st, en,
    metrics.mem_total,
    metrics.mem_used,
    metrics.mem_free,
    metrics.mem_shared,
    metrics.mem_buffers,
    metrics.mem_cached
        = string.find(s, 'Mem:%s*(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)')
    st, en,
    metrics.swap_total,
    metrics.swap_used,
    metrics.swap_free
        = string.find(s, 'Swap:%s*(%d+)%s+(%d+)%s+(%d+)')
end

-- --------------------------------------------------------------------------
-- Retrieves information from 'df' command output
local function parse_df_command ()
    local factor = factors[settings.fs_dimension]
    local f = io.popen ('df --block-size=1 -P | tail +2', 'r')
    -- local s = f:read ("*l")
    for line in f:lines () do
        local st, en, fs, total, used, free, mount_point =
            string.find (line, '(%S+)%s+(%d+)%s+(%d+)%s+(%d+)%s+[%-%d]-%%?%s+(.*)')
        if fs ~= nil then
            metrics["fs_total->"..mount_point] = string.gsub (total / factor, '(%d+%.%d%d)(.*)', "%1")
            metrics["fs_used->"..mount_point] = string.gsub (used / factor, '(%d+%.%d%d)(.*)', "%1")
            metrics["fs_free->"..mount_point] = string.gsub (free / factor, '(%d+%.%d%d)(.*)', "%1")
        end
    end
    f:close ()

end

local sysmon_timer

-- --------------------------------------------------------------------------
-- Main calculating of values, template parsing and Ion statusd updating
local function update_sysmon ()
    local sysmon_st = settings.template
    
    parse_free_command ()

    parse_df_command ()
    
    -- filling the template by actual values
    sysmon_st = string.gsub (sysmon_st, "%%%{([%w%_]+)%s+(%S-)%}", function (arg1, arg2)
        return metrics[arg1.."->"..arg2]
    end)
    sysmon_st = string.gsub (sysmon_st, "%%([%w%_]+)", function (arg1)
        return metrics[arg1]
    end)
    sysmon_st = string.gsub (sysmon_st, "%$%{(.-)%}", function (arg1)
        return loadstring ("return "..arg1) ()
    end)
    -- replacing the '%%' macros with the '%' symbol
    sysmon_st = string.gsub (sysmon_st, "%%%%", "%%")

    if statusd ~= nil then
        statusd.inform ("sysmon_template", sysmon_st)
        statusd.inform ("sysmon", sysmon_st)
        sysmon_timer:set (settings.interval, update_sysmon)
    else
        io.stdout:write (sysmon_st.."\n")
    end
end

-- --------------------------------------------------------------------------
-- Init
if statusd ~= nil then
    sysmon_timer = statusd.create_timer ()
end
update_sysmon ()