Flume自定义拦截器的编写

我们Source中读到的数据往往会被分为几个不同的日志种类 然后通过Sink发送到不同的节点去进行处理 。 那么对于同一个Source中读到的不同的数据 我们往往根据读到的数据中的一些特定的字段值或者其他的特征值 来将他们区分为不同的日志种类 在Flume中我们需要自定义拦截器,然后通过ChannelSelector(Channel选择器)来将同一个Source中的不同类型的日志数据 进行一次分类 将他们写入不同的Channel中

拦截器的思想 : Source中读取到的Event事件 我们通过获得这个Event的body部分(也就是该Event的实际数据),通过判定这个body中是否包含某一个关键字(根据不同的业务决定不同的选择方法 这个示例就是通过是否包含“Hello”关键字) 来将他们分为两个不同的种类。 那么Flume的ChannelSelector 是怎么判定这个Event写入哪个Channel中呢 是通过这个Event的Header中包含的信息 (需要我们自己在运行文件中定义) 所以我们对这个Event加入Header信息 对不同类型的日志数据指定不同的关键字 即可

Java代码:

首先需要带入依赖


        
            org.apache.flume
            flume-ng-core
            1.7.0
        
    
package com.jee.interceptor;

import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class MyInterceptor implements Interceptor {

    //通过Interceptor拦截器拦截后 发送给ChannelSelector的Event列表
    private List events;

    //初始化方法
    public void initialize() {
        events = new ArrayList();
    }

    public Event intercept(Event event) {
        //获得Event的头部信息
        Map headers = event.getHeaders();
        //获得Event的body信息
        byte[] body = event.getBody();
        String content = new String(body);
        //如果该Event中包含Hello关键字 那么就是就将该Event的header部分添加上一个{"type","one"}的键值对
        //如果不包含 就将该Event的header部分添加上一个{"type","two"}的键值对
        //这个键值对的key和value都可以随意定义 只需要在Flume的运行文件中 设置相应的key 和 value即可
        if(content.contains("Hello")){
            headers.put("type","one");
        }else{
            headers.put("type","two");
        }
        return event;
    }

    public List intercept(List list) {
        //清空事件数组  防止将上一次的结果也一起添加(很重要 防止重复)
        events.clear();
        for(Event event : list){
            //将通过拦截器的Event加入到列表中
            events.add(intercept(event));
        }
        return events;
    }

    public void close() {

    }


    //自定义的静态内部类 必须要写  因为运行文件需要这个自定义的内部类 
    //它必须实现Interceptor.Builder接口
    public static class Builder implements Interceptor.Builder{

        //返回上面我们自己定义的拦截器
        public Interceptor build() {
            return new MyInterceptor();
        }

        public void configure(Context context) {

        }
    }
}

Flume的运行文件 :
我们可以去http://flume.apache.org/官网中就找 里面有详细的官方案例 编写Flume的运行文件 建议去官网中copy一份 然后按自己需求进行更改即可

# Name the components on this agent
a1.sources = r1
a1.sinks = k1 k2
a1.channels = c1 c2

# Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = hadoop2
a1.sources.r1.port = 44444

# Describe the sink
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = hadoop3
a1.sinks.k1.port = 4141
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = hadoop4
a1.sinks.k2.port = 4142

#Interceptor
a1.sources.r1.interceptors = i1
#type就是我们自己代码中的自定义拦截器的全类名
a1.sources.r1.interceptors.i1.type = com.jee.interceptor.MyInterceptor$Builder

#Channel selector
#Channel选择器默认是replicating 将该source中的数据都复制到所有的channel中 
#因为我们想要实现分类的效果 所以需要使用multiplexing
a1.sources.r1.selector.type = multiplexing
#header的值就是我们代码中写入header中的key
a1.sources.r1.selector.header = type
#mapping的值就是我们代码中写入header中的value
a1.sources.r1.selector.mapping.one = c1
a1.sources.r1.selector.mapping.two = c2


# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
a1.channels.c2.type = memory
a1.channels.c2.capacity = 1000
a1.channels.c2.transactionCapacity = 100


# Bind the source and sink to the channel
a1.sources.r1.channels = c1 c2
a1.sinks.k1.channel = c1
a1.sinks.k2.channel = c2

你可能感兴趣的:(Flume自定义拦截器的编写)