【问题标题】:format shell script logs and write to a file格式化 shell 脚本日志并写入文件
【发布时间】:2021-01-21 12:21:21
【问题描述】:

我需要将 shell 脚本中的所有输出/错误日志记录到标准格式的文件中。

例如文件 script.sh:

echo "I want to be a json message!"
echo "I also want to be a json message!"

执行如下:

./script.sh >> jsonmessages.log

应该给我一个文件内容,如:

{timestamp: '2020-12-31 00:00:00', message: 'I want to be a json message!'}
{timestamp: '2020-12-31 00:00:00', message: 'I also want to be a json message!'}

【问题讨论】:

    标签: bash shell sh stdout


    【解决方案1】:

    感谢您的解决方案。

    我能够通过以下实现将脚本执行的日志写入日志文件:

    1. 创建一个 json 记录器

        json_logger() {
               # Values for json
               current_timestamp="$(date +\"%Y-%m-%dT%H:%M:%S\")"
               param1="$param1value"
               param2="$param2value"
               log_level=$1
               script_name=$(basename $2 .sh)
      
               # Create json and re-direct to log file
               jq --raw-input --compact-output \
               '{
                       "@timestamp": '$current_timestamp',
                       "parameter1": "'$param1'",
                       "parameter2": "'$param2'",
                       "log-level": "'$log_level'",
                       "logger": "'$script_name'",
                       "message": .
               }' >> /var/log/app.log 2>&1 
           }
      
    2. 然后执行如下脚本

         "script.sh" 2>&1 | json_logger "INFO" {job_name or script_name}
      

    【讨论】:

      【解决方案2】:

      将 shell 字符串可靠地转换为有效的 JSON 字符串的最佳选择是使用 JSON 解析器/格式化程序。最受欢迎的是jq

      这是一个使用 jq 的带时间戳的 JSON 消息记录器的实现:

      #!/usr/bin/env bash
      
      json_logger() {
        while read -r msg || [ -n "$msg" ]; do
          jq \
            -nc \
            --arg msg "$msg" \
            '{ "timestamp": (now | strftime("%Y-%m-%d %H:%M:%S")), "message": $msg }'
        done
      }
      
      
      ----------
      
      
      

      编辑:

      正如KamilCuk 写道:

      我们可以在没有缓慢的 bash 循环的情况下做得更好 - 它只是 jq --raw-input '{ "timestamp": (now | strftime("%Y-%m-%d %H:%M:%S")), "message": . }'

      所以这里有一个改进的json_logger

      json_logger() {
        jq \
          --raw-input \
          --compact-output \
          '{ "timestamp": (now | strftime("%Y-%m-%d %H:%M:%S")), "message": . }'
      }
      

      附录:

      Harshit Kushwaha wrote:

      例如,我需要在调用 json_logger 的 json 中打印方法名称。如何修改 json_logger 以及如何在 echo 中使用它?

      如果将方法名称作为参数提供给json_logger 函数,则下面是一个实现:

      #!/usr/bin/env bash
      
      IFS= read -r -d '' __JQ_LOGGER_SCRIPT <<'JQSCRIPT'
      {
        "timestamp": now | strftime("%Y-%m-%d %H:%M:%S"),
        "message": .
      } |
        if ($name | length) != 0
        then
          . + { "method": $name }
        else
          .
        end
      JQSCRIPT
      
      json_logger() {
        jq \
          --raw-input \
          --compact-output \
          --arg name "$1" \
          "$__JQ_LOGGER_SCRIPT"
      }
      
      echo "I want to be a json message!" | json_logger
      echo "I also want to be a json message!" | json_logger echo
      
      printf %s $'I am a message with "quoted text" and some special characters: \'\t\7\42\\\'; that can only be properly converted to JSON with a JSON formatter and parser.' | json_logger printf
      

      生成此 JSON 输出:

      {"timestamp":"2021-01-29 14:02:46","message":"I want to be a json message!"}
      {"timestamp":"2021-01-29 14:02:46","message":"I also want to be a json message!","method":"echo"}
      {"timestamp":"2021-01-29 14:02:46","message":"I am a message with \"quoted text\" and some special characters: '\t\u0007\"\\'; that can only be properly converted to JSON with a JSON formatter and parser.","method":"printf"}
      

      【讨论】:

      • 谢谢@Léa Gris。但是有了这个,我将只能记录 echo 或 printf 消息。我们能否以某种方式配置该函数以用于在运行脚本时生成的错误消息?
      • @HarshitKushwaha 请参阅:How can I pipe stderr, and not stdout?
      • 我们可以在没有缓慢的 bash 循环的情况下做得更好 - 它只是 jq --raw-input '{ "timestamp": (now | strftime("%Y-%m-%d %H:%M:%S")), "message": . }'
      • 感谢@KamilCuk 和 Léa Gris,我现在可以使用 2>&1 打印标准错误和标准输出消息。我还可以在json中添加一些参数吗?例如,我需要在调用 json_logger 的 json 中打印方法名称。如何修改 json_logger 以及如何在 echo 中使用它?
      • @HarshitKushwaha 我刚刚添加了一个带有可选方法名称的实现。虽然下次,请不要在得到答案后扩大您的问题。 JQ 是一个不错的工具,但它有自己的脚本语法,可能很难使用,但我鼓励你一次又一次地尝试自己的虚拟测试。确实值得付出努力,因为这将节省您从 shell 处理 JSON 内容的时间。
      【解决方案3】:
      ./script.sh | awk -v squot="'" '{ print "{\"timestamp\": \""strftime("%Y-%m-%d %H:%M:%S")"\", \"message\": \""$0"\"}" }' mess | jq >> jsonmessages.log
      

      使用 GNU awk,使用 awk 的 strftime 函数以所需格式打印时间戳,以及双引号和所需格式的其他数据。通过管道传递到 jq 以确保 json 有效

      【讨论】:

      • awk 无法可靠地生成有效的 JSON 字符串
      • 然后你可以通过管道传递到 jq 以确保你有有效的 json
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 2012-12-03
      相关资源
      最近更新 更多