Java 将Log4j输出写入HDFS

Java 将Log4j输出写入HDFS,java,hadoop,log4j,hdfs,Java,Hadoop,Log4j,Hdfs,是否有人试图将日志文件直接写入Hadoop分布式文件系统 如果是,请回答如何实现这一点。 我想我必须为它创建一个Appender 这是路吗? 我需要以特定的时间间隔将日志写入文件,并在稍后阶段查询该数据。我建议用于此任务。有。通过这种方式,您可以将日志发送到Flume,它会将日志写入HDFS。这种方法的好处是,Flume成为与HDFS的单点通信。Flume使添加新数据源变得很容易,而无需编写一堆代码来与HDFS反复交互 标准log4j(1.x)不支持写入HDFS。但幸运的是,log4j很容易扩展

是否有人试图将日志文件直接写入Hadoop分布式文件系统

如果是,请回答如何实现这一点。 我想我必须为它创建一个Appender

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

我建议用于此任务。有。通过这种方式,您可以将日志发送到Flume,它会将日志写入HDFS。这种方法的好处是,Flume成为与HDFS的单点通信。Flume使添加新数据源变得很容易,而无需编写一堆代码来与HDFS反复交互

标准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源代码,并查看AppenderSkleton是如何定义的,它将为您提供那里的所有信息。祝你好运

注意:写入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;
    }

}

两年后,有没有人知道如何不用水槽来做这件事?在我的例子中,日志甚至不够长,不需要它