描述很长,请耐心等待:
我的日志文件大小从300 mb到1.5 Gb,需要在给定搜索键的情况下进行过滤。
日志的格式如下:
24 May 2017 17:00:06,827 [INFO] 123456 (Blah : Blah1) Service-name:: Single line content
24 May 2017 17:00:06,828 [INFO] 567890 (Blah : Blah1) Service-name:: Content( May span multiple lines)
24 May 2017 17:00:06,829 [INFO] 123456 (Blah : Blah2) Service-name: Multiple line content. Printing Object[ ID1=fac-adasd ID2=123231
ID3=123108 Status=Unknown
Code=530007 Dest=CA
]
24 May 2017 17:00:06,830 [INFO] 123456 (Blah : Blah1) Service-name:: Single line content
4 May 2017 17:00:06,831 [INFO] 567890 (Blah : Blah2) Service-name:: Content( May span multiple lines)
鉴于搜索键123456,我需要获取以下内容:
24 May 2017 17:00:06,827 [INFO] 123456 (Blah : Blah1) Service-name:: Single line content
24 May 2017 17:00:06,829 [INFO] 123456 (Blah : Blah2) Service-name: Multiple line content. Printing Object[ ID1=fac-adasd ID2=123231
ID3=123108 Status=Unknown
Code=530007 Dest=CA
]
24 May 2017 17:00:06,830 [INFO] 123456 (Blah : Blah1) Service-name:: Single line content
以下awk脚本完成了我的工作(非常缓慢):
gawk '/([0-9]{1}|[0-9]{2})\s\w+\s[0-9]{4}/{n=0}/123456/{n=1} n'
搜索1 GB大小的日志文件大约需要8分钟。我需要为许多这样的文件执行此操作。最重要的是,我有多个这样的搜索键,这使整个任务变得不可能。
我最初的解决方案是使用多线程。我使用了fixedThreadPoolExecutor,为每个需要过滤的文件提交了一个任务。在任务描述中,我使用java的Runtime()生成了新进程,它将使用bash执行gawk脚本并将输出写入文件然后合并所有文件。
虽然这似乎是一种糟糕的方式,但由于过滤依赖于I / O而不是CPU,因此与按顺序在每个文件上执行脚本相比,它确实给了我加速。
但它仍然不够,因为整个事情需要2小时,对于一个搜索密钥,需要27gb的日志文件。平均而言,我有4个这样的搜索键,需要获取所有结果并将它们组合在一起。
我的方法效率不高,因为:
A)当给出多个搜索键时,它会多次访问每个日志文件,从而导致更多的I / O开销 B)它会产生在每个线程内创建进程的开销。
所有这一切的简单解决方案是使用一些正则表达式库从远离awk并在java中完成整个事情。这里的问题是什么是可以为我提供所需输出的正则表达式库?
使用awk,我有/filter/{action}
属性,可以让我指定要捕获的多行范围(如上所示)。我怎样才能在java中做同样的事情?
我可以接受各种建议。例如,一个极端的选择是将日志文件存储在像S3这样的共享文件系统中,并使用多台计算机处理输出。
我是stackoverflow的新手,我甚至不知道我是否可以在这里发布。但过去一周我一直在研究这个问题,我需要有专业知识的人来指导我。提前谢谢。
答案 0 :(得分:1)
您有几个选择。
最好的一个imo是使用反向词典。这意味着对于至少一个日志中存在的每个关键字x,您存储对包含它的所有日志的引用。但是,由于你已经花了一个星期的时间来完成这项任务,我建议你使用已经存在的东西,然后做到这一点:Elasticsearch。您实际上可以使用完整的ELK堆栈(elasticsearch,logstash,kibana - 主要为日志设计)甚至解析日志,因为您可以在配置文件中放置正则表达式。您只需要对文件编制索引一次,并且可以在几毫秒内完成搜索。
如果你真的想浪费精力而不是寻求最佳解决方案,你可以使用hadoop上的map-reduce来过滤日志。但这并不是map-reduce最佳的任务,它更像是一个黑客。
答案 1 :(得分:0)
如果您希望加快执行时间,切换到Java可能不是最佳选择,但如果您正在考虑它,我写了一个可能有用的Java类。
您可以使用它同时搜索文件中的一个或多个键。由于您正在读取日志文件,因此可以安全地假设所有行都遵循正确的格式而没有错误。因此,不是使用正则表达式格式检查整行,而是简单地跳到密钥所在的位置(第一个ShallowWrapper
之后的数字),并将其与所需的值进行比较(假设它始终是一个数字)。
以这种方式使用它:
]
第三个参数是自定义接口Set<Integer> keys = new HashSet();
keys.add(123456);
keys.add(314159);
/* synchronously (omitting 3rd argument prints to stdout) */
new KeySearch('path/to/file.log', keys).run();
/* asynchronously!!! (to use PrintStream, create the output file first) */
PrintStream ps1 = new PrintStream('lines-found1.log');
PrintStream ps2 = new PrintStream('lines-found2.log');
new Thread(new KeySearch('path/to/1.log', keys, ps1::println)).start();
new Thread(new KeySearch('path/to/2.log', keys, ps2::println)).start();
,它在找到行时接收它们。我使用方法引用作为示例,但它可以是您想要的任何内容。这是类(至少需要Java 8)。
KeySearch.Callback