我正在开发一个“包装脚本”,用作Bash中的“日志记录辅助工具”。
它应该在调用时打印出有关调用堆栈的信息。
我已经完成了它的工作,接下来,但仍有一些问题/疑问,我想从这里的专家那里得到最好的答案。
################################################################################
# Formats a logging message.
function my_function_format_logging_message() {
local -r TIMESTAMP="$(date '+%H:%M:%S')"
local -r PROCESS="$$" # Deliberately not using $BASHPID, focus: parent process
local -r CALLER="${FUNCNAME[1]}"
local -i call_stack_position=1
if [[ "${CALLER}" == 'my_function_log_trace' ||
"${CALLER}" == 'my_function_log_debug' ||
"${CALLER}" == 'my_function_log_info' ||
"${CALLER}" == 'my_function_log_warning' ||
"${CALLER}" == 'my_function_log_error' ||
"${CALLER}" == 'my_function_log_critical' ]]
then
call_stack_position=$((call_stack_position++))
fi
local -r SOURCE="$(basename "${BASH_SOURCE[$call_stack_position]}")"
local -r FUNCTION="${FUNCNAME[$call_stack_position]}"
local -r LINE="${BASH_LINENO[$call_stack_position-1]}" # Previous function
local -r SEVERITY="$1"
local -r MESSAGE="$2"
# TODO: perform argument validation
printf '%s [PID %s] %s %s %s:%s - %s\n' \
"${TIMESTAMP}" \
"${PROCESS}" \
"${SEVERITY}" \
"${SOURCE}" \
"${FUNCTION}" \
"${LINE}" \
"${MESSAGE}"
}
################################################################################
my_function_format_logging_message CRITICAL Temporarily increasing energy level to 9001
或:
my_function_log_info Dropping back to power level 42
我想不出更好的方法来增加这个变量,是否有更好/更易读的形式?
我可以使用更好的构造来检测调用是否是由记录方法进行的吗? (例如trace,debug,info ..)。所有这些if
陈述都让我的眼睛受伤了。
我是否重新发明轮子/滥用我想学习的工具? (即shell脚本)
我当然可能正在重新发明轮子,但这是自我训练..有一天我不再是一个收费站的夜班工人了。
我正在寻找与指定的my_function_log_ *名称和没有其他人的匹配项。假设我有这种自由度是不行的(许多if
就是出于这个原因,我正在寻找一些语法糖或更好地使用语言功能来做那种“集合成员”检验)。
答案 0 :(得分:2)
我可以为你的前两个问题提出建议:
if [[ "${CALLER}" == my_function_log_* ]]
then
let call_stack_position++
fi
如果您只想在log _:
之后获得一组值if [[ "${CALLER}" =~ my_function_log_(trace|debug|info|warning|error|critical) ]]
then
let call_stack_position++
fi
答案 1 :(得分:1)
更可读的增量方法是在数字上下文中递增它:
(( call_stack_position++ ))
对于匹配,你可以在bash中使用glob:
[[ $CALLER == my_function_log_* ]]
就重新发明轮子而言,您可以使用logger
命令从bash使用syslog日志记录。本地syslog守护程序将处理格式化日志消息并将其写入文件。
logger -p local0.info "CRITICAL Temporarily increasing energy level to 9001"
根据评论更新。您可以使用关联数组更明确地了解您要查找的内容。它需要bash v4或更高版本。
declare -A arr=(
['my_function_log_trace']=1
['my_function_log_debug']=1
['my_function_log_info']=1
['my_function_log_warning']=1
['my_function_log_error']=1
['my_function_log_critical']=1
);
if [[ ${arr[CALLER]} ]]; then
...
fi
您还可以使用扩展globbing进行模式匹配,类似于perreal的答案中的正则表达式,但没有正则表达式:
shopt -s extglob
if [[ $CALLER == my_function_log_@(trace|debug|info|warning|error|critical) ]]; then
...
fi
答案 2 :(得分:1)
Bash的类型系统,如果你甚至想要调用它,那么它是非常基本的:字符串和整数是它唯一的一等公民,数组是事后补充的,它的功能远不及Python集或Ruby数组。话虽如此,对于依赖于字符串匹配的数组,有一个穷人的in
运算符。给定一系列函数名称:
log_functions=(my_function_log_trace my_function_log_debug my_function_log_info my_function_log_warning my_function_log_error my_function_log_critical)
这样:
[[ ${log_functions[*]} =~ \\b$CALLER\\b ]]
将仅匹配数组的成员。当我们谈论穷人的构造时,你可以将上面的模式与布尔控制算子结合成一个穷人的三元分配,完全跳过数值评估:
local -i call_stack_position=$([[ ${log_functions[*]} =~ \\b$CALLER\\b ]] && echo 1 || echo 2)
在systems that do not support the GNU extensions to regcomp()
(notably OS X and Cygwin)上的警告:,字边界匹配需要使用更冗长的字符类形式,即
[[ ${log_functions[*]} =~ [[:\<:]]$CALLER[[:\>:]] ]]
注意:看到你的代码并注意到你提到你正在学习shell脚本,我提供两个与正确问题无关的观察结果:
printf
命令中都不需要它。basename
,而是使用${var##*/}
。