-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogging
More file actions
executable file
·192 lines (167 loc) · 6.86 KB
/
logging
File metadata and controls
executable file
·192 lines (167 loc) · 6.86 KB
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
#!/bin/bash
[[ ${__LOGS_LOADED__} -eq 1 ]] && return 0
export __LOGS_LOADED__=1
shopt -s extglob # required to consistently extract the verbosity from positional parameters
__JOB__="$(basename "$0" '.sh')"
_black_='\033[0;30m'
_red_='\033[0;31m'
_green_='\033[0;32m'
_yellow_='\033[0;33m'
_purple_='\033[0;35m'
_white_='\033[0;97m'
_cyan_='\033[0;36m'
_lgreen_='\033[0;92m'
_reset_='\033[0m'
function ecrit() { __verb__=1 elog "_purple_" "FATAL" "$*" ;}
function eerror() { __verb__=2 elog "_red_" "ERROR" "$*" ;}
function ewarn() { __verb__=2 elog "_yellow_" "WARN" "$*" ;}
function einfo() { __verb__=2 elog "_white_" "INFO" "$*" ;}
function edebug() { __verb__=3 elog "_green_" "DEBUG" "$*" ;}
function etrace() { __verb__=4 elog "_cyan_" "TRACE" "$*" ;}
## eprint outputs irrespective of verbosity
function eprint() { __verb__=0 elog "_lgreen_" "*" "$*" ;}
function edumpvar() { local -a a=(); for var in "$@"; do a+=("$var = '${!var}' "); done; etrace "${FUNCNAME[1]} :::: ${a[*]}"; }
function elog() {
# if ! [[ -v cccombo_breaker ]]; then
# local cccombo_breaker=1
# edebug "${FUNCNAME[2]} called ${FUNCNAME[1]} and __L_O__ is '${__LOG_OPEN__}' & __L_L__ is '${__LOG_LEVEL__}' & __v__ is '${__verb__}' FUNCNAME is '${#FUNCNAME[@]}' long"
# edumpvar __LOG_OPEN__ __LOG_LEVEL__ __verb__
# fi
if [[ ${FUNCNAME[1]} == "eprint" ]]; then
local fd=${__STOUTFD__}
else
local fd=${__STERRFD__}
fi
if [[ ${verbosity:-2} -ge ${__verb__} ]]; then
printf "${!1}%5s${_reset_} %s\n" "$2" "$3" >&$fd
fi
if [[ -n ${__LOG_OPEN__} && ${__LOG_LEVEL__} -ge ${__verb__} ]]; then
printf "%(%Y-%m-%d %H:%M:%S)T ${!1}%5s${_reset_} %s\n" -1 "$2" "$3" >>"${__LOG__}"
fi
}
function dlog() {
if [[ -n ${__LOG_OPEN__} ]]; then
if [[ -n ${__LOG_STOUT__} ]]; then
dd if="${__STOUT_PIPE__}" iflag=nonblock status=none 2>/dev/null
fi
printf "%(%Y-%m-%d %H:%M:%S)T ${!1}%-7s${_reset_}%b\n" -1 "$2" "$3" >>"${__LOG__}"
else
edebug "Failed to write '$3' to file because the Log File is Closed."
fi
}
function __init_messages__() {
exec {__STOUTFD__}>&1
exec {__STERRFD__}>&2
extract_verbosity "$@"
trap __end_messages__ EXIT
}
extract_verbosity() {
local arg
local -i next_positional=2
local rtn=0
for arg in "$@"; do
case $arg in
-!(-)*v|--verb)
if [[ -n ${!next_positional} && ${!next_positional} =~ ^[0-4]$ ]]; then
export verbosity=${!next_positional}
rtn=2
break
fi
;;
-!(-)*v[0-4]|--verb=[0-4])
export verbosity=${arg: -1}
rtn=1
break
;;
esac
(( next_positional++))
done
return $rtn
}
function __open_logfile__() {
edumpvar __LOG_OPEN__ __LOGPATH__
if [[ -z ${__LOG_OPEN__} ]]; then
if [[ -d ${__LOGPATH__} ]]; then
__LOG__="${__LOGPATH__}/LOG_${__JOB__}.txt"
if ! [[ -e ${__LOG__} ]]; then
local user=$(awk -F':' -v uid=$EUID '$3 == uid {print $1}' /etc/passwd)
install -o "$user" -g "$user" -m 660 /dev/null "${__LOG__}"
fi
exec {__LOGFD__}>>"${__LOG__}" # only used to keep the file open...
__LOG_OPEN__=1
dlog "_white_" "LOGS" "SESSION OPENED"
if [[ -n ${__LOG_STOUT__} ]]; then
local user=$(awk -F':' -v uid=$EUID '$3 == uid {print $1}' /etc/passwd)
install -o "$user" -g "$user" -m 700 -d "/run/${__JOB__}/$$"
__SO_PIPE_PATH__="/run/${__JOB__}/$$"
__STOUT_PIPE__="${__SO_PIPE_PATH__}/somessages.pipe"
mkfifo -m 700 "${__STOUT_PIPE__}"
exec {__SO_PIPE_FD__}<>"${__STOUT_PIPE__}"
sed -u 's/^/ /' "${__STOUT_PIPE__}" > >(tee -a "${__LOG__}" >&"${__STOUTFD__}") &
__SED_SO_PID__=$!
exec 1>>"${__STOUT_PIPE__}"
etrace "${FUNCNAME[0]} inherited stout from __init_messages__ on FD: '${__STOUTFD__}'"
etrace "Pipe initialized on FD: '${__SO_PIPE_FD__}' pointing to '${__STOUT_PIPE__}'"
etrace "Sed filtering '${__STOUT_PIPE__}' on PID: '${__SED_SO_PID__}.' Appending output to: '${__LOG__}' and FD: '${__STOUTFD__}'"
edumpvar user __STOUT_PIPE__ __SO_PIPE_FD__ __SED_SO_PID__
fi
if [[ -n ${__LOG_STERR__} ]]; then
local user=$(awk -F':' -v uid=$EUID '$3 == uid {print $1}' /etc/passwd)
install -o "$user" -g "$user" -m 700 -d "/run/${__JOB__}/$$"
__SE_PIPE_PATH__="/run/${__JOB__}/$$"
__STERR_PIPE__="${__SE_PIPE_PATH__}/semessages.pipe"
mkfifo -m 700 "${__STERR_PIPE__}"
exec {__SE_PIPE_FD__}<>"${__STERR_PIPE__}"
sed -u -r -e "s/^/ \x1b\[0;31m/" -e "s/$/\x1b\[0m/" "${__STERR_PIPE__}" > >(tee -a "${__LOG__}" >&"${__STERRFD__}") &
__SED_SE_PID__=$!
exec 2>>"${__STERR_PIPE__}"
etrace "${FUNCNAME[0]} inherited sterr from __init_messages__ on FD: '${__STERRFD__}'"
etrace "Pipe initialized on FD: '${__SE_PIPE_FD__}' pointing to '${__STERR_PIPE__}'"
etrace "Sed filtering '${__STERR_PIPE__}' on PID: '${__SED_SE_PID__}.' Appending output to: '${__LOG__}' and FD: '${__STERRFD__}'"
edumpvar user __STERR_PIPE__ __SE_PIPE_FD__ __SED_SE_PID__
fi
if [[ ${__LOG_LEVEL__} -ge 4 || ${verbosity} -ge 4 ]]; then
ls -Alh /proc/$$/fd | awk '{ print $(NF-2), $(NF-1), $NF}' | tail -n +2 >&2 # "${__STOUT_PIPE__}"
fi
trap __end_messages__ EXIT
edebug "Logging to '${__LOG__}'"
edumpvar __LOG_OPEN__ __LOGPATH__ __LOG__
edumpvar __LOG_STOUT__ __LOGFD__ __STOUTFD__ __STERRFD__
else
ewarn "__LOGPATH__ is not a directory. Logging disabled."
return 1
fi
else
edebug "Log File: '${__LOG__}' already open."
return 1
fi
}
function __end_messages__() {
[[ -n "${__LOG_OPEN__}" ]] && dlog "_white_" "LOGS" "SESSION CLOSED\n" && unset __LOG_OPEN__
[[ -v __LOGFD__ ]] && exec {__LOGFD__}>&-
exec 1>&${__STOUTFD__}-
exec 2>&${__STERRFD__}-
if [[ -n ${__LOG_STOUT__} ]]; then
kill ${__SED_SO_PID__}
exec {__SO_PIPE_FD__}>&-
rm -r "${__SO_PIPE_PATH__}"
unset __LOG_STOUT__
fi
if [[ -n ${__LOG_STERR__} ]]; then
kill ${__SED_SE_PID__}
exec {__SE_PIPE_FD__}>&-
[[ -d ${__SE_PIPE_PATH__} ]] && rm -r "${__SE_PIPE_PATH__}"
unset __LOG_STERR__
fi
unset __LOG_OPEN__ __STOUTFD__ __STERRFD__ __LOG__ __LOGPATH__ __LOGFD__ __SED_SO_PID__ __SO_PIPE_PATH__ __SE_PIPE_PATH__ __SED_SE_PID__
trap - EXIT
}
# relevant information... i think?
# https://unix.stackexchange.com/questions/522877/how-to-cat-named-pipe-without-waiting/522881#522881 # see GNU dd's remark for info
# https://technotes.adelerhof.eu/bash/logging/ # rough template of this library
# https://stackoverflow.com/questions/6834347/named-pipe-closing-prematurely-in-script
# https://stackoverflow.com/questions/5376489/how-do-i-use-exec-3myfifo-in-a-script-and-not-have-echo-foo3-close-the-pipe
# https://stackoverflow.com/questions/2776994/tee-a-pipe-asynchronously
# https://catonmat.net/bash-one-liners-explained-part-three - SEE ITEM 13??
# https://github.com/miguelmota/bash-streams-handbook#send-commands-to-terminal-through-a-named-pipe
# https://github.com/codeforester/base/blob/master/lib/stdlib.sh