自定义组件
Flume可以对部分组件实现自定义,自定义时根据Flume版本导入flume-ng-core
自定义Source
getChannelProcessor().processEvent(event);
自定义source主要是调用channelProcessor将event写入channel之中。
package cn.lpc.myflume;
/**
* 项目名:MyFlume
* 描述:自定义Source
* @author : Lpc
* @date : 2019-12-05 13:52
**/
public class MySource extends AbstractSource implements Configurable, PollableSource {
String field;
public void configure(Context context) {
field=context.getString("field","default");
}
public Status process() throws EventDeliveryException {
// 创建事件头部信息
try {
HashMap<String, String> headMap = new HashMap<String, String>();
SimpleEvent event = new SimpleEvent();
for (int i = 0; i < 10; i++) {
event.setBody((field+i).getBytes());
event.setHeaders(headMap);
getChannelProcessor().processEvent(event);
Thread.sleep(10000);
}
} catch (Exception e) {
e.printStackTrace();
return Status.BACKOFF;
}
return Status.READY;
}
public long getBackOffSleepIncrement() {
return 0;
}
public long getMaxBackOffSleepInterval() {
return 0;
}
}
在写Source时观察了一下source的put流程
- agent在启动时,调用了PollableSourceRunner.start()。因此source要PollableSource接口。
- 启动一个线程,这个线程为PollingRunner,PollingRunner负责启动和停止Source,由 PollingRunner初始化Source。
- 一旦有新的数据,调用source封装event,一个source必须实现 process(),这个方法是最核心的方法,它负责发现新的数据,存储到event!
- 调用getChannelProcessor().processEventBatch(events);
- 在processEventBatch()中,先调用拦截器,处理Events
- 使用channelselector获取当前source对应的必须的channel,向channel的dataQuene中,放入处理好的event
- 循环每一个event!,调用channel.put(event); 调用Channel中的transaction对象的doPut(event);将event移动到putList中!
- 一批event放完之后,执行事务的commit();清空putlist(缓存)!
- 如果发生异常,调用rollback(),将之前放入到channel中的一批事务中的event回滚。
自定义Sink
package cn.lpc.myflume;
import org.apache.flume.*;
import org.apache.flume.conf.Configurable;
import org.apache.flume.sink.AbstractSink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 项目名:MyFlume
* 描述:自定义sink
*
* @author : Lpc
* @date : 2019-12-05 14:36
**/
public class MySink extends AbstractSink implements Configurable {
private Logger logger = LoggerFactory.getLogger(MySink.class);
public Status process() throws EventDeliveryException {
Status status = Status.READY;
//获取管道
Channel ch=getChannel();
//获取事务
Transaction tr = ch.getTransaction();
try {
//开启事务
tr.begin();
Event take = ch.take();
if (take==null){
tr.rollback();
return Status.BACKOFF;
}else {
logger.info(take.getBody().toString()+"sink");
tr.commit();
}
} catch (ChannelException e) {
e.printStackTrace();
tr.rollback();
status= Status.BACKOFF;
}finally {
if (tr!=null){
tr.close();
}
}
return status;
}
public void configure(Context context) {
}
}
sink的事务最为致命
自定义拦截器
package cn.lpc.myflume;
/**
* 项目名:MyFlume
* 描述:自定义拦截器,配合自定义的source使用,作用是在每条语句后加一
*
* @author : Lpc
* @date : 2019-12-05 14:14
**/
public class MyInterceptor implements Interceptor {
public void initialize() {
}
public Event intercept(Event event) {
byte[] body = event.getBody();
String sBody = new String(body);
event.setBody( (sBody+"intercept").getBytes());
return event;
}
public List<Event> intercept(List<Event> events) {
for (Event event : events) {
intercept(event);
}
return events;
}
public void close() {
}
public static class Builder implements Interceptor.Builder {
private boolean preserveExisting;
private String key;
private String value;
public void configure(Context context) {
}
public Interceptor build() {
return new MyInterceptor();
}
}
}
实现Interceptor接口。initialize和close分别再拦截器初始和关闭时调用。初始化时可以实现configorable接口。调用配置的参数。主要的方法是intercept(),处理一个event。在最后还需要实现Builder。flume通过调用builder获取拦截器对象。配置时为a1.sources.s1.interceptors.i1.type="全类名$Builder"