以下awkscript 解析日志文件并执行时间增量(间隔)的计算
#!/usr/bin/awk -f
# converts milliseconds to HH:MM:SS,mmm format
function msecs2date(msc) {
h = msc/3600000
m = (msc%3600000)/60000
s = (msc%60000)/1000
ms = msc%1000
printf("%02d:%02d:%02d,%03d\n", h, m, s, ms)
}
# converts HH:MM:SS,mmm to milliseconds
function date2msecs(dat) {
split(dat,d,":")
split(d[3],sx,",")
return d[1]*3600000 + d[2]*60000 + sx[1]*1000 + sx[2]
}
# parses the logfile and generates 2 space-separated columns:
# Col.1 > displays the get/release pair REQUEST_CODE
# Col.2 > displays the time delta between the 'get' and 'release'
# events for the respective REQUEST_CODE in Col.1
BEGIN {FS=" "}
{
one = $1
ten = $NF
getline
if ($10 == ten){
printf("%s ",ten)
msecs2date(date2msecs($1)-date2msecs(one))
}
}
您可以通过将其保存为例如 logdelta 然后使其可执行并运行它来使用它:
$ chmod +x logdelta
$ ./logdelta logfile > outputfile
这是您的日志文件提取(另存为日志)输入脚本时的输出:
$ ./logdelta log
wCv4cbch 00:00:00,006
sZhegruu 00:00:00,007
这个脚本的作用本质上非常简单(还要检查脚本中的 cmets):
它使用空格作为分隔符 (FS=" ") 逐行解析日志文件,从与特定代码相关的两行中获取适当的标记(使用 getline 技巧),然后继续检查来自两行的请求代码是否相等。如果是,它首先使用 date2msecs 函数在两个时间戳上计算时间增量(以毫秒为单位),然后使用 msecs2date 函数将此时间增量转换回 HH:MM:SS,mmm 格式,以此类推,直到日志文件结束。
这两个转换器函数非常简单,您可以在split() 函数here 和here 上找到更多信息。
现在,如果您打算将此脚本用于生产服务器日志文件,有几点值得注意:
A - 永远不要完全相信在互联网上找到的代码(这也适用于这个脚本)
这意味着一件事:在采用任何解决方案之前,通过各种极端情况反复测试,例如损坏的日志文件和其他畸形或异常情况(见注)。
B - 性能很重要
这就是我选择awk 来实现这个脚本的原因。为了测试它的性能,我根据您提供的摘录创建了一个全天日志文件,使用以下c++(实际上是c)程序:
#include <cstdio>
#include <algorithm> // for rand()
# creates len-sized random alphanumeric codes
void gen_random(char* s, const int len) {
static const char alphanum[] ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < len; ++i) s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
s[len] = 0;
}
int main(int argc, char* argv[]){
char* filler="INFO [...] (http--0.0.0.0-8443-17) User xxx";
char* coda="REQUEST_CODE =";
char* action;
char gc[9];
for (int i=0;i<24;i++){
for (int j=0;j<60;j++){
for (int k=0;k<60;k++){
for (int l=0;l<1001;l=l+7){
l % 2 == 0 ? ( action="get", gen_random(gc,8) ):(action="release", void(0));
printf("%02d:%02d:%02d,%003d %s %s %s %s\n",i,j,k,l,filler,action,coda,gc);
};
printf("%02d:%02d:%02d,999 %s release %s %s\n",i,j,k,filler,coda,gc);
};
};
};
return 0;
}
像这样构建它:
$ g++ -o logen logen.cpp
并运行它:
$ ./logen > logfile
它会创建一个 1.1GB(12441600 行)的虚假日志文件:
$ head -n 4 logfile
00:00:00,000 INFO [...] (http--0.0.0.0-8443-17) User xxx get REQUEST_CODE = fa37JncC
00:00:00,007 INFO [...] (http--0.0.0.0-8443-17) User xxx release REQUEST_CODE = fa37JncC
00:00:00,014 INFO [...] (http--0.0.0.0-8443-17) User xxx get REQUEST_CODE = HryDsbza
00:00:00,021 INFO [...] (http--0.0.0.0-8443-17) User xxx release REQUEST_CODE = HryDsbza
...
$ tail -n 4 logfile
23:59:59,980 INFO [...] (http--0.0.0.0-8443-17) User xxx get REQUEST_CODE = AI9xRoPQ
23:59:59,987 INFO [...] (http--0.0.0.0-8443-17) User xxx release REQUEST_CODE = AI9xRoPQ
23:59:59,994 INFO [...] (http--0.0.0.0-8443-17) User xxx get REQUEST_CODE = LEAeMTva
23:59:59,999 INFO [...] (http--0.0.0.0-8443-17) User xxx release REQUEST_CODE = LEAeMTva
具有(或多或少)真实日志文件的代表性大小。
当它输入到脚本中时,性能方面,结果如下:
$ time ./logdelta logfile > ouputfile
real 0m35.776s
user 0m30.364s
sys 0m2.312s
即 1.1 GB 的日志文件大约需要 35 秒,这是相当令人满意的性能(在运行 Xubuntu 14.04 的单核 2GB VM 上测试)。
这里还有一些示例输出:
$ head -n 2 outputfile
fa37JncC 00:00:00,007
HryDsbza 00:00:00,007
...
$ tail -n 2 outputfile
AI9xRoPQ 00:00:00,007
LEAeMTva 00:00:00,005
注意:我发布虚假日志文件生成器代码的原因是为了鼓励您修改它并尝试将各种人为错误合并到生成的日志文件中,以便能够测试如何此脚本(按原样或根据您的修改)处理其他极端情况。