flume拦截器及自定义拦截器

拦截器做什么呢?

时间拦截器

以时间拦截器为例.会在Event的header中添加一个属性进去,属性的key叫做timestamp, value是当前的毫秒值.
flume拦截器及自定义拦截器_第1张图片
问题是写到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键值对.
一般步骤如下

  • 新建类实现 Interceptor接口
  • 重写 initialize,intercept,close方法,关键是如何设置header和body的值.header的类型为map,可以利用map的put方法写入键值对. body的类型是byte[].可以直接调用event对象的setbody方法.
  • 实现内部类Builder类,创建拦截器实例
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) {

        }
    }
}

内置拦截器StaticInterceptor.

构造函数

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;
        }
    }

TimeStamp拦截器

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;
  }

host拦截器

本质就是修改了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;
      }
  }

总结

  • 拦截器可以在数据进入channel前对数据进行处理.
  • 拦截器可以修改或添加event的body 或者header.
  • 自定义拦截器关键要重写intercept方法,然后修改或添加header or body的值,以满足自己的需求.
  • 拦截器中添加的header可以在sink下沉时文件夹or文件的命名中用到.

你可能感兴趣的:(flume,java,flume)