|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
[Java] Come fare un log parser che simula tail -f?
Ciao a tutti. Avrei bisogno di un consiglio su come realizzare l'oggetto del topic. Fin'ora non ho mai scritto programmi che non utilizzassero gli stream per leggere da file di input, mentre ora avrei bisogno di:
mettermi in "tail" su un certo log possibilmente filtrare la roba che viene effettivamente caricata in memoria parsare la roba che viene caricata in memoria Il punto 3 è ok in quanto è virtualmente analogo a ciò che ho gia, i primi due sono più oscuri. Qualcuno mi sa indicare una libreria o qualcosa di utile? Grazie, TD |
|
|
|
|
|
#2 |
|
Bannato
Iscritto dal: Jan 2003
Città:
Messaggi: 4423
|
...mi verrebbe da consigliare l'uso di librerie ssh come le jsch e catturare l'output della console...
...ciao... |
|
|
|
|
|
#3 |
|
Bannato
Iscritto dal: Jan 2003
Città:
Messaggi: 4423
|
...ma a volte la soluzione è piu' banale...
Codice:
public class Tail {
public static void main(String[] args) {
new Tail("c:/test.txt");
}
public Tail(String file){
try{
Reader fileReader = new FileReader(file);
BufferedReader input = new BufferedReader(fileReader);
String line = null;
while (true) {
if ((line = input.readLine()) != null) {
System.out.println(line);
continue;
}
try {
Thread.sleep(1000L);
} catch (InterruptedException x) {
Thread.currentThread().interrupt();
break;
}
}
input.close();
}catch(Exception e){
System.out.println(e);
}
}
}
|
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
Innanzitutto grazie mille perchè dovrebbe andare bene!
Avrei però un paio di domande... 1) immagino che non sia possibile evitare di fare polling ogni x secondi, ma innescare una read solo quando lo stato del file cambia? 2) scusa ma dove vai di next() sulla linea che leggi? EDIT: l' ho provato e questo è quello che fa... ho scritto x y z su un file, e un programma ke scrivesse sullo stesso file x y z a b c Ho lanciato prima il programma di tail, che mi ha quindi stampato x y z dato che nel file erano gia presenti. Poi ho lanciato lo scrittore, che è andato a sovrascrivere il precedente file, tuttavia riscrivendo i primi 3 caratteri identici a quelli che c'erano prima. Con mio grande stupore ho notato che il programma di tail però NON li ha ristampati, ha stampato solo i nuovi, quindi x y z a b c mentre mi sarei per lo meno aspettato x y z x y z a b c Umm, sono un po' confuso... EDIT2: il continue serve a non mandare il thread in wait finchè ho linee da processare, giusto? Ultima modifica di tylerdurden83 : 01-08-2008 alle 21:42. |
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
mi sorge un dubbio, non è che rilegge il log dall'inizio?...
|
|
|
|
|
|
#6 | |
|
Bannato
Iscritto dal: Jan 2003
Città:
Messaggi: 4423
|
Quote:
...ciao... |
|
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
Quote:
anyway, ho una domanda: Reader fileReader = new FileReader(log); BufferedReader input = new BufferedReader(fileReader); String line = null; while (true) { if ((line = input.readLine()) != null) { se non ho capito male, il BufferedReader legge tutto il file di input, readLine ne legge riga per riga, sia quelle già presenti al lancio che quelle che si aggiungono successivamente, però alla fine input contiene una bufferizzazzione di tutto il log, anche quando, una volta letto tutto, resto in ascolto e quindi catturo solo le nuove righe. In pratica, se il file di input è un log enorme, lo bufferizza, legge e lavora, ma quando si mette effettivamente in tail, non svuota il buffer con tutta la roba preesistente... |
|
|
|
|
|
|
#8 | |
|
Member
Iscritto dal: Mar 2007
Messaggi: 298
|
Quote:
Il codice di ally dovrebbe funzionare bene, l'unico dettaglio è che legge sempre tutto il file, mentre il tail -f apre il file "dalla fine", non scoda tutto il contenuto. Una variazione semplice che tenga questo di conto potrebbe essere: Codice:
public class TailLogger {
public static void main(String[] args) throws Exception {
new TailLogger("C:/test.txt");
}
public TailLogger(String file) {
try{
FileInputStream fs = new FileInputStream(file);
fs.skip(fs.available());
Reader fileReader = new InputStreamReader(fs);
BufferedReader input = new BufferedReader(fileReader);
String line = null;
while (true) {
if ((line = input.readLine()) != null) {
System.out.println(line);
continue;
}
try {
Thread.sleep(1000L);
} catch (InterruptedException x) {
Thread.currentThread().interrupt();
break;
}
}
input.close();
}catch(Exception e){
System.out.println(e);
}
}
}
|
|
|
|
|
|
|
#9 | |
|
Bannato
Iscritto dal: Jan 2003
Città:
Messaggi: 4423
|
Quote:
...ciao... |
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
Grazie di nuovo ad entrambi per i consigli!
La storia del leggere tutto il log, di per sè, direi che mi farebbe anche comodo, ti spiego da dove m'è sorto quel quesito però. In pratica, lanciando il jar sotto windows, e dandogli in pasto un log di prova con una 30 di entry, vedo ke il processo occupa sui 17 mega di ram. Mentre, lanciandolo sotto unix, e dandogli in pasto un log di migliaia di entry (log che comunque pesava max 10 mega), il processo inspiegabilmente occupa 623 mega! Tu mi dirai, se pure bufferizzasse tutto il log da 10 mega, come ci arriva a 600+? Non ne ho idea ad essere sincero, il jar è lo stesso, cambiano solo il log e l'SO... Per quanto riguarda il mio primissimo quesito posto, cioè come si spostasse senza usare una funzione next(), solo ora ho trovato una spiegazione, le api potrebbero spiegare un pochino meglio cosa fa esattamente readline() invece di dire solo legge una riga... |
|
|
|
|
|
#11 |
|
Member
Iscritto dal: Mar 2007
Messaggi: 298
|
Riguardo al next(), il reader non è un Iterator e dunque non c'è motivo per cui dovrebbe avere una funzione next(). Quasi tutte le API di I/O di Java usano degli stream, ed i Reader hanno dunque la logica di uno stream (leggi lo stream andando in avanti, quindi quando leggi una riga con readLine() il puntatore del file si sposta di conseguenza e la prossima lettura parte da dove è rimasta la precedente). E' poco ovvio ma quando ci hai fatto l'abitudine non ci pensi più.
Per quanto riguarda l'utilizzo di memoria, i fattori possono essere tanti, JVM diverse e diversa gestione della garbage collection e quant'altro. In ogni caso ti confermo che, nella jvm 1.5, il BufferedReader usa una cache di 8kb, ho verificato nella sorgente della libreria. Direi dunque che il problema sia che per ogni lettura che fai crei da qualche parte un oggetto String che contiene la riga letta. Prova a ridurre la quantità di memoria per la vm (opzione -xmx), metti una quantità piccola, 30M o giù di lì, e vedi come va. |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
Allora, il comando per forzare il processo ad occupare max 30 mega è andato bene, anche se alla fine facendo TOP mi dice sui 34, comunque meglio di 600!
Mi sfugge ancora una cosa sugli stream. Metti che creo lo stream di un file, salta il contenuto pre-esistente e si mette in tail. Se da shell faccio > nomelog.log, il programma rimane running ma non leggerà mai più da quel log... |
|
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
UPDATE:
ragazzi, ho di nuovo bisogno del vostro aiuto. Ho messo su l'applicazione. Avendo necessità di mettermi in tail su due log diversi ho fatto in modo di creare un thread per ogni log, che si mette in while (true) { if ((line = input.readLine()) != null) { su di essi, così come mi avevate suggerito. Ulteriore complicazione era la rotazione dei log una volta raggiunta una certa dimensione, per cui ho messo un controllo, se la dimensione precedente è > della corrente rigrea lo stream etc, e sta funzionando. Il problema enorme è però che si perde qualche riga. Mi spiego, facendo dei controlli rispetto ai log originali, mettendo delle print su un nuovo log subito dopo la if ((line = input.readLine()) != null) { mi sono accorto che alcune righe non le ha proprio lette. So che è difficile debuggare così, le sole cose che vi posso dire sono: - le righe perse non sono la prima o l'ultima di un nuovo log dopo aver ruotato, ma al centro di log da cui ha letto la riga prima e quella dopo - i thread non cadono, ho messo un controllo periodico (isAlive) - il processo non sfora mai la memoria impostata dalla virtual machine come mi avete detto di fare. A parte che se non ho capito male dovrebbe lanciare un'eccezione qualora ciò avvenga, ad ogni modo non si è mai avvicinato manco lontanamente al max heap size memory impostato - ovviamente il programma non genera nessuna eccezione, nè tantomeno cade mai Ho deciso quindi di fare una prova di "stress" sulla mia macchina locale (windows, java 1.6 - mentre la macchina di lavoro è unix, java 1.5, sto compilando sulla mia con l'opzione -target 1.5). Ho pensato potesse essere un problema di troppe entry nello stesso istante nel log su cui sono in tail, così ho scritto un'applicazioncina che mi spara sui due log 2 righe, il tutto in un ciclo for i=0 i<15.000, in 3-4 secondi spara 15.000 righe per log, eppure non ne ha persa manco una. Non so più che pensare, nè che prove fare. L'unica cosa che non ho provato ancora tra le 1000 che ho provato è sostituire if ((line = input.readLine()) != null) con if (bufferedReader.ready()==true) { line = input.readLine(); Grazie 1000 a tutti per l'aiuto, TD |
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Nov 2004
Messaggi: 691
|
Boh, ho fatto altre prove...
Ho messo il jar in ascolto su un log mio usato per i test, vuoto. Ho provato, sul server unix, a sparare con un altro jar 15000 righe una alla volta, e non ha dato problemi. Ho provato a spararle 500 alla volta, cioè creando una stringa che concat("\n") e concat(riga successiva), quindi in una sola write sul log di test ho scritto 500 righe, anche in questo caso nessun problema.... Non ho proprio più idea di dove andare a parare....fin'ora in ogni test non ha mai perso una sola riga, anche se i test sono stati molto più "stressanti" rispetto ai log su cui sta in tail normalmente, eppure pare perdere dati solo da quelli.... |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 00:02.




















