package org.apache.flume.source;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.EventDrivenSource;
import org.apache.flume.conf.Configurable;
import org.apache.flume.event.EventBuilder;
import org.apache.flume.instrumentation.SourceCounter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TailFileSource extends AbstractSource implements EventDrivenSource,
Configurable {
private static final Logger logger = LoggerFactory.getLogger(TailFileSource.class);
private SourceCounter sourceCounter;
private String pointerFile;
private String tailFile;
private long collectInterval;
private int batchLine;
private boolean batch;
private AtomicBoolean tailRun=new AtomicBoolean(true);
private AtomicLong cursor=new AtomicLong(0);
@Override
public void configure(Context context) {
if (sourceCounter == null) {
sourceCounter = new SourceCounter(getName());
}
pointerFile = context.getString("tailfile.pointer","cursor.pt");
tailFile = context.getString("tailfile.file","data.txt");
collectInterval=context.getLong("tailfile.collectInterval",3000L);
batchLine=context.getInteger("tailfile.batchLine",10);
batch=context.getBoolean("tailfile.batch",false);
}
@Override
public synchronized void start() {
super.start();
sourceCounter.start();
TailFile tf=new TailFile();
tf.addFileTailerListener(new FileTailerListener(){
@Override
public void newFileLine(List<Event> events) {
if(!events.isEmpty()){
getChannelProcessor().processEventBatch(events);
sourceCounter.incrementAppendBatchAcceptedCount();
sourceCounter.addToEventAcceptedCount(events.size());
}
}
@Override
public void newFileLine(Event event) {
getChannelProcessor().processEvent(event);
sourceCounter.incrementAppendAcceptedCount();
}
});
Thread t=new java.lang.Thread(tf);
t.setDaemon(true);
t.start();
}
@Override
public synchronized void stop() {
tailRun.set(false);
super.stop();
sourceCounter.stop();
}
protected interface FileTailerListener{
public void newFileLine(List<Event> events);
public void newFileLine(Event event);
}
protected class TailFile implements java.lang.Runnable{
private Set<FileTailerListener> listeners = new HashSet<FileTailerListener>();
public void addFileTailerListener(FileTailerListener l) {
this.listeners.add(l);
}
public void removeFileTailerListener(FileTailerListener l) {
this.listeners.remove(l);
}
@Override
public void run() {
long[] st=this.readPointerFile();
RandomAccessFile file=null;
boolean flag=true;
while(flag){
try {
File tf=new File(tailFile);
file = new RandomAccessFile(tf, "r");
if(st[0]==tf.lastModified()){
cursor.set(st[1]);
}else{
st[0]=tf.lastModified();
cursor.set(0);
}
flag=false;
} catch (Exception e) {
try {
logger.error(e.getMessage()+",will retry file:"+tailFile);
Thread.sleep(5000);
} catch (Exception e1) {
}
}
}
while(tailRun.get()){
try {
if(!this.sameTailFile(st[0])) {
logger.error("file change:"+tailFile);
File tf=new File(tailFile);
file = new RandomAccessFile(tf, "r");
st[0]=tf.lastModified();
cursor.set(0);
}
long fileLength =file.length();
if (fileLength < cursor.get()) {
cursor.set(fileLength);
}
if (fileLength > cursor.get()) {
file.seek(cursor.get());
String line = file.readLine();
int i=1;
if(batch){
java.util.List<Event> batchAl=new java.util.ArrayList<Event>(batchLine);
while (line != null) {
batchAl.add(EventBuilder.withBody(line.getBytes()));
if(i%batchLine==0) {
fireNewFileLine(batchAl);
batchAl.clear();
cursor.set(file.getFilePointer());
st[1]=cursor.get();
writePointerFile(st);
}
line = file.readLine();
i++;
}
if(!batchAl.isEmpty()){
fireNewFileLine(batchAl);
batchAl.clear();
cursor.set(file.getFilePointer());
st[1]=cursor.get();
writePointerFile(st);
}
}else{
while(line!=null){
fireNewFileLine(EventBuilder.withBody(line.getBytes()));
line = file.readLine();
}
cursor.set(file.getFilePointer());
st[1]=cursor.get();
writePointerFile(st);
}
}
Thread.sleep(collectInterval);
} catch (Exception e) {
}
}
try {
if(file!=null) file.close();
} catch (Exception e) {
}
}
private long[] readPointerFile(){
logger.info("read pointerFile:"+pointerFile);
java.io.ObjectInputStream ois=null;
long[] temp={0L,0L};
try {
ois=new java.io.ObjectInputStream(new java.io.FileInputStream(new File(pointerFile)));
temp[0]=ois.readLong();
temp[1]=ois.readLong();
} catch (Exception e) {
logger.error("can't read pointerFile:"+pointerFile);
} finally{
try {
if(ois!=null)ois.close();
} catch (Exception e) {
}
}
return temp;
}
private void writePointerFile(long[] temp){
logger.debug("write pointerFile:"+pointerFile);
java.io.ObjectOutputStream oos=null;
try {
oos=new java.io.ObjectOutputStream(new java.io.FileOutputStream(pointerFile));
oos.writeLong(temp[0]);
oos.writeLong(temp[1]);
} catch (Exception e) {
logger.error("can't write pointerFile:"+pointerFile);
}finally{
try {
if(oos!=null)oos.close();
} catch (Exception e) {
}
}
}
private boolean sameTailFile(long time){
return new File(tailFile).lastModified()==time?true:false;
}
protected void fireNewFileLine(List<Event> events) {
for (Iterator<FileTailerListener> i = this.listeners.iterator(); i.hasNext();) {
FileTailerListener l = i.next();
l.newFileLine(events);
}
}
protected void fireNewFileLine(Event event) {
for (Iterator<FileTailerListener> i = this.listeners.iterator(); i.hasNext();) {
FileTailerListener l = i.next();
l.newFileLine(event);
}
}
}
}
相关推荐
Flume-NG 安装与配置指南 Flume-NG 是一个分布式日志收集系统,能够从各种数据源中实时采集数据,并将其传输到集中式存储系统中。本文将指导您完成 Flume-NG 的安装和基本配置。 安装 Flume-NG 1. 先决条件:...
Flume-ng-1.6.0-cdh.zip 内压缩了 3 个项目,分别为:flume-ng-1.6.0-cdh5.5.0.tar.gz、flume-ng-1.6.0-cdh5.7.0.tar.gz 和 flume-ng-1.6.0-cdh5.10.1.tar.gz,选择你需要的版本。
flume-1.5.0-cdh5.3.6。 大数据日志收集工具 flume-1.5.0-cdh5.3.6。 大数据日志收集工具flume-1.5.0-cdh5.3.6。 大数据日志收集工具flume-1.5.0-cdh5.3.6。 大数据日志收集工具flume-1.5.0-cdh5.3.6。 大数据日志...
Flume-ng-sql-source是Apache Flume的一个扩展插件,主要功能是允许用户从各种数据库中抽取数据并将其传输到其他目的地,如Apache Kafka。在本案例中,我们讨论的是版本1.5.2的发布包,即"flume-ng-sql-source-...
Flume-ng-sql-source-1.5.2是Apache Flume的一个扩展,它允许Flume从SQL数据库中收集数据。Apache Flume是一个分布式、可靠且可用于有效聚合、移动大量日志数据的系统。"ng"代表"next generation",表明这是Flume的...
注意:flume-interceptor-1.0-SNAPSHOT.jar flume-interceptor-1.0-SNAPSHOT.jar flume-interceptor-1.0-SNAPSHOT.jar flume-interceptor-1.0-SNAPSHOT.jar flume-interceptor-1.0-SNAPSHOT.jar flume-interceptor-...
1. **bin** 目录:包含可执行脚本,如 `flume-ng` 和 `flume-agent`,用于启动、停止和管理 Flume 代理。 2. **conf** 目录:存放配置文件,例如 `flume.conf`,这是默认的配置文件,用户可以在这里定义数据流的结构...
flume-ng-sql-source-1.5.1 flume连接数据库 很好用的工具
"flume-ng-1.6.0-cdh5.5.0.tar.gz" 是 Apache Flume 的一个特定版本,具体来说是 "Next Generation" (ng) 版本的 1.6.0,与 Cloudera Data Hub (CDH) 5.5.0 发行版兼容。CDH 是一个包含多个开源大数据组件的商业发行...
flume-ng-sql-source-1.5.3.jar,flume采集mysql数据jar包,将此文件拖入FLUME_HOME/lib目录下,如果是CM下CDH版本的flume,则放到/opt/cloudera/parcels/CDH-xxxx/lib/flume-ng/lib下,同样需要的包还有mysql-...
包含flume-ng-sql-source-1.5.1&flume;-ng-sql-source-1.4.1 此内容均为网上下载
flume-ng-sql-source-1.5.2.jar从数据库中增量读取数据到hdfs中的jar包
flume断点续传覆盖jar,使用组件flume-taildir-source-1.9.0覆盖flume/bin目录下的jar即可
flume拦截器 保留binlog es、data、database、table、type字段 分区字段名称: eventDate 放入 /opt/cloudera/parcels/CDH/lib/flume-ng/lib目录重启flume即可
flume是一个日志收集器,更多详细的介绍可以参照官网:http://flume.apache.org/ flume-ng-sql-source实现oracle增量数据读取 有了这个jar文件即可从关系型数据库拉去数据到flume
Flume-ng 在 Windows 环境搭建并测试 + Log4j 日志通过 Flume 输出到 HDFS Flume-ng 是一个高可用、可靠、分布式的日志聚合系统,可以实时地从各种数据源(如日志文件、网络 socket、数据库等)中收集数据,并将其...
该压缩包“flume-ng-1.6.0-cdh5.7.0”是针对Cloudera Data Hub (CDH) 5.7.0 平台的Flume的特定版本,"ng"代表"Next Generation",意味着它是Flume的更新版本,提供了更先进的特性和性能优化。CDH是一个完整的、经过...
这个名为 "apache-flume-1.7.0-bin.tar.zip" 的压缩包包含 Apache Flume 的 1.7.0 版本的二进制文件。文件以 `.tar.gz` 格式压缩,这是一种常见的在 Unix-like 系统上使用的文件打包和压缩格式,它首先使用 `tar` ...
flume-ng-sql-source-1.4.1 flume采集mysql数据到kudu