【问题标题】:Carving data from log file从日志文件雕刻数据
【发布时间】:2016-04-09 10:37:36
【问题描述】:

我有一个包含以下数据的日志文件:

 time=1460196536.247325 latency=3:6:7:9:16:(8)ms latency95=11ms latency99=13ms requests=517 option1=0 option2=0 errors=0 throughput=480rps ql=1 rr=0.00% cr=0.00% accRequests=101468 accOption1=0 accOption2=0 accLatency=2:6:7:8:3998:(31)ms accLatency95=11ms accLatency99=649ms accOpenQueuing=1664 accErrors=278

我正在尝试编写 bashscript,我尝试为日志文件中的每一行雕刻这些值并将其写入第二个文件:

  • 时间(转换为当地时间 GMT+2)
  • 延迟99
  • 请求
  • 错误

第二个文件中的所需输出:

 time    latency99   requests    errors

 12:08:56   13         517          0 

这是使用正则表达式最简单的方法吗?

【问题讨论】:

    标签: bash shell logging extract multiple-columns


    【解决方案1】:

    这是一个适用于版本 4 及更高版本的 Bash 解决方案,使用关联数组:

    #!/bin/bash
    # Assoc array to hold data.
    declare -A data
    # Log file ( the input file ).
    logfile=$1
    # Output file.
    output_file=$2
    
    # Print column names for required values.
    printf '%-20s %-10s %-10s %-10s\n' time latency99 requests errors > "$output_file"
    # Iterate over each line in $logfile
    while read -ra arr; do
        # Insert keys and values into 'data' array.
        for i in "${arr[@]}"; do
            data["${i%=*}"]="${i#*=}"
        done
        # Convert time to GMT+2
        gmt2_time=$(TZ=GMT+2 date -d "@${data[time]}" '+%T')
        # Print results to stdout.
        printf '%-20s %-10s %-10s %-10s\n' "$gmt2_time" "${data[latency99]%ms}" "${data[requests]}" "${data[errors]}" >> "$output_file"
    done < "$logfile"
    

    如您所见,脚本接受两个参数。第一个是日志文件的文件名,第二个是日志文件中每一行解析数据将被逐行插入的输出文件。

    请注意,我使用GMT+2 作为TZ 变量的值。 改为使用精确区域作为值。例如,TZ="Europe/Berlin"。 您可能想使用工具tzselect 来了解您所在区域的正确字符串值。

    为了测试它,我创建了以下日志文​​件,其中包含 3 行不同的输入:

    time=1260196536.242325 latency=3:6:7:9:16:(8)ms latency95=11ms latency99=10ms requests=100 option1=0 option2=0 errors=1 throughput=480rps ql=1 rr=0.00% cr=0.00% accRequests=101468 accOption1=0 accOption2=0 accLatency=2:6:7:8:3998:(31)ms accLatency95=11ms accLatency99=649ms accOpenQueuing=1664 accErrors=278
    time=1460246536.244325 latency=3:6:7:9:16:(8)ms latency95=11ms latency99=20ms requests=200 option1=0 option2=0 errors=2 throughput=480rps ql=1 rr=0.00% cr=0.00% accRequests=101468 accOption1=0 accOption2=0 accLatency=2:6:7:8:3998:(31)ms accLatency95=11ms accLatency99=649ms accOpenQueuing=1664 accErrors=278
    time=1260236536.147325 latency=3:6:7:9:16:(8)ms latency95=11ms latency99=30ms requests=300 option1=0 option2=0 errors=3 throughput=480rps ql=1 rr=0.00% cr=0.00% accRequests=101468 accOption1=0 accOption2=0 accLatency=2:6:7:8:3998:(31)ms accLatency95=11ms accLatency99=649ms accOpenQueuing=1664 accErrors=278
    

    让我们运行测试(脚本名称是 sof):

    $ ./sof logfile parsed_logfile
    $ cat parsed_logfile
    time                 latency99  requests   errors    
    12:35:36             10         100        1         
    22:02:16             20         200        2         
    23:42:16             30         300        3 
    

    编辑:

    根据 cmets 中可以看到的 OP 请求以及聊天中进一步讨论的内容,我编辑了脚本以包含以下功能:

    • latency99 的值中删除ms 后缀。
    • 从日志文件中逐行读取输入,解析并将结果输出到 选定的文件。
    • 仅在输出的第一行中包含列名。
    • 将时间值转换为 GMT+2。

    【讨论】:

    • 出于某种原因,我得到了这个:(Bash 版本 4.2.25)./test.sh column: line too long time latency99 requests errors
    • 我明白了。这是输入行长度的限制,以字节为单位,由column 定义。我编辑了我的答案,只使用printf
    • 如何在 13 之后删除“ms”?我需要定义一个日志文件,它会逐行读取,然后将输出写入另一个文件?
    • 日志文件的内容是什么?和Bash脚本中定义的input一样吗?
    • 是的,输入文件包含与输入相同的内容,但有数千行。
    【解决方案2】:

    这是一个 awk 脚本。假设日志文件是mc.log,脚本保存为mc.awk,你可以像这样运行它:awk -f mc.awk mc.log with GNU awk。

    mc.awk

        BEGIN{
            OFS="\t"
            # some "" to align header and values in output
            print "time", "", "latency99", "requests", "errors"
        }
    
        function getVal( str) {
            # strip leading "key=" and trailing "ms" from str
            gsub(/^.*=/, "", str)
            gsub(/ms$/, "", str)
            return str
        }
    
        function fmtTime( timeStamp ){
            val=getVal( timeStamp )
            return strftime( "%H:%M:%S", val)
        }
    
        {
            # some "" to align header and values in output
            print fmtTime($1), getVal($4), "", getVal($5), "", getVal($8)
        }
    

    【讨论】:

    • 我收到awk: mc.awk: line 24: function strftime never defined
    • @user3580316 我正在使用:awk --version:GNU Awk 4.0.1。你用的是什么awk?如果你只是return val,你会得到未格式化的时间戳。
    • @user3580316 你用的是什么操作系统和awk版本,也许你可以将GNU awk安装为gawk,你可以运行以下命令:gawk -f mc.awk mc.log代替。
    【解决方案3】:

    这是一个awk 版本(不是 GNU)。转换日期需要调用外部程序:

    #!/usr/bin/awk -f
    
    BEGIN {
        FS="([[:alpha:]]+)?[[:blank:]]*[[:alnum:]]+="
        OFS="\t"
        print "time", "latency99", "requests", "errors"
    }
    {
        print $2, $5, $6, $9 
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 2013-03-17
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 2014-05-17
      • 2012-11-07
      相关资源
      最近更新 更多