将Log4j输出写入HDFS

时间:2013-05-07 13:21:14

标签: java hadoop log4j hdfs

是否有人尝试直接 log4j 日志文件

如果是,请回复如何实现此目的。 我想我必须为它创建一个Appender。

这是这样的吗? 我的必要性是以特定的间隔将日志写入文件,并在稍后阶段查询该数据。

2 个答案:

答案 0 :(得分:8)

我建议使用Apache Flume执行此任务。有Flume appender for Log4j。这样,您将日志发送到Flume,并写入HDFS。这种方法的好处是Flume成为与HDFS的单点通信。 Flume可以轻松添加新数据源,而无需一次又一次地编写一堆代码与HDFS交互。

答案 1 :(得分:2)

标准log4j(1.x)不支持写入HDFS。但幸运的是,log4j很容易扩展。我编写了一个HDFS FileAppender来将日志写入MapRFS(与Hadoop兼容)。文件名可以是“maprfs:///projects/example/root.log”。它在我们的项目中运作良好。我提取代码的appender部分并将其粘贴到下面。代码段可能无法运行。但这会让你知道如何写你的appender。实际上,您只需要扩展org.apache.log4j.AppenderSkeleton,并实现append(),close(),requiresLayout()。有关更多信息,您还可以下载log4j 1.2.17源代码并查看如何定义AppenderSkeleton,它将为您提供所有信息。祝你好运!

注意:写入HDFS的另一种方法是将HDFS挂载到所有节点,这样就可以像写入本地目录一样编写日志。也许这是一种更好的实践方式。

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Layout;
import org.apache.hadoop.conf.Configuration;

import java.io.*;

public class HDFSFileAppender {
    private String filepath = null;
    private Layout layout = null;

    public HDFSFileAppender(String filePath, Layout layout){
        this.filepath = filePath;
        this.layout = layout;
    }

    @Override
    protected void append(LoggingEvent event) {
        String log = this.layout.format(event);
        try {
            InputStream logStream = new ByteArrayInputStream(log.getBytes());
            writeToFile(filepath, logStream, false);
            logStream.close();
        }catch (IOException e){
            System.err.println("Exception when append log to log file: " + e.getMessage());
        }
    }

    @Override
    public void close() {}

    @Override
    public boolean requiresLayout() {
        return true;
    }

    //here write to HDFS
    //filePathStr: the file path in MapR, like 'maprfs:///projects/aibot/1.log'
    private boolean writeToFile(String filePathStr, InputStream inputStream, boolean overwrite) throws IOException {
        boolean success = false;
        int bytesRead = -1;
        byte[] buffer = new byte[64 * 1024 * 1024];
        try {
            Configuration conf = new Configuration();
            org.apache.hadoop.fs.FileSystem fs = org.apache.hadoop.fs.FileSystem.get(conf);
            org.apache.hadoop.fs.Path filePath = new org.apache.hadoop.fs.Path(filePathStr);
            org.apache.hadoop.fs.FSDataOutputStream fsDataOutputStream = null;

            if(overwrite || !fs.exists(filePath)) {
                fsDataOutputStream = fs.create(filePath, overwrite, 512, 3, 64*1024*1024);
            }else{ //append to existing file.
                fsDataOutputStream = fs.append(filePath, 512);
            }

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                fsDataOutputStream.write(buffer, 0, bytesRead);
            }

            fsDataOutputStream.close();
            success = true;
        } catch (IOException e) {
            throw e;
        }
        return success;
    }

}