拦截器做什么呢?
以时间拦截器为例.会在Event的header中添加一个属性进去,属性的key叫做timestamp, value是当前的毫秒值.
问题是写到header然后呢?有啥用呢? 就是在比如说保存到hdfs上时,这个header中的时间戳的value可以作为文件夹的目录,这样就比较方便. 也可以比如说加到文件名上面.
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = timestamp
a1.sources.r1.interceptors.i1.header = timestamp
a1.sources.r1.interceptors.i1.preserveExisting = true
关键一步是在设置sink为hdfs的时候.%{timestamp}就可以取到拦截器中key对应的value的值了. 这样你的文件夹命名中就有了时间
hdfs://mypc01/test/%{timestamp}
举个例子
#设置名字关联通道
a1.sources = r1
a1.channels = c1
a1.sinks = s1
a1.sources.r1.channels = c1
a1.sinks.s1.channel = c1
#指定source的属性
a1.sources.r1.type = syslogtcp
a1.sources.r1.host = mypc01
a1.sources.r1.port = 10086
#指定一下拦截器. 设立三个拦截器
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = timestamp
a1.sources.r1.interceptors.i1.header = timestamp
a1.sources.r1.interceptors.i1.preserveExisting = true
#指定channel的属性
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
#指定sink的属性
a1.sinks.s1.type = hdfs
a1.sinks.s1.hdfs.path = hdfs://mypc01/test/%{timestamp}
# 如果想用时间戳拦截器设置的键值对消息头,那么下面的属性要设置false
a1.sinks.s1.hdfs.useLocalTimeStamp = false
a1.sinks.s1.hdfs.filePrefix = Flumadata
a1.sinks.s1.hdfs.fileSuffix = .log
a1.sinks.s1.hdfs.rollInterval = 30
a1.sinks.s1.hdfs.rollSize = 0
a1.sinks.s1.hdfs.rollCount = 0
# 下面三个属性是用于hdfs上的目录的滚动条件,如果想要使用,需要使用true, 禁止使用要改为false
a1.sinks.s1.hdfs.round = true
a1.sinks.s1.hdfs.roundValue = 2
a1.sinks.s1.hdfs.roundUnit = minute
# 如果想要使用纯文本文件DataStream,那么写格式需要使用Text
a1.sinks.s1.hdfs.fileType = DataStream
a1.sinks.s1.hdfs.writeFormat = Text
测试
echo "hello" | nc mypc01 10086
总而言之,拦截器就是可以把header中的kv对中的v 作为hdfs的目录名或者文件名.
host拦截器,static拦截器同理.
拦截器文档
如下,自定义拦截器,并依据body内容的不同设置不同的header键值对.
一般步骤如下
public class Myinter implements Interceptor {
@Override
public void initialize() {
}
@Override
public Event intercept(Event event) {
byte[] body = event.getBody();
if (body[0] > 48 && body[0] <= 57) {
//如果是body开头是数字,设置header的type属性为number
event.getHeaders().put("type", "number");
} else if (body[0] >= 65 && body[0] <= 90 || (body[0] >= 97 && body[0] <= 122)) {
//如果是body开头是字母,设置header的type属性为character
event.getHeaders().put("type", "character");
} else {
//如果是body开头是其他,设置header的type属性为其他
event.getHeaders().put("type", "others");
}
return event;
}
@Override
public List<Event> intercept(List<Event> list) {
for (Event event : list) {
intercept(event);
}
return list;
}
@Override
public void close() {
}
public static class MyBuilder implements Builder {
/**
* 此方法按时框架自己帮我们创建拦截器的方法
*
* @return
*/
@Override
public Interceptor build() {
return new Myinter();
}
@Override
public void configure(Context context) {
}
}
}
构造函数
private StaticInterceptor(boolean preserveExisting, String key, String value) {
this.preserveExisting = preserveExisting;
this.key = key;
this.value = value;
}
关键方法重写.重写了intercept方法,接收一个event,处理后再返回一个新的event.对event进行的处理就是给header添加了一个自定义的键值对.这个键值对是在写flume的方案时需要定义的. 也有一些是可以直接获取的,比如TimeStamp拦截器,就可以直接获取当前时间作为header使用.
public Event intercept(Event event) {
Map<String, String> headers = event.getHeaders();
if (this.preserveExisting && headers.containsKey(this.key)) {
return event;
} else {
headers.put(this.key, this.value);
return event;
}
}
event中header中的key是通过System.currentTimeMillis()获得的.
/**
* Modifies events in-place.
*/
@Override
public Event intercept(Event event) {
获得事件中的所有头信息,都是以key-value的形式存储
Map<String, String> headers = event.getHeaders();
if (preserveExisting && headers.containsKey(header)) {
// we must preserve the existing timestamp
} else {
//获取当前系统时间
long now = System.currentTimeMillis();
// //把时间戳放到头信息
headers.put(header, Long.toString(now));
}
return event;
}
本质就是修改了event的header,给里面添加了一个键值对.用来描述数据的来源,就是host相关信息.
/**
* Modifies events in-place.
*/
@Override
public Event intercept(Event event) {
Map<String, String> headers = event.getHeaders();
if (preserveExisting && headers.containsKey(header)) {
return event;
}
if (host != null) {
headers.put(header, host);
}
return event;
}
正则拦截器和以上稍有不同,是内event的body进行匹配判断,满足需求返回event,不满足返回null… 就相当于消失了. 或者说是一种过滤的功能.
public Event intercept(Event event) {
if (!this.excludeEvents) {
return this.regex.matcher(new String(event.getBody())).find() ? event : null;
} else {
return this.regex.matcher(new String(event.getBody())).find() ? null : event;
}
}