启动flume
flume启动master 日志输出路径
starting master, logging to/home/demo/flume_output/log/flume/flume-demo-master-master.out
如果将master,node,和collector分出来的话,需要按照功能区分的服务器上启动不同的命令,具体命令如下:
Flume master //启动master
Flume node //启动node Flumenode_nowatch //启动node 但不启动watchdog。
Flume node/node_nowatch –n collector //启动collector
1.在远程登录服务器的时候,开了3个ssh客户端
分别启动master,node,最后一个负责执行flume shell(用于连接master[flume是基于zookeeper文件系统的分布式日志采集器,所以flume shell操作跟zookeeper非常相似])
2.执行启动 flume master 和 flume node报错。(已解决)[原因是未设置环境变量]
设置环境变量为:flume-env.sh
内容如下:
export FLUME_HOME=/opt/flume
export FLUME_CONF_DIR=/opt/flume/conf
exportFLUME_LOG_DIR=/home/demo/flume_output/log/flume
exportFLUME_PID_DIR=/home/demo/flume_output/run/flume
Flume web页面查看端口号
http://localhost:35871/flumemaster.jsp // 访问主机页面
http://localhost:35862/flumeagent.jsp // 访问node管理界面
http://localhost:35863/flumeagent.jsp // 访问collector
监听、收集文件
exec mapDataNode1(物理节点名称) fooNode1(逻辑节点名称) //首先映射物理节点和逻辑节点,也就是先将要给搜集日志的物理节点设置一个逻辑节点名称
//然后设置逻辑节点要搜集日志的文件夹或者文件
exec configfooNode1 fooflow'tail("/opt/flume/testFlumeFileInfo/testAgentLog")' 'agentE2EChain("node1")'
exec config fooNode1 fooflow'tailDir("/home/hadoop/system/logs/flume")''agentE2EChain("DataNode1","DataNode2","DataNode3")'
//最后把搜集到的日志发送到目标文件夹或者hdfs上
exec configDataNode1 fooflow collectorSource 'collectorSink("hdfs://NameNode:9000/flume/collected","foo")'
备注:一个物理节点可以映射多个逻辑节点,也就是说一个服务器上可以采集多块日志文件目录。然后到具体的跟踪日志文件的时候就能同时进行对多个agent节点进行日志采集。最后执行收集文件,就可以把搜集的日志文件汇总到最终的目标地点。
值得注意的是。在没有更改配置文件的时候,默认导入hdfs的格式是非常乱的。里面有很多暂时用不上的参数,比如说要采集的原日志文件中只有nihao这几个字母,但是导入到hdfs中后就会出现一大堆东西,比如说: /u000,…body….timestamp…等
如果只想在hdfs中写入原有日志的内容,就把collector format的参数改成”raw”即可
如果要取消getconfigs里面的agent 到 collector上的映射。执行 exec decommission node1
即可
flume日志动态跟踪
当被监控的日志文件夹里新增一个文件的时候:
如果该文件内容为空,那么将不写入最终的目标路径(hdfs)
如果创建了一个新文件,并且新文件里有内容的话,那么最终collector将收集被监控的文件夹里的新文件,然后将文件以数据流的形式做传递agent->collector->hdfs
跟踪写入到hdfs时的状态发现:
当被跟踪的文件夹里有新文件的时候,hdfs没有创建文件,当新创建的文件夹写入内容后,hdfs状态开始发生变化,首先观察到hdfs会新增一个tmp临时文件,当文件写入完成后,tmp文件会被移除,那么hdfs里将出现一个新增的hdfs文件。
Flume格式化输入的日志文件
参考过有关博客资料后,发现如果想要格式化输入的日志文件信息导入到hdfs中,需要修改配置文件,并且自己手写格式化jar包,并将jar包相应的部署到服务器上。
以下是参考的资料:
提取tailSrcFile中字串,将其添加到Event的元数据中,在Hadoop中建立符合Hive分区规范的目录层次。
以PaserTailFile为例:
1、Hive创建表指定Hadoop中文件目录(分区上层目录),设置好分区信息
eg:
create table if not exists test(
id int,
name string
)
partitioned by(school string,class int )
row format delimited fields terminated by "\t"
location "/data/hivedata/student/";
2、collector配置
exec config ******* 'collectorSource''{ParserTailFileDecorator("(.+)_(.+)_(.+)_(") =>collectorSink("hdfs://*****:9000/******/%{gameName}/%{logType}/rid=%{serverId}/logdate=%{dateStr}","%{tailSrcFile}-")}'
其中ParserTailFileDecorator第一个参数为正则表达式,其余参数为对应元组的名字
3、agent配置
exec config *******'tailDir("*******","(.+)_(.+)_(.+)_(.+)('{value("gameName","******") =>agentE2EChain("******","*****","******")}'
4、plugin
build.xml:
<?xml version="1.0"?>
<project name="flume-ParserTailFile" default="jar">
<property name="javac.debug"value="on"/>
<property name="flume.base"value="/home/hadoop/flume"/>
<pathid="classpath">
<pathelementlocation="${flume.base}/build/classes"/>
<filesetdir="${flume.base}/lib">
<includename="**/guava*.jar"/>
<includename="**/log4j-*.jar"/>
<includename="**/slf4j-*.jar"/>
</fileset>
<filesetdir="${flume.base}">
<includename="flume-*.jar"/>
</fileset>
<pathelementlocation="${flume.base}/lib/"/>
</path>
<targetname="jar">
<mkdir dir="build"/>
<mkdirdir="build/classes"/>
<javac srcdir="./src" destdir="build/classes"debug="${javac.debug}">
<classpath refid="classpath"/>
</javac>
<jarjarfile="ParserTailFile.jar" basedir="build/classes"/>
</target>
<targetname="clean">
<echo message="Cleaninggenerated files and stuff"/>
<deletedir="build"/>
<deletefile="ParserTailFile.jar"/>
</target>
</project>
src\ParserTailFile\ParserTailFileDecorator.java:
package ParserTailFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.*;
import java.util.HashMap;
import java.util.Map;
import com.cloudera.flume.conf.Context;
import com.cloudera.flume.conf.SinkFactory.SinkDecoBuilder;
import com.cloudera.flume.core.Event;
import com.cloudera.flume.core.EventImpl;
import com.cloudera.flume.core.EventSink;
import com.cloudera.flume.core.EventSinkDecorator;
import com.cloudera.util.Pair;
import com.google.common.base.Preconditions;
public class ParserTailFileDecorator<S extendsEventSink> extends EventSinkDecorator<S> {
public ParserTailFileDecorator(S s,String ...argvs) {
super(s);
_valArr = argvs.clone();
}
@Override
public void append(Event e) throws IOException, InterruptedException {
Map<String,byte[]> parserAttrs = newHashMap<String,byte[]>(); // 创建一个新的Map,
parserAttrs.putAll(e.getAttrs()); // e.getAttrs为只读
if (e.getAttrs().containsKey("tailSrcFile"))
{
String tailSrcFile = newString(parserAttrs.get("tailSrcFile"));
int len = _valArr.length;
Pattern pattern =Pattern.compile(_valArr[0]);
Matcher matcher =pattern.matcher(tailSrcFile);
if (matcher.matches()&& matcher.groupCount() >= len - 1)
{
for (inti=1; i < len; i++)
{
parserAttrs.put(_valArr[i],matcher.group(i).getBytes());
}
}
}
EventImpl e2 = newEventImpl(e.getBody(),
e.getTimestamp(),e.getPriority(),e.getNanos(), e.getHost(),
parserAttrs);
super.append(e2);
}
public static SinkDecoBuilder builder() {
return new SinkDecoBuilder() {
@Override
public EventSinkDecorator<EventSink>build(Context context,
String... argv) {
Preconditions.checkArgument(argv.length>= 2,
"usage:ParserDecorator(\"regex\",[groupName1,[groupName2,...]])");
returnnew ParserTailFileDecorator<EventSink>(null,argv);
}
};
}
public static List<Pair<String, SinkDecoBuilder>>getDecoratorBuilders() {
List<Pair<String, SinkDecoBuilder>> builders =
new ArrayList<Pair<String,SinkDecoBuilder>>();
builders.add(new Pair<String,SinkDecoBuilder>("ParserTailFileDecorator",
builder()));
return builders;
}
private String[] _valArr;
}
代码参考HelloWorld和flume源码自身相关插件修改
编译后,将得到的ParserTailFile.jar 置于flume/lib下,并修改conf/flume-site.xml文件
<property>
<name>flume.plugin.classes</name>
<value>ParserTailFile.ParserTailFileDecorator</value>
<description>Comma separated list ofplugins</description>
</property>
由于插件只在collector中使用,故ParserTailFile.jar 只需放到master和collector端,而agent端不用放