一、分析Log4j向flume发送日志的过程
按照前述调试过程,理清Log4j向flume发送日志所经过的过程,如下所示:
首先在初始化日志类时,就需要读取配置文件信息,并对其进行解读定位,关键是用到了org.apache.flume.clients.log4jappender.Log4jAppender类。在类初始化过程中,重点对该类进行调用,使得log4j在输出时可以通过netty,输出到相应的目标当中。
private static final Logger logger = LoggerFactory.getLogger(MyTest.class);
初始化过程中其调用关系为log4j->log4jAppender->RpcClientFactory ->NettyAvroRpcClient,如下图所示
可以看出,log4j将日志直接输送到flume当中,同发送到文件、console等appender中一样,flume在其源码过程中,特意增加Log4jAppender类来解决相关的传送问题。
logger.info("Now the time is:{}",String.valueOf(new Date().getTime()));
log4j在输出的时候调用了log4jAppender通过netty将相关数据传递到flume中,有关log4j的如何调用Appender网上相关分析很多,大家可以自行搜索。
二、log4jAppender分析
有关log4j的Appender自定义开发可以参考这里,该文详细介绍了log4j的调用机理、结构关系及自定义Appender需要注意的事项,log4j能够直接输出日志到flume,核心就在于flume源码中提供了自定义的log4jAppender来解决这一问题。
1、继承log4j公共的基类:AppenderSkeleton
public class Log4jAppender extends AppenderSkeleton {
private String hostname;
private int port;
……
2、重写打印日志核心方法:abstract protected void append(LoggingEvent event);
@Override
public synchronized void append(LoggingEvent event) throws FlumeException{
//If rpcClient is null, it means either this appender object was never
//setup by setting hostname and port and then calling activateOptions
//or this appender object was closed by calling close(), so we throw an
//exception to show the appender is no longer accessible.
if (rpcClient == null) {
String errorMsg = "Cannot Append to Appender! Appender either closed or" +
" not setup correctly!";
LogLog.error(errorMsg);
if (unsafeMode) {
return;
}
throw new FlumeException(errorMsg);
}
……
3、初始化加载资源:public void activateOptions(),
@Override
public void activateOptions() throws FlumeException {
Properties props = new Properties();
props.setProperty(RpcClientConfigurationConstants.CONFIG_HOSTS, "h1");
props.setProperty(RpcClientConfigurationConstants.CONFIG_HOSTS_PREFIX + "h1",
hostname + ":" + port);
props.setProperty(RpcClientConfigurationConstants.CONFIG_CONNECT_TIMEOUT,
……
这里最关键的是在参数初始化过程中初始化了netty连接,这也是flume-NG一个比较大的改动,使用了JBOSS的netty来完成传输任务。
其他如释放资源:public void close();是否需要按格式输出文本:public boolean requiresLayout() 等等在类中都有体现,可以进一步进行仔细的分析。