是否有人尝试直接将 log4j 日志文件
如果是,请回复如何实现此目的。 我想我必须为它创建一个Appender。
这是这样的吗? 我的必要性是以特定的间隔将日志写入文件,并在稍后阶段查询该数据。答案 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;
}
}