我正在尝试编写一个shell脚本来从日志文件中提取相同单词的行之间的间隔。 参赛作品很简单:
19:38:24,077 INFO [...](http - 0.0.0.0-8443-17)用户xxx获取REQUEST_CODE = wCv4cbch 19:38:24,083 INFO [...](http - 0.0.0.0-8443-17)用户xxx发布REQUEST_CODE = wCv4cbch 19:38:24,091 INFO [...](http - 0.0.0.0-8443-17)用户xxx获取REQUEST_CODE = sZhegruu 19:38:24,098 INFO [...](http - 0.0.0.0-8443-17)用户xxx发布REQUEST_CODE = sZhegruu
我需要找到相同键之间的时间间隔,其中键是'='运算符后面的代码。例如
19:38:24,077 INFO [...](http - 0.0.0.0-8443-17)用户xxx获取REQUEST_CODE = wCv4cbch
和
19:38:24,083 INFO [...](http - 0.0.0.0-8443-17)用户xxx发布REQUEST_CODE = wCv4cbch
有什么想法吗?
非常感谢
答案 0 :(得分:0)
使用grep和正则表达式,例如,如果你想要3分钟的日志间隔
grep" 16 / sep / 2002:19:3 [1-4]"日志文件
答案 1 :(得分:0)
以下awk
脚本解析日志文件并执行时间增量(间隔)的计算
#!/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
这个脚本的功能基本上非常简单(另请参阅脚本中的注释):
它使用空格作为分隔符(FS=" "
)逐行解析日志文件,从两行中获取与特定代码相关的适当标记(使用getline
技巧)然后继续检查来自两条线的请求代码是否相等。如果是,则首先使用两个时间戳上的date2msecs
函数计算时间增量(以毫秒为单位),然后使用{{1将此时间增量转换回 HH:MM:SS,mmm 格式函数,依此类推,直到日志文件结束。
这两个转换器功能非常简单,您可以在msecs2date
函数here和here上找到更多信息。
现在,如果您要将此脚本用于生产服务器日志文件,则有一些值得注意的事项:
A - 永远不要完全信任互联网上的代码(这也适用于这个脚本)
这意味着一件事:在采用任何解决方案之前,一次又一次地通过各种极端情况进行测试,例如损坏的日志文件和其他错误或异常(参见注释)。
B - 效果重要
这就是我选择split()
来实现此脚本的原因。为了测试其性能,我使用以下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
它创建了一个1.1GB(12441600行)的虚假日志文件:
$ ./logen > logfile
...
$ 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
即1.1 GB日志文件约35秒,这是一个相当令人满意的性能(在运行Xubuntu 14.04的单核2GB VM上测试)。
以下是一些示例输出:
$ time ./logdelta logfile > ouputfile
real 0m35.776s
user 0m30.364s
sys 0m2.312s
...
$ head -n 2 outputfile
fa37JncC 00:00:00,007
HryDsbza 00:00:00,007
注意:我发布faux日志文件生成器代码的原因是为了鼓励您修改它并尝试将各种人为错误合并到生成的日志文件中,以便能够测试如何这个脚本(原样或有你的修改)处理其他角落案件。