使用 shell 脚本记录 - 捕获 STDERR 以使用时间戳进行记录

使用 shell 脚本记录 - 捕获 STDERR 以使用时间戳进行记录

解决了:

几个月前,我对登录 shell 脚本产生了兴趣。

第一个想法是手动记录功能,如下所示:

add2log() {
    printf "$(date)\tINFO\t%s\t%s\n" "$1" "$2" >>"$logPATH"
}

但我想自动化它,例如 STDERR 会自动记录。

已经有一段时间了,我找到了满意的答案,终于花时间分享了。


对于每个 shell 脚本,我现在使用一个“main.sh”来保存日志函数以及配置(设置日志和配置文件)。它看起来是这样的:

#!/bin/bash

###################################################################
# MY HEADERS
###################################################################


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~Global vars

mainScriptNAME=$(basename "$0")
mainScriptNAME="${mainScriptNAME%.*}"
mainScriptDIR=$(dirname "$0")
version="v0.0"
scriptsDIR="$mainScriptDIR/SCRIPTS"
addonsDIR="$mainScriptDIR/ADDONS"


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~LOGGER FUNCS

manualLogger() {

    # $1=PRIORITY $2=FUNCNAME $3=message
    printf "$(date)\t%s\t%s()\t%s\n" "$1" "$2" "$3" >>"$logFilePATH"
}

stdoutLogger() {

    # $1=message
    printf "$(date)\tSTDOUT\t%s\n" "$1" >>"$logFilePATH"
}

stderrLogger() {

    # $1=message
    printf "$(date)\tSTDERR\t%s\n" "$1" >>"$logFilePATH"
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~LOG & CONF

createLog() {
    # code to set and touch logFilePATH & confFilePATH
    manualLogger "INFO" "${FUNCNAME[0]}" "Log file created."
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~MAIN

#
createLog

#run scripts
{

    #
    source "$scriptsDIR/file1.sh"
    doSomthing1
    doSomthing2

    #
    source "$scriptsDIR/file2.sh"
    anotherFunction1
    anotherFunction2

    ...


} 2> >(while read -r line; do stderrLogger "$line"; done) \
1> >(while read -r line; do stdoutLogger "$line"; done) 


换句话说:

  • 我想要运行的所有脚本/函数都位于 ./SCRIPTS 文件夹中的单独文件中(所以我的 main.sh 几乎总是相同的)
  • 我将所有这些脚本放在一个组 { ... } 中以捕获它们的 STDOUT 和 STDERR
  • 它们的 STDOUT 和 STDERR 被重定向到各自的记录器函数

日志文件如下所示(一个手动记录器、一个 STDOUT 记录器、一个 STDERR 记录器的示例):

Lun 23 mai 2022 12:20:42 CEST   INFO    createLog() Log file created.
Lun 23 mai 2022 12:20:42 CEST   STDOUT  Some standard output
Lun 23 mai 2022 12:20:42 CEST   STDERR  ls: sadsdasd: No such file or directory

该小组将所有输出收集在日志中。相反,您显然可以根据需要对每个功能使用重定向2> >(while read ...和。1> >(while read ...例如doSomthing1它的 STDOUT 和 STDERR 将记录,但doSomthing2只有它的 STDERR 重定向。

答案1

从表面上看,您似乎只是添加了调试语句。这里的“重”是什么意思?在 Bash 脚本(或者更确切地说任何与此相关的编程语言)中,如果您需要回显某些内容,则需要有一个语句来告诉解释器echo您已传递的内容。

如果您希望在脚本(或任何代码段)中的某个点执行操作,则没有什么可以替代编写命令。

您可以使用 IO 重定向来实现各种技巧,但您必须有两个语句 - 一个在开始,一个在结束,才能实现您想要的效果。

如果您想要完整记录脚本,请参阅set -x。如果您只想记录脚本的某些函数,请set -x在 suhshell 中使用这些函数。

(set -x; func1)

答案2

我在专用目录中使用标志文件:

foo.bash:
  
#!/bin/bash
[[ -f $HOME/.local/debug/foo.debug ]] && \
  source $HOME/.local/debug/foo.debug
...

我可以在foo.debug文件中放入任何我喜欢的内容,包括类似debug_foofunction=1、 以及稍后的内容,foofoofunction可以使用debug_foofunction(小心 - 它可能未定义)来调用(或不调用)调试代码。
如果我简单地说rm $HOME/.local/debug/foo.debug,所有调试代码都会被关闭。如果我将其更改为,debug_foofunction=0我可以关闭foofunction调试,同时保留其他调试设置(例如debug_foootherfunction=1)。

阅读man bash有关“ trap”内置的内容。

真正的解决方案是不要编写复杂的脚本。使用适合您的问题集的编程语言。

始终将脚本粘贴到https://shellcheck.net语法检查器中,或shellcheck在本地安装。让使用成为shellcheck您开发过程的一部分。

相关内容