记录脚本输出有哪些指导原则?

时间:2016-12-14 00:08:15

标签: linux bash logging

是否有一些写剧本的权限?是否不鼓励使用大型/长型bash脚本,这种方式不需要进行日志记录?

我尝试了几种不同的方法来记录脚本输出,但是在决定它们时需要引用一些东西:

  1. Echo / printf一些行到控制台供用户读取,“手动”将更完整的信息写入日志文件(通过调用“log”函数添加时间戳并写入文件)。使用其他功能检查命令的退出代码。
  2. 将命令输出到日志函数,该函数从标准输入读取,然后将其写入文件(带有时间戳),最后将组合输出回送回控制台。
  3.   

    示例1:

    log_file='test.log'
    log () {
      # Writes a message to the log with a full timestamp and log level, "INFO" if not specified.
      # Requires a global variable, "$log_file"
      # Example: log 'Something happened'
      #      or: log 'Bad stuff happened' 'WARNING'
      local log_msg="$1"
      local log_lvl="$2"
    
      if [ -z "$log_lvl" ]; then
        log_lvl="INFO"
      fi
      local log_prefix="$(printf '[%s] [%s]' "$(date +'%Y/%m/%d %T.%3N')" "$log_lvl")"
    
      printf '%-36s %s\n' "$log_prefix" "$log_msg" >> "$log_file"
    }
    
         

    示例2:

    set -o pipefail
    log_file='test.log'
    
    log () {
      # Relies on stdin!
      local msg="$(cat -)"
    
      echo "$msg"
      echo '['"$(date)"']' "$msg" >> "$log_file"
    }
    
    echo test |& log
    echo "$?"
    not_a_command |& log
    echo "$?"
    echo finished |& log
    echo "$?"
    

1 个答案:

答案 0 :(得分:1)

BashFAQ #106直接就位;下面将讨论一些个人最佳实践,但有问题的FAQ是由Freenode #bash IRC频道背后的同一个人维护的社区资源,更完整,并且在发生任何冲突时进行控制。

尽可能预先执行重定向。

运行echo "foo" >>"$filename"会在运行echo之前打开输出文件名,然后再关闭它。这使得记录非常高开销;不要那样做。代替:

# in bash 4.1 or later
exec {log_fd}>"$filename"             # open a log file for output
echo "Log this statement" >&"$log_fd" # and write to it efficiently

在早期版本的bash中,您需要自己分配FD:

# manually selecting FD 3 to use for logging
exec 3>"$filename"
echo "Log this statement" >&3

保持高效!

在bash中,这意味着如果可能的话,你应该避免使用子shell或外部进程。在bash 4中,下面是一个示例,说明如何执行此操作:

[[ $logfile ]] && exec {log_fd}>"$logfile"

log() {
  # log to stderr unconditionally
  printf '%s\n' "$*" >&2
  # log to logfile if we have a file descriptor for it
  [[ $log_fd ]] && printf '[%(%Y-%m-%dT%H:%M:%S)T] %s\n' -1 "$*" >&"$log_fd"
}

请注意bash 4.2扩展名%(...)T作为外部date命令的内置替换,以及缺少任何可能打开新文件描述符或生成子shell的操作。

尽可能使用内置日志记录和跟踪

对于bash 4.0或更新版本,BASH_XTRACEFD提供了一种在不污染stderr的情况下使用set -x的方法(通过为要发出的语句级跟踪指定备用文件描述符)。使用它!

#!/usr/bin/env bash
PS4=':${BASH_SOURCE##*/}:${LINENO}+' ## set prefix format for logged lines
[[ $tracefile ]] && exec {BASH_XTRACEFD}>>"$tracefile" && set -x

如果您的脚本使用tracefile=foo.trace运行,则上面将附加执行期间调用该文件的所有操作的完整逐行日志,其中包含源文件和前面每行的行号。一般来说,这可以让您获得比其他方式更详细的日志记录,并且工作量大大减少。

有一些例外:set -x输出不是非常有用的一个地方是显示read的结果。可以使用noop:

while read -r foo bar baz; do
  : foo="$foo" bar="$bar" baz="$baz"
  # ...put your other logic here...
done <inputfile.txt

这将记录:(相当于true的noop命令)的调用,其值foobarbaz填充{ {1}}作为跟踪文件的一部分作为参数传递。