1 -- filename : statusd_sysmon.lua
5 -- system monitor for Ion3 WM statusbar
6 -- Written by Vladimir Chizhov < jagoterr *at* gmail *dot* com >
7 -- I'll apreciate any comments, bug reports and feature requests :)
9 -- Shows memory, swap and filesystem statistics, based on 'free' and 'df' commands output.
10 -- Allows lua-expression evaluation with the values.
12 -- This script can work not only as a Ion3 statusd monitor, but also as a standalone script.
13 -- If it works as a Ion statusd monitor, it reads user settings from statusd.
15 if not statusd_sysmon
then
24 -- %% - percents symbol (%)
25 -- ${expression} - evaluates lua expression
26 -- Shortly about expressions:
27 -- - may contain all macroses (of format %macros_name or
28 -- %{macros_name macros_params*})
29 -- - may contain global function calls
30 -- - may contain arithmetic, logical operations etc.
31 -- - there is a global function 'dpr' defined in this script
32 -- for decreasing double numbers' precision (see this
33 -- function comments for more information and the example templates)
36 -- %mem_total - total available memory
37 -- %mem_used - used memory
38 -- %mem_free - free memory
39 -- %mem_buffers - buffered memory
40 -- %mem_cached - cached memory
41 -- %mem_shared - shared memory
44 -- %swap_total - total available swap space
45 -- %swap_used - used swap space
46 -- %swap_free - free swap space
49 -- %{fs_total mount_point} - total available space on filesystem
50 -- %{fs_used mount_point} - used space on filesystem
51 -- %{fs_free mount_point} - free space on filesystem
55 -- simple swap statistics
56 -- template = "swap used %swap_used of %swap_total"
58 -- used swap in percents with one sign after comma!
59 -- how? so... try to understand, I think it's not very hard, if you read the previous comments
60 -- template = "swap used by ${dpr (%swap_used / %swap_total * 100)}%%"
62 -- RAM used, excluding buffers and cached memory
63 -- template = "RAM used: ${%mem_used - %mem_buffers - %mem_cached}"
65 -- root filesystem simple info
66 -- note, that you should specify the actual mount point for filesystem, accordingly to /etc/mtab
67 -- template = "/ used by %{fs_used /} of %{fs_total /}"
71 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)} %%)",
73 -- DIMENSION for monitors
80 -- dimension for RAM and SWAP
83 -- dimension for filesystems
90 if statusd
~= nil then
91 settings
= table.join (statusd
.get_config ("sysmon"), statusd_sysmon
)
93 settings
= statusd_sysmon
105 -- --------------------------------------------------------------------------
106 -- Decreases the precision of the floating number
107 -- @param number the number to decrease it's precision
108 -- @param signs_q the quantity of signs after the comma to be left
109 function dpr (number, signs_q
)
110 local pattern
= "%d+"
111 if signs_q
== nil then
115 pattern
= pattern
.."%."
117 for i
= 1, tonumber (signs_q
) do
118 pattern
= pattern
.."%d"
120 return string.gsub (number, "("..pattern
..")(.*)", "%1")
123 -- --------------------------------------------------------------------------
124 -- Retrieves information from 'free' command output
125 local function parse_free_command ()
126 local f
= io
.popen ('free -'..settings
.mem_dimension
, 'r')
127 local s
= f
:read('*a')
138 = string.find(s
, 'Mem:%s*(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)')
143 = string.find(s
, 'Swap:%s*(%d+)%s+(%d+)%s+(%d+)')
146 -- --------------------------------------------------------------------------
147 -- Retrieves information from 'df' command output
148 local function parse_df_command ()
149 local factor
= factors
[settings
.fs_dimension
]
150 local f
= io
.popen ('df --block-size=1 -P', 'r')
151 -- local s = f:read ("*l")
152 for line
in f
:lines () do
153 local st
, en
, fs
, total
, used
, free
, mount_point
=
154 string.find (line
, '(%S+)%s+(%d+)%s+(%d+)%s+(%d+)%s+[%-%d]-%%?%s+(.*)')
156 metrics
["fs_total->"..mount_point
] = string.gsub (total
/ factor
, '(%d+%.%d%d)(.*)', "%1")
157 metrics
["fs_used->"..mount_point
] = string.gsub (used
/ factor
, '(%d+%.%d%d)(.*)', "%1")
158 metrics
["fs_free->"..mount_point
] = string.gsub (free
/ factor
, '(%d+%.%d%d)(.*)', "%1")
167 -- --------------------------------------------------------------------------
168 -- Main calculating of values, template parsing and Ion statusd updating
169 local function update_sysmon ()
170 local sysmon_st
= settings
.template
172 parse_free_command ()
176 -- filling the template by actual values
177 sysmon_st
= string.gsub (sysmon_st
, "%%%{([%w%_]+)%s+(%S-)%}", function (arg1
, arg2
)
178 return(metrics
[arg1
.."->"..arg2
] or "")
180 sysmon_st
= string.gsub (sysmon_st
, "%%([%w%_]+)", function (arg1
)
181 return (metrics
[arg1
] or "")
183 sysmon_st
= string.gsub (sysmon_st
, "%$%{(.-)%}", function (arg1
)
184 return loadstring("return "..arg1
)()
186 -- replacing the '%%' macros with the '%' symbol
187 sysmon_st
= string.gsub (sysmon_st
, "%%%%", "%%")
189 if statusd
~= nil then
190 statusd
.inform ("sysmon_template", sysmon_st
)
191 statusd
.inform ("sysmon", sysmon_st
)
192 sysmon_timer
:set (settings
.interval
, update_sysmon
)
194 io
.stdout
:write (sysmon_st
.."\n")
198 -- --------------------------------------------------------------------------
200 if statusd
~= nil then
201 sysmon_timer
= statusd
.create_timer ()