flume拦截mysql_Flume 自定义拦截器 多行读取日志+截断

前言:

Flume百度定义如下:

Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。

搭建并使用flume不是特别难,而且网上也有技术文章分享,我不再赘述了。本文主要建立在已经搭建并使用flume的情况。

业务场景:

flume读取日志是按行读取,无法进行多行读取,当出现如下日志时将无法读到日志的正确时间与类型信息,所以我们需要有一种可以多行读取日志信息的办法,这里采用自定义拦截器的方法:

1 2019-08-02 14:34:13.153 [DEBUG][tomcatThreadPool-7][com.xxx.xxx.xxx.xxx.web.CommonHandlerExceptionResolver] (CommonHandlerExceptionResolver.java:134) \n Exception:------------------------------------------------------------------\ncom.xxx.xxx.xx.exceptions.XxxException: \n### Error querying database. Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (5638500 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.\n### The error may exist in com/xxx/xxx/xxx/basic/mapper/custom/CsWmFrtRateExtMapper.xml\n### The error may involve defaultParameterMap\n### The error occurred while setting parameters\n### SQL: SELECT * FROM ((SELECT cwfr.CS_WM_FRT_RATE_ID AS CS_WM_FRT_RATE_ID, cwfr.ACTIVE_DATE_BEGIN AS ACTIVE_DATE_BEGIN, cwfr.FRT_ITEM_CODE AS FRT_ITEM_CODE, cwfr.FRT_ITEM_NAME AS FRT_ITEM_NAME, cwfr.RP_FLAG AS RP_FLAG, cwfr.FRT_MODE AS FRT_MODE, cwfr.CALCULATION_ITEM AS CALCULATION_ITEM, cwfr.CHARGE_UOM_CODE AS CHARGE_UOM_CODE, cwfr.CHARGE_UOM_NAME AS

对于一些业务系统的日志可能会比较大,超1M,2M甚至更多,可以根据实际情况只截取前面一部分保留下来即可,为了让功能更具有灵活性,在实现上增加开关属性,默认打开着,不需要时设置关闭。

自定义拦截器实现的属性:过滤正则,截断标识(即开关),总截取最大长度,单个截取最大长度,最后一个事件流。最后一个事件流的作用保留下来与下一批次一起,按正则匹配后才发送出去,因为flume是按批次读取的,默认是100行,而这个配置又与flume运行内存有关系。这个是属于参数调优的话题。

特别注意:代码打包后是需要放到flume安装目录下的lib下。放进去后需要重新才会生效。

代码实现如下:

1 packageorg.apache.flume.custom;2

3 importcom.google.common.collect.Lists;4 importorg.apache.commons.codec.Charsets;5 importorg.apache.flume.Context;6 importorg.apache.flume.Event;7 importorg.apache.flume.interceptor.Interceptor;8

9 importjava.util.List;10 importjava.util.regex.Matcher;11 importjava.util.regex.Pattern;12

13 /**

14 * 自定义拦截器 参考 Author: xiufen.huang Create Data: 2019/8/12 15:4615 */

16 public class MultInterceptor implementsInterceptor {17

18 //过滤正则

19 private static Pattern regex = null;20 //截取标志

21 private static Boolean cutFlag = true;22 //总截取最大长度

23 private static Integer cutMax = null;24 //单个截取最大长度

25 private static Integer singleCut = null;26 //最后一个事件流

27 private static List lastList =Lists.newArrayList();28

29 @Override30 public voidinitialize() {31

32 }33

34 @Override35 publicEvent intercept(Event event) {36 //System.out.println("----------intercept(Event event)方法执行,处理单个event");

37 returnevent;38 }39

40 @Override41 public List intercept(Listlist) {42 //System.out.println("进来方法了吗?");43

44 //处理结果 event list

45 List intercepted = null;46

47 int addnum = 0;//记录上一个正确匹配的event在队列中的位置,以便下一event有和它连接的需要

48

49 if (lastList != null && lastList.size() >0){50 //初始化

51 int initCapacity = list.size() +lastList.size();52 intercepted =Lists.newArrayListWithCapacity(initCapacity);53 //添加

54 intercepted.addAll(lastList);55

56 //清空

57 lastList =Lists.newArrayList();58 }else{59 intercepted =Lists.newArrayListWithCapacity(list.size());60 }61

62 //有正则的情况

63 for (int i = 0; i < list.size(); i++) {64 Event interceptedEvent = null;65 Matcher matcher = regex.matcher(newString(list.get(i).getBody(), Charsets.UTF_8));66 if(matcher.find()) {67 interceptedEvent =intercept((Event)list.get(i));68 //单个的body

69 String singleBody = newString(interceptedEvent.getBody(), Charsets.UTF_8);70 int singleBodyLen =singleBody.length();71 System.out.println("正则匹配-原始body---------:" +singleBody);72 if(cutFlag) {73 //处理最大截取数边界条件--一定要重新一个变量接收

74 int lsSingleCut = singleCut > singleBodyLen ?singleBodyLen : singleCut;75 //截取字符串--新变量

76 String singleCutBody = new String(singleBody.substring(0, lsSingleCut));77

78 System.out.println("单个截取-截取后body=============:" +singleCutBody);79 //重新赋值body

80 interceptedEvent.setBody(singleCutBody.getBytes());81 }82

83 intercepted.add(interceptedEvent);84 addnum = addnum +1;85 //System.out.println("matcher.find() 下的:addnum:" + addnum);

86 } else{87 if (intercepted.size() == 0) {88 //表示本次没有匹配上

89 continue;90 }91

92 addnum = addnum >= intercepted.size() ? intercepted.size() - 1: addnum;93

94

95 String body = new String(intercepted.get(addnum).getBody(), Charsets.UTF_8) + "\n"

96 + newString(list.get(i).getBody(), Charsets.UTF_8);97

98 System.out.println("总截取-原始body---------:" +body);99 int bodyLen =body.length();100 //截取body-新变量

101 String cutBody =body;102 if(cutFlag) {103

104 //处理最大截取数边界条件--新变量

105 int lsCutMax = cutMax > bodyLen ?bodyLen : cutMax;106 //截取字符串

107 cutBody = new String(body.substring(0, lsCutMax));108 System.out.println("-处理截取-截取后body=============: " +body);109 }110

111 intercepted.get(addnum).setBody(cutBody.getBytes());112 }113 }114

115 //最后一个保存在静态变量,等待下一批次

116 if (intercepted != null && intercepted.size() > 0){117 int lastIndex = intercepted.size() -1;118 lastList.add(intercepted.get(lastIndex));119 //移除最后一个索引

120 intercepted.remove(lastIndex);121 }122

123 returnintercepted;124 }125

126 @Override127 public voidclose() {128 System.out.println("----------自定义拦截器close方法执行");129 }130

131 public static class Builder implementsInterceptor.Builder {132 @Override133 publicInterceptor build() {134 System.out.println("----------build方法执行");135 return newMultInterceptor();136 }137

138 @Override139 public voidconfigure(Context context) {140 String regexStr = context.getString("regex", null);141 cutFlag = context.getBoolean("cutFlag", true);142 cutMax = context.getInteger("cutMax", 0);143 singleCut = context.getInteger("singleCut", 0);144 System.out.println("参数regexStr:" + regexStr + ",参数cutMax: " + cutMax + ",cutFlag: " +cutFlag145 + " ,singleCut: " +singleCut);146

147 //由于外面传过来的单位是kb,所以这边需要乘以1024

148 cutMax = cutMax * 1024;149 System.out.println("总截取最大值:" +cutMax);150 singleCut = singleCut * 1024;151 System.out.println("单个截取最大值:" +singleCut);152

153 if (null !=regexStr) {154 //转换正则

155 regex =Pattern.compile(regexStr);156 }157

158 }159 }160 }

View Code

使用说明:

在flume启动配置文件增加以下内容:

#匹配时间并转换为时间戳到header中

a1.sources.tail.interceptors.i2.type=org.apache.flume.custom.MultInterceptor$Builder

#正则表达式,按需求定

a1.sources.tail.interceptors.i2.regex=(((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29))

#开启日志长度截取标志,默认true,开启

a1.sources.tail.interceptors.i2.cutFlag = true

#最大截取字符串长度,整数,尽量控制在2M以内,单位:kb,1M=1024

a1.sources.tail.interceptors.i2.cutMax = 2048

#单个截取字符串长度,整数,尽量控制在1.5M以内,单位:kb,1M=1024

a1.sources.tail.interceptors.i2.singleCut=1024

a1.sources.tail.interceptors.i2.serializers=se1

a1.sources.tail.interceptors.i2.serializers.se1.type=org.apache.flume.interceptor.RegexExtractorInterceptorMillisSerializer

a1.sources.tail.interceptors.i2.serializers.se1.name=timestamp

a1.sources.tail.interceptors.i2.serializers.se1.pattern=yyyy-MM-dd

参考实现:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值