java 通过正则表达式_java-grok通过正则表达式解析日志

项目中有一个新的需求,就是需要解析日志,将日志中的部分数据分析获取出来供系统使用,通俗的讲就是抓取日志中的部分有用的信息,比如下面的apache日志信息,我需要解析每行日志,获取每行日志的IP地址、用户、创建时间、请求方式、地址....如果我们单纯使用java的方式,可能会想到通过文件流读取日志信息,然后逐行解析字符串,但是这种方式太过于复杂,而且效率比较低,在网上查询了相关的资料,决定使用logstash的grok工具,在网上也有相对应的java实现,其实现原理就是自定义正则表达式,通过正则表达式来解析日志,好处就是我们可以将日志中不规则的数据转换为规则的数据,例如map或者json数据,还有就是写一次表达式之后,可以在多处运行,如果有什么不同的地方,只需要修改一下正则表达式即可,是不是感觉很方便呢。

64.242.88.10 - - [07/Mar/2004:16:05:49 -0800] "GET /twiki/bin/edit/Main/Double_bounce_sender?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12846

64.242.88.10 - - [07/Mar/2004:16:06:51 -0800] "GET /twiki/bin/rdiff/TWiki/NewUserTemplate?rev1=1.3&rev2=1.2 HTTP/1.1" 200 4523

64.242.88.10 - - [07/Mar/2004:16:10:02 -0800] "GET /mailman/listinfo/hsdivision HTTP/1.1" 200 6291

64.242.88.10 - - [07/Mar/2004:16:11:58 -0800] "GET /twiki/bin/view/TWiki/WikiSyntax HTTP/1.1" 200 7352

64.242.88.10 - - [07/Mar/2004:16:20:55 -0800] "GET /twiki/bin/view/Main/DCCAndPostFix HTTP/1.1" 200 5253

网上对grok的定义是:Grok 是 Logstash 最重要的插件。你可以在 grok 里预定义好命名正则表达式,在稍后(grok参数或者其他正则表达式里)引用它。参考博文:http://udn.yyuap.com/doc/logstash-best-practice-cn/filter/grok.html

用java api的方式来集成grok,在github上面已经有了相关的项目工程实现了,我们可以在github中获取这个工程:https://github.com/thekrakken/java-grok,或者直接使用其打包好了的jar包和相关依赖包,可以在我的资源目录中进行下载:http://download.csdn.net/detail/harderxin/9923587

相关依赖包包括:commons-beanutils-1.8.3.jar、commons-lang3-3.1.jar、commons-logging-1.1.1.jar、gson-2.2.2.jar、slf4j-api-1.7.5.jar,版本号可以不与上面列举一样。

如果你是maven工程,可以在pom.xml文件中添加下面的依赖,不过其他依赖包仍然需要自己去引入进来:

io.thekraken

grok

0.1.5

好了,现在我们开始对相关api进行操作了,新建工程,将相关的jar包引入进来,还有就是引入java-grok工程中默认的正则表达式文件,它里面定义了数字、文本、日期、IP地址等等一些列的基础数据的正则表达式,参考:https://github.com/thekrakken/java-grok/blob/master/patterns/patterns

要使用java-grok,首先需要通过定义好的正则表达式文件的路径创建Grok对象,我们可以定义为一个单列模式

package com.harderxin.grok.core;

import io.thekraken.grok.api.Grok;

import io.thekraken.grok.api.exception.GrokException;

public class GrokInstance {

private static Grok grok;

private GrokInstance() {

}

public static Grok getGrokInstance(String grokPatternPath) {

if (grok == null) {

try {

grok = Grok.create(grokPatternPath);

} catch (GrokException e) {

e.printStackTrace();

}

}

return grok;

}

}

获取到Grok对象后,通过传入我们需要解析的日志的表达式名称和要转换的日志消息,来创建Match对象:

public static Match getMatch(String pattern, String message) {

Match match = null;

try {

grok.compile(pattern);

match = grok.match(message);

match.captures();

} catch (GrokException e) {

e.printStackTrace();

match = null;

}

return match;

}

得到Match对象后,我们就可以将数据转换为对应的Map或者Json数据了,我写了一个辅助类:

package com.harderxin.grok.core;

import java.util.Map;

import io.thekraken.grok.api.Grok;

import io.thekraken.grok.api.Match;

import io.thekraken.grok.api.exception.GrokException;

public class GrokUtils {

private static final String GROK_PATTERN_PATH = "conf/agent_patterns";

private static Grok grok = GrokInstance.getGrokInstance(GROK_PATTERN_PATH);

public static Map toMap(String pattern, String message) {

Match match = getMatch(pattern, message);

if (match != null) {

return match.toMap();

}

return null;

}

public static String toJson(String pattern, String message) {

Match match = getMatch(pattern, message);

if (match != null) {

return match.toJson();

}

return null;

}

private static Match getMatch(String pattern, String message) {

Match match = null;

try {

grok.compile(pattern);

match = grok.match(message);

match.captures();

} catch (GrokException e) {

e.printStackTrace();

match = null;

}

return match;

}

}

创建我们的测试类,注意:

上面的每次解析只能解析日志中的单行数据,当要解析一个日志文件的时候,我们需要逐行解析该文件,我们需要解析下面这一行日志:

64.242.88.10 - - [07/Mar/2004:16:45:56 -0800] \"GET /twiki/bin/attach/Main/PostfixCommands HTTP/1.1\" 401 12846,通过程序解析后,我需要得到clientip =64.242.88.10,timestamp = 07/Mar/2004:16:45:56 -0800,verb=GET,httpversion = 1.1等这样格式化的数据,用我们上面的程序就可以做到。

在patterns文件中定义好我们需要解析日志的正则表达式:

XINTEST %{IPORHOST:clientip} %{USER:ident;boolean} %{USER:auth}[%{HTTPDATE:timestamp;date;dd/MMM/yyyy:HH:mm:ss Z}\] \"(?:%{WORD:verb;string} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion;float})?|%{DATA:rawrequest})\" %{NUMBER:response;int} (?:%{NUMBER:bytes;long}|-)

其中的IPORHOST是pattern中已经定义好的正则表达式,如下面所示,clientip是我们为解析后的数据的Key的别名,如果没有别名,默认名称为正则表达式的名称:

IP (?:%{IPV6:UNWANTED}|%{IPV4:UNWANTED})

HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b)

IPORHOST (?:%{HOSTNAME:UNWANTED}|%{IP:UNWANTED})

我们的pattern表达式编写好了,名称为XINTEST,下面就可以使用我们的代码进行测试了,在测试的时候,pattern表达式需要使用%{}将名称放进去,这个是规定:

package com.harderxin.grok.test;

import java.util.Map;

import com.harderxin.grok.core.GrokUtils;

public class GrokTest2 {

public static void main(String[] args) {

String pattern = "%{XINTEST}";

String message = "64.242.88.10 - - [07/Mar/2004:16:45:56 -0800] \"GET /twiki/bin/attach/Main/PostfixCommands HTTP/1.1\" 401 12846";

String json = GrokUtils.toJson(pattern, message);

System.out.println(json);

Map map = GrokUtils.toMap(pattern, message);

System.out.println(map.toString());

}

}

代码输出的json数据如下:

{

"HOUR": "16",

"INT": "-0800",

"MINUTE": "45",

"MONTH": "Mar",

"MONTHDAY": "07",

"SECOND": "56",

"TIME": "16:45:56",

"XINTEST": "64.242.88.10 - - [07/Mar/2004:16:45:56 -0800] \"GET /twiki/bin/attach/Main/PostfixCommands HTTP/1.1\" 401 12846",

"YEAR": "2004",

"auth": "-",

"bytes": 12846,

"clientip": "64.242.88.10",

"httpversion": 1.1,

"ident": false,

"request": "/twiki/bin/attach/Main/PostfixCommands",

"response": 401,

"timestamp": "Mar 8, 2004 8:45:56 AM",

"verb": "GET"

}

日志中相关的数据就被我们程序解析出来了!!其实它的原理就是我们自定义正则表达式,然后通过正则表达式去匹配每一行的数据,转换为用户定义的key:value数据!有了这个功能,我们可以解析的日志无论多么复杂多变,只要它里面的数据遵循一定的正则表达式匹配规则,那么就能转换为我们需要的数据!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值