lo standard log4j (1.x) non supporta la scrittura su HDFS. ma fortunato, log4j è molto facile da estendere. Ho scritto un HDFS FileAppender per scrivere il log su MapRFS (compatibile con Hadoop). il nome del file può essere qualcosa come "maprfs: ///projects/example/root.log". Funziona bene nei nostri progetti. Estrao la parte del codice dell'appender e la incollo qui sotto. i frammenti di codice potrebbero non essere in grado di essere eseguiti. ma questo ti darà l'idea di come scriverti appender. In realtà, è sufficiente estendere org.apache.log4j.AppenderSkeleton e implementare append(), close(), requireLayout(). per ulteriori informazioni, è anche possibile scaricare il codice sorgente di log4j 1.2.17 e vedere come è definito l'AppenderSkeleton, vi darà tutte le informazioni lì. in bocca al lupo!
nota: il metodo alternativo per scrivere su HDFS consiste nel montare l'HDFS su tutti i nodi, in modo da poter scrivere i registri proprio come scrivere nella directory locale. forse questo è un modo migliore in pratica.
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;
}
}
fonte
2017-10-28 02:38:39
due anni dopo qualcuno ha notizie su come farlo senza usare il canale? Nel mio caso i registri non sono neanche lontanamente abbastanza lunghi da averne bisogno – Irene