bin/khatus_parse_upower
define BUILD_AWK_EXE
- echo '#! $(PATH_TO_AWK) -f' > $@ && \
- echo 'BEGIN {Module = "$(notdir $@)"}' >> $@ && \
- cat $^ >> $@ && \
+ echo '#! $(PATH_TO_AWK) -f' > $@ && \
+ echo 'BEGIN {Node = Node ? Node : "$(shell hostname)"}' >> $@ && \
+ echo 'BEGIN {Module = "$(notdir $@)"}' >> $@ && \
+ cat $^ >> $@ && \
chmod +x $@
endef
bin/khatus_bar: \
src/awk/exe/bar.awk \
src/awk/lib/cache.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk \
src/awk/lib/msg_out.awk \
- src/awk/lib/util.awk
+ src/awk/lib/num.awk
$(BUILD_AWK_EXE)
bin/khatus_actuate_alert_to_notify_send: \
src/awk/exe/actuate_alert_to_notify_send.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk
$(BUILD_AWK_EXE)
bin/khatus_actuate_device_add_to_automount: \
src/awk/exe/actuate_device_add_to_automount.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk \
src/awk/lib/msg_out.awk
$(BUILD_AWK_EXE)
bin/khatus_actuate_status_bar_to_xsetroot_name: \
src/awk/exe/actuate_status_bar_to_xsetroot_name.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk
$(BUILD_AWK_EXE)
bin/khatus_monitor_devices: \
src/awk/exe/monitor_devices.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk \
src/awk/lib/msg_out.awk
$(BUILD_AWK_EXE)
bin/khatus_monitor_energy: \
src/awk/exe/monitor_energy.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk \
src/awk/lib/msg_out.awk \
- src/awk/lib/util.awk
+ src/awk/lib/num.awk
$(BUILD_AWK_EXE)
bin/khatus_monitor_errors: \
src/awk/exe/monitor_errors.awk \
+ src/awk/lib/str.awk \
src/awk/lib/msg_in.awk \
src/awk/lib/msg_out.awk
$(BUILD_AWK_EXE)
bin/khatus_parse_metar_d_output: \
src/awk/exe/parse_metar_d_output.awk \
src/awk/lib/msg_out.awk \
- src/awk/lib/util.awk
+ src/awk/lib/str.awk
$(BUILD_AWK_EXE)
bin/khatus_parse_mpd_status_currentsong: \
- report history and trends on when and how-often each
device/category is plugged-in, how-long it stays plaugged-in, etc.
- daemonize `khatus`, so we don't have to re-launch `X11` to re-launch `khatus`
-- interoperate with other khatus instances
+- interoperate with other khatus nodes
- prefix machine ID to each data source
(What should that ID be? Hostname? Pub key?)
- fetch remote data and process locally
2> >(
while read line
do
- echo "ERROR${MSG_FS}${executable_name}${MSG_FS}$line" > "$pipe"
+ echo "${NODE}${MSG_FS}${executable_name}${MSG_FS}error${MSG_FS}$line" > "$pipe"
done \
) \
| while read line
do
- echo "OK${MSG_FS}${executable_name}${MSG_FS}$line" > "$pipe"
+ echo "${NODE}${MSG_FS}${executable_name}${MSG_FS}data${MSG_FS}$line" > "$pipe"
done
cmd_exit_code=${PIPESTATUS[0]}
if [ "$cmd_exit_code" -ne 0 ]
then
echo
- "ERROR${MSG_FS}${executable_name}${MSG_FS}NON_ZERO_EXIT_CODE${MSG_FS}$cmd_exit_code" \
+ "${NODE}${MSG_FS}${executable_name}${MSG_FS}error${MSG_FS}NON_ZERO_EXIT_CODE${MSG_FS}$cmd_exit_code" \
> "$pipe"
fi
}
main() {
declare -A opts=(
+ ["--node"]=$(hostname)
["--dir_bin"]="$HOME/bin"
["--dir_perf_logs"]=''
["--file_pipe"]=$(mktemp)
echo '----------------------------------------------'
) >&2
+ NODE="${opts['--node']}"
+
screen_brightness_device_path='/sys/class/backlight'
screen_brightness_device_path+="/${opts['--screen_brightness_device_name']}"
Display = Display ? Display : ":0"
}
-$1 == "OK" && \
-$3 ~ /^alert/ {
- src = $2
- key = $3
- split(key, key_parts, Kfs)
- priority = key_parts[2]
- subject = key_parts[3]
- # Not just using $6 for body - because body might contain a character
- # identical to FS
- len_line = length($0)
- len_head = length($1 FS $2 FS $3 FS $4 FS $5 FS)
- len_body = len_line - len_head
- body = substr($0, len_head + 1, len_body)
+$3 == "alert" {
+ delete msg
+ msg_in_parse(msg, $0)
+ body = msg["body"]
sep = body ? "\n" : ""
- body = body sep "--" src
- urgency = priority
+ body = body sep "--" msg["node"] ":" msg["module"]
+ urgency = msg["priority"]
sub("hi" , "critical", urgency)
sub("med", "normal" , urgency)
cmd = \
sprintf(\
"DISPLAY=%s notify-send -u %s %s \" %s\"",
- Display, urgency, subject, body \
+ Display, urgency, msg["subject"], body \
)
system(cmd)
next
Execute_On_Mount = Execute_On_Mount ? Execute_On_Mount : ""
}
-$1 == "OK" && \
+$1 == Node && \
$2 == "khatus_sensor_devices" && \
-$3 == "add" && \
-$4 ~ /[0-9]$/ {
- mount_device($4)
+$3 == "data" && \
+$4 == "add" && \
+$5 ~ /[0-9]$/ {
+ mount_device($5)
}
function mount_device(path, cmd, line, lines, line_count, status, i,
path_mnt=line
sub("^Mounted " path_dev " at ", "", path_mnt)
sub("\.$", "", path_mnt)
- msg_out_ok_alert("low", "successfully-mounted", path_dev " to " path_mnt)
+ msg_out_alert_low("successfully-mounted", path_dev " to " path_mnt)
if (Execute_On_Mount) {
system(Execute_On_Mount " '" path_mnt "'")
}
} else {
- msg_out_ok_alert("hi", "unexpected-success-line", line)
+ msg_out_alert_hi("unexpected-success-line", line)
}
}
} else {
- msg_out_ok_alert("hi", "failed-to-mount-device", path)
+ msg_out_alert_hi("failed-to-mount-device", path)
}
}
-$1 == "OK" && \
+$1 == Node && \
$2 == "khatus_bar" && \
$3 == "status_bar" {
- # Not just using $4 for val - because val might contain a character
- # identical to FS
- len_line = length($0)
- len_head = length($1 FS $2 FS $3 FS)
- len_val = len_line - len_head
- val = substr($0, len_head + 1, len_val)
- system("xsetroot -name \"" val "\"")
+ delete msg
+ msg_in_parse(msg, $0)
+ system("xsetroot -name \"" msg["status_bar"] "\"")
next
}
# -----------------------------------------------------------------------------
# Input
# -----------------------------------------------------------------------------
-$1 == "OK" {
- cache_update()
+$3 == "data" {
+ delete msg
+ msg_in_parse(msg, $0)
+ cache_update(msg["node"], msg["module"], msg["key"], msg["val"])
}
-$1 == "OK" && \
-$2 == "khatus_sensor_datetime" {
+$1 == Node && \
+$2 == "khatus_sensor_datetime" && \
+$3 == "data" {
# Code for bar_make_status is expected to be passed as an
# additional source file, using -f flag.
- msg_out_ok("status_bar", bar_make_status())
+ msg_out_status_bar(bar_make_status())
}
-
# -----------------------------------------------------------------------------
# Energy
# -----------------------------------------------------------------------------
!used["is_expired"] && \
total["value"] \
) {
- percent = util_round((used["value"] / total["value"]) * 100)
+ percent = num_round((used["value"] / total["value"]) * 100)
percent_str = sprintf("%d", percent)
} else {
percent_str = "__"
if (mu["value"] == "yes") {show = "X"}
else if (mu["value"] == "no") {show = vl["value"] " " vr["value"]}
else {
- msg_out_error(\
+ msg_out_log_error(\
"bar_make_status_volume_pulseaudio_sink: " sink ". ", \
"Unexpected value for 'mute' field: " mu["value"] \
)
} else if (state["value"] == "stop") {
status = bar_make_status_mpd_state_known("⬛")
} else {
- msg_out_error(\
+ msg_out_log_error(\
"bar_make_status_mpd", \
"Unexpected value for 'state' field: " state["value"] \
)
-$1 == "OK" && \
-$2 == "khatus_sensor_devices" \
+$2 == "khatus_sensor_devices" && \
+$3 == "data" \
{
- msg_out_ok_alert("low", "BlockDeviceEvent", $3 " " $4)
+ delete msg
+ msg_in_parse(msg, $0)
+ msg_out_alert_low( \
+ "BlockDeviceEvent",
+ msg["key"] " " msg["val"] " on " msg["node"]\
+ )
}
bat_alert_spec[5] = "hi|Energy_CRITICALLY_Low|CHARGE NOW!!! GO GO GO!!!"
}
-$1 == "OK" && \
+$1 == Node && \
$2 == "khatus_sensor_energy" && \
-$3 == "line_power" {
+$3 == "data" && \
+$4 == "line_power" {
line_power_prev = line_power_curr
- line_power_curr = $4
+ line_power_curr = $5
if (line_power_curr == "no" && line_power_prev != "no") {
- msg_out_ok_alert("low", "PowerUnplugged", "")
+ msg_out_alert_low("PowerUnplugged", "")
}
}
-$1 == "OK" && \
+$1 == Node && \
$2 == "khatus_sensor_energy" && \
-$3 == "battery_state" {
+$3 == "data" && \
+$4 == "battery_state" {
battery_state_prev = battery_state_curr
- battery_state_curr = $4
+ battery_state_curr = $5
}
-$1 == "OK" && \
+$1 == Node && \
$2 == "khatus_sensor_energy" && \
-$3 == "battery_percentage" {
+$3 == "data" && \
+$4 == "battery_percentage" {
# TODO: Re-think the spec - can't rely on order of keys
- battery_percentage = util_ensure_numeric($4)
+ battery_percentage = num_ensure_numeric($5)
if (battery_state_curr == "discharging") {
for (threshold in bat_alert_spec) {
- threshold = util_ensure_numeric(threshold)
+ threshold = num_ensure_numeric(threshold)
if (battery_percentage <= threshold && !_alerted[threshold]) {
- split(bat_alert_spec[threshold], msg, "|")
- priority = msg[1]
- subject = msg[2]
- body = sprintf("%d%% %s", battery_percentage, msg[3])
- msg_out_ok_alert(priority, subject, body)
+ split(bat_alert_spec[threshold], alert, "|")
+ priority = alert[1]
+ subject = alert[2]
+ body = sprintf("%d%% %s", battery_percentage, alert[3])
+ msg_out_alert(priority, subject, body)
_alerted[threshold]++
}
}
-/^ERROR/ {
- src = $2
- # Not just using $3 for body - because body might contain a character
- # identical to FS
- len_line = length($0)
- len_head = length($1 FS $2 FS)
- len_body = len_line - len_head
- body = substr($0, len_head + 1, len_body)
- msg_out_ok_alert("hi", "ERROR_IN_" src, body)
+$3 == "error" {
+ delete msg
+ msg_in_parse(msg, $0)
+ subject = "ERROR_IN_" msg["node"] ":" msg["module"]
+ msg_out_alert_hi(subject, msg["line"])
}
/[A-z][a-z]+ *: / {
split($0, line, ":")
- key = util_strip(line[1])
- val = util_strip(line[2])
+ key = str_strip(line[1])
+ val = str_strip(line[2])
values[NR] = val
first[key] = NR
last[key] = NR
}
/^ +/ {
- values[NR] = util_strip($0)
+ values[NR] = str_strip($0)
last[key] = NR
}
_scale["khatus_sensor_net_addr_io", "bytes_read" ] = 1 / _bytes_per_mb
}
-function cache_update( src, key, val, len_line, len_head, len_val, time) {
- src = $2
- key = $3
- # Not just using $4 for val - because an unstructured value (like name of a
- # song) might contain a character identical to FS
- len_line = length($0)
- len_head = length($1 FS $2 FS $3 FS)
- len_val = len_line - len_head
- val = substr($0, len_head + 1, len_val)
- val = cache_maybe_total_to_diff(src, key, val)
- val = cache_maybe_scale(src, key, val)
- _cache[src, key] = val
+function cache_update(node, module, key, val, time) {
+ # TODO: Use node value
+ val = cache_maybe_total_to_diff(module, key, val)
+ val = cache_maybe_scale(module, key, val)
+ _cache[module, key] = val
time = cache_get_time()
- _cache_mtime[src, key] = time
+ _cache_mtime[module, key] = time
if (time % GC_Interval == 0) {
cache_gc()
}
}
-function cache_get(result, src, key, ttl, time, age, is_expired) {
+function cache_get(result, module, key, ttl, time, age, is_expired) {
time = cache_get_time()
- _cache_atime[src, key] = time
- age = time - _cache_mtime[src, key]
+ _cache_atime[module, key] = time
+ age = time - _cache_mtime[module, key]
result["is_expired"] = ttl && age > ttl # ttl = 0 => forever
- result["value"] = _cache[src, key]
+ result["value"] = _cache[module, key]
}
function cache_res_fmt_or_def(result, format, default) {
return result["is_expired"] ? default : sprintf(format, result["value"])
}
-function cache_get_fmt_def(src, key, ttl, format, default, result) {
+function cache_get_fmt_def(module, key, ttl, format, default, result) {
default = default ? default : "--"
- cache_get(result, src, key, ttl)
+ cache_get(result, module, key, ttl)
return cache_res_fmt_or_def(result, format, default)
}
-function cache_get_time( src, key, time) {
- src = "khatus_sensor_datetime"
+function cache_get_time( module, key, time) {
+ module = "khatus_sensor_datetime"
key = "epoch"
- time = _cache[src, key]
- _cache_atime[src, key] = time
+ time = _cache[module, key]
+ _cache_atime[module, key] = time
return time
}
-function cache_gc( src_and_key, parts, src, key, unused_for) {
- for (src_and_key in _cache) {
- split(src_and_key, parts, SUBSEP)
- src = parts[1]
+function cache_gc( module_and_key, parts, module, key, unused_for) {
+ for (module_and_key in _cache) {
+ split(module_and_key, parts, SUBSEP)
+ module = parts[1]
key = parts[2]
- val = _cache[src, key]
- unused_for = cache_get_time() - _cache_atime[src, key]
+ val = _cache[module, key]
+ unused_for = cache_get_time() - _cache_atime[module, key]
if (unused_for > GC_Interval) {
- msg_out_info(\
+ msg_out_log_info(\
"cache_gc",
sprintf(\
- "Deleting unused data SRC=%s KEY=%s VAL=%s",
- src, key, val\
+ "Deleting unused data MODULE=%s KEY=%s VAL=%s",
+ module, key, val\
) \
)
- delete _cache[src, key]
+ delete _cache[module, key]
}
}
}
-function cache_maybe_total_to_diff(src, key, val, key_parts) {
+function cache_maybe_total_to_diff(module, key, val, key_parts) {
split(key, key_parts, Kfs)
- if (_total_to_diff[src, key_parts[1]]) {
- _prev[src, key] = _curr[src, key]
- _curr[src, key] = val
- return (_curr[src, key] - _prev[src, key])
+ if (_total_to_diff[module, key_parts[1]]) {
+ _prev[module, key] = _curr[module, key]
+ _curr[module, key] = val
+ return (_curr[module, key] - _prev[module, key])
} else {
return val
}
}
-function cache_maybe_scale(src, key, val, key_parts) {
+function cache_maybe_scale(module, key, val, key_parts) {
split(key, key_parts, Kfs)
- if ((src SUBSEP key_parts[1]) in _scale) {
- return val * _scale[src, key_parts[1]]
+ if ((module SUBSEP key_parts[1]) in _scale) {
+ return val * _scale[module, key_parts[1]]
} else {
return val
}
BEGIN {
- FS = Msg_fs ? Msg_fs : "|"
- Kfs = Key_fs ? Key_fs : ":"
+ FS1 = "|" # Fiels separator, level 1 (record to fields)
+ FS2 = ":" # Fiels separator, level 2 (field to subfields)
+
+ FS = FS1
+ Kfs = FS2
+}
+
+function msg_in_parse(msg, line, fields, type) {
+ split(line, fields, FS1)
+ msg["node"] = fields[1]
+ msg["module"] = fields[2]
+ type = fields[3]
+ msg["type"] = type
+
+ if (type == "data") {
+ msg["key"] = fields[4]
+ msg["val"] = str_tail(str_join(fields, 1, 4, FS1) FS1, line)
+ } else if (type == "error") {
+ msg["line"] = str_tail(str_join(fields, 1, 3, FS1) FS1, line)
+ } else if (type == "alert") {
+ msg["priority"] = fields[4]
+ msg["subject"] = fields[5]
+ msg["body"] = str_tail(str_join(fields, 1, 5, FS1) FS1, line)
+ } else if (type == "log") {
+ msg["location"] = fields[4]
+ msg["level"] = fields[5]
+ msg["msg"] = str_tail(str_join(fields, 1, 5, FS1) FS1, line)
+ } else if (type == "status_bar") {
+ msg["status_bar"] = str_tail(str_join(fields, 1, 3, FS1) FS1, line)
+ } else {
+ msg_out_log_error(\
+ "msg_in_parse",
+ "Unexpected msg type: " type " in given input line: " line \
+ )
+ exit 1
+ }
}
BEGIN {
- OFS = Msg_fs ? Msg_fs : "|"
- Kfs = Key_fs ? Key_fs : ":"
+ FS1 = "|" # Fiels separator, level 1 (record to fields)
+ FS2 = ":" # Fiels separator, level 2 (field to subfields
+
+ OFS = FS1
+ Kfs = FS2
+}
+
+# -----------------------------------------------------------------------------
+# alert
+# -----------------------------------------------------------------------------
+function msg_out_alert_low(subject, body) {
+ msg_out_alert("low", subject, body)
+}
+
+function msg_out_alert_med(subject, body) {
+ msg_out_alert("med", subject, body)
}
-function msg_out_ok_alert(priority, subject, body, key, val) {
+function msg_out_alert_hi(subject, body) {
+ msg_out_alert("hi", subject, body)
+}
+
+function msg_out_alert(priority, subject, body) {
# priority : "low" | "med" | "hi"
# subject : string without spaces
# body : anything
- key = "alert" Kfs priority Kfs subject
- val = body
- msg_out_ok(key, val)
+ print(Node, Module, "alert", priority, subject, body)
+}
+
+# -----------------------------------------------------------------------------
+# log
+# -----------------------------------------------------------------------------
+function msg_out_log_info(location, msg) {
+ msg_out_log("info", location, msg)
}
-function msg_out_ok(key, val) {
- msg_out("OK", key, val, "/dev/stdout")
+function msg_out_log_error(location, msg) {
+ msg_out_log("error", location, msg)
}
-function msg_out_info(location, msg) {
- msg_out("INFO", location, msg, "/dev/stderr")
+function msg_out_log(level, location, msg) {
+ print(Node, Module, "log", location, level, msg) > "/dev/stderr"
}
-function msg_out_error(location, msg) {
- msg_out("ERROR", location, msg, "/dev/stderr")
+# -----------------------------------------------------------------------------
+# status_bar
+# -----------------------------------------------------------------------------
+function msg_out_status_bar(bar) {
+ print(Node, Module, "status_bar", bar)
}
-function msg_out(status, key, val, channel) {
- print(status, Module, key, val) > channel
+# -----------------------------------------------------------------------------
+# data
+# -----------------------------------------------------------------------------
+function msg_out_data(key, val) {
+ print(Node, Module, "data", key, val)
}
-function util_strip(s) {
- sub("^ *", "", s)
- sub(" *$", "", s)
- return s
-}
-
-function util_round(n) {
+function num_round(n) {
return int(n + 0.5)
}
-function util_ensure_numeric(n) {
+function num_ensure_numeric(n) {
return n + 0
}
-#------------------------------------
-# Why do we need util_ensure_numeric?
-#------------------------------------
+#-----------------------------------
+# Why do we need num_ensure_numeric?
+#-----------------------------------
# awk appears to be guessing the type of an inputted scalar based on usage, so
# if we read-in a number, but did not use it in any numeric operations, but did
# use as a string (even in just a format string!) - it will be treated as a
--- /dev/null
+function str_join(array, from, to, sep_given, str, sep, i) {
+ str = ""
+ sep = ""
+ for (i=from; i<=to; i++) {
+ str = str sep array[i]
+ sep = sep_given
+ }
+ return str
+}
+
+function str_tail(head, full, tail, len_tail, len_head, len_full) {
+ len_full = length(full)
+ len_head = length(head)
+ len_tail = len_full - len_head
+ tail = substr(full, len_head + 1, len_tail)
+ return tail
+}
+
+function str_strip(s) {
+ sub("^ *", "", s)
+ sub(" *$", "", s)
+ return s
+}