0

我有一个日志文件,其中包含如下行:

...timestamp...(id=1234)..GO...
...timestamp...(id=1234)..DONE...

事实:

  • 时间戳的格式为 HH:MM:SS.ssss(s 表示部分秒)
  • 每个 'id' 号码都有两条相关联的行,一条“GO”和一条“DONE”
  • 两条关联的线不一定彼此相邻;该文件是按时间顺序排列的

我想要的是:

  • 匹配相关的 GO/DONE 行
  • 区分时间戳
  • (理想情况下)创建一个新文件的形式:

    diffTime <GO line> <DONE line>
    

我的主要症结是区分时间戳。这将非常有用,而且我缺乏编写它的排序/sed/awk 技能。是否有日志文件工具可以帮助这种黑客行为?

4

2 回答 2

3

我不知道任何这样的工具,但可以在 shell 中编写它。例如,这个日志:

11:18:51 (id=123) 开始
11:18:52 (id=124) 开始
11:18:53 (id=123) 完成
11:18:54 (id=125) 开始
11:18:55 (id=125) 完成
11:18:55 (id=124) 完成

可以转化为

2 123
3 124
1 125

其中第一列是以秒为单位的时间,第二列是事务ID。

命令是:

cat example.log
| sed 's|\([^ ]\+\) (id=\([^)]\+\)) \(.\+\)|\1 \2 \3|;s|GO|1|;s|DONE|2|'
| sort -k2,3
| paste - -
| tr ':' ' '
| awk '{printf("%d %d\n", ((($6-$1)*60*60)+(($7-$2)*60)+($8-$3)), $4)}'

这种单行可能会更加简化。

这个怎么运作:

  • 将行格式更改为“11:18:51 123 GO”
  • 用 1 替换 GO,用 2 替换 DONE(因为稍后它允许我们正确排序)
  • 按事务 ID 和状态对结果行进行排序
  • 加入每 2 行(现在每个结果行都描述了事务的开始和结束)
  • 将所有冒号替换为空格(以便awk稍后简化表达式)
  • 通过手动除法计算时间差异
  • 打印结果
于 2011-09-19T05:41:23.110 回答
2

这是一个脚本,可以让你走到一半:

#!/bin/bash

# Script must be called with one parameter, the name of the file to process
if [ $# -ne 1 ]; then
  echo "Usage: $0 filename"
  exit
fi

filename=$1


# Use sed to put the timestamp after the id
#    10:46:01:0000 (id=20) GO
#    10:46:02:0000 (id=10) GO
#    10:46:03:0000 (id=10) DONE
#    10:46:04:0000 (id=20) DONE
#
#  becomes
#
#    (id=20) 10:46:01:0000 GO
#    (id=10) 10:46:02:0000 GO
#    (id=10) 10:46:03:0000 DONE
#    (id=20) 10:46:04:0000 DONE
#
# \1 timestamp
# \2 id
# \3 status (GO or DONE)
#         \1          \2              \3
sed -e "s/\([0-9:]*\) \((id=[0-9]*)\) \(.*\)/\2 \1 \3/" $filename > temp1


# Now sort the file. This will cause timestamps to be sorted, grouped by id
#    (id=20) 10:46:01:0000 GO
#    (id=10) 10:46:02:0000 GO
#    (id=10) 10:46:03:0000 DONE
#    (id=20) 10:46:04:0000 DONE
#
#  becomes
#
#    (id=10) 10:46:02:0000 GO
#    (id=10) 10:46:03:0000 DONE
#    (id=20) 10:46:01:0000 GO
#    (id=20) 10:46:04:0000 DONE
sort temp1 > temp2


# Use sed to put the id after the timestamp
#    (id=10) 10:46:02:0000 GO
#    (id=10) 10:46:03:0000 DONE
#    (id=20) 10:46:01:0000 GO
#    (id=20) 10:46:04:0000 DONE
#
#  becomes
#
#    10:46:02:0000 (id=10) GO
#    10:46:03:0000 (id=10) DONE
#    10:46:01:0000 (id=20) GO
#    10:46:04:0000 (id=20) DONE
# \1 id
# \2 timestamp
# \3 status (GO or DONE)
sed -e "s/\((id=[0-9]*)\) \([0-9:]*\) \(.*\)/\2 \1 \3/" temp2 > temp3

其余的......在运行这个脚本之后,每个 GO 行后面都会跟着一个具有相同 id 的 DONE 行,假设存在这样的 DONE 行。

接下来,您可以读取每对行,提取时间戳并区分它们(查看 Johnsyweb 建议的时间戳函数)。然后将两条线合并为一条线。您的结果现在看起来像:

#    1s 10:46:02:0000 (id=10) GO 10:46:03:0000 (id=10) DONE
#    3s 10:46:01:0000 (id=20) GO 10:46:04:0000 (id=20) DONE

请注意条目是如何按起始时间戳乱序的。发生这种情况是因为我们之前按 id 排序。我将把它留作练习,让您弄清楚如何以正确的顺序获取条目。我们希望 id=20 的条目出现在 id=10 之前,因为 id=20 在 id=10 之前开始。

#    3s 10:46:01:0000 (id=20) GO 10:46:04:0000 (id=20) DONE
#    1s 10:46:02:0000 (id=10) GO 10:46:03:0000 (id=10) DONE

我确信这很令人困惑,所以如果您有任何问题,请告诉我。我确信有更有效的方法来完成这一切,但这是我的想法。

于 2011-09-19T05:06:54.413 回答