Java functionality for reading the tail of dynamically growing and rotating log files, inspired by the *nix command 'tail -f'.
Under development.
tail4J provides two main classes: Tail (low-level) and TailMinusF (high-level) running in an own thread.
Initially, this one outputs the last ten lines of /var/log/syslog to command line. All repeated calls to visit() in periods of 1000 msec will add those lines, that were created in the meantime.
package de.arthurpicht.tail4j.demo;
import de.arthurpicht.tail4j.Tail;
import java.io.File;
import java.io.IOException;
public class HelloWorld {
public static void main(String[] args) throws IOException, InterruptedException {
Tail tail = new Tail(new File("/var/log/syslog"));
while (true) {
tail.visit();
Thread.sleep(1000);
}
}
}
In real world applications, you will want to do some custom processing of log statements. In order to do so, implement the LogstatementProcessor interface and pass it to Tail on initialization.
package de.arthurpicht.tail4j.demo;
import de.arthurpicht.tail4j.LogstatementProcessor;
import de.arthurpicht.tail4j.Tail;
import java.io.File;
import java.io.IOException;
public class HelloWorld2 {
public static void main(String[] args) throws IOException, InterruptedException {
int nrOfLastLines = 5;
LogstatementProcessor logstatementProcessor = logStatement -> System.out.println("Here I could do some processing of \"" + logStatement + "\" ...");
Tail tail = new Tail(new File("/var/log/syslog"), nrOfLastLines, logstatementProcessor);
while (true) {
tail.visit();
Thread.sleep(1000);
}
}
}
Class TailMinusF provides a functionality for observing a specified file continuously by spawning an own thread.
Have a look on TailMinusFConfBuilder for full configuration capabilities.
package de.arthurpicht.tail4j.demo;
import de.arthurpicht.tail4j.TailMinusF;
import de.arthurpicht.tail4j.TailMinusFConfBuilder;
import java.io.File;
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
TailMinusFConfBuilder tailMinusFConfBuilder
= new TailMinusFConfBuilder()
.setFile(new File("/var/log/syslog"));
TailMinusF tailMinusF = new TailMinusF(tailMinusFConfBuilder.build());
tailMinusF.start();
Thread.sleep(60 * 1000);
tailMinusF.stop();
}
}
Just as shown for Tail, here again a custom LogstatementProcessor can be implemented.
package de.arthurpicht.tail4j.demo;
import de.arthurpicht.tail4j.LogstatementProcessor;
import de.arthurpicht.tail4j.TailMinusF;
import de.arthurpicht.tail4j.TailMinusFConfBuilder;
import java.io.File;
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
LogstatementProcessor logstatementProcessor = logStatement -> System.out.println("Here I could do some processing of \"" + logStatement + "\" ...");
TailMinusFConfBuilder tailMinusFConfBuilder
= new TailMinusFConfBuilder()
.setFile(new File("/var/log/syslog"))
.setLogstatementProcessor(logstatementProcessor);
TailMinusF tailMinusF = new TailMinusF(tailMinusFConfBuilder.build());
tailMinusF.start();
Thread.sleep(60 * 1000);
tailMinusF.stop();
}
}
Note that no checked exceptions are thrown by TailMinusF. Instead a ExceptionListener is notified in case an exception occurs. By default, a DefaultExceptionListener just caches the last exception for a later processing.
package de.arthurpicht.tail4j.demo;
import de.arthurpicht.tail4j.DefaultExceptionListener;
import de.arthurpicht.tail4j.LogstatementProcessor;
import de.arthurpicht.tail4j.TailMinusF;
import de.arthurpicht.tail4j.TailMinusFConfBuilder;
import java.io.File;
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
LogstatementProcessor logstatementProcessor = logStatement -> System.out.println("Here I could do some processing of \"" + logStatement + "\" ...");
TailMinusFConfBuilder tailMinusFConfBuilder
= new TailMinusFConfBuilder()
.setFile(new File("/var/log/syslog"))
.setLogstatementProcessor(logstatementProcessor);
TailMinusF tailMinusF = new TailMinusF(tailMinusFConfBuilder.build());
tailMinusF.start();
Thread.sleep(60 * 1000);
tailMinusF.stop();
DefaultExceptionListener defaultExceptionListener = (DefaultExceptionListener) tailMinusF.getTailMinusFConf().getExceptionListener();
if (defaultExceptionListener.isExceptionOccurred()) {
System.out.println("Exception occurred: " + defaultExceptionListener.getLastException().getMessage());
}
}
}
As shown here, an instance of ExceptionListener interface can be implemented, in order to provide a custom exception handling.
package de.arthurpicht.tail4j.demo;
import de.arthurpicht.tail4j.ExceptionListener;
import de.arthurpicht.tail4j.LogstatementProcessor;
import de.arthurpicht.tail4j.TailMinusF;
import de.arthurpicht.tail4j.TailMinusFConfBuilder;
import java.io.File;
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
LogstatementProcessor logstatementProcessor = logStatement -> System.out.println("Here I could do some processing of \"" + logStatement + "\" ...");
ExceptionListener exceptionListener = e -> System.out.println("Exception occurred: " + e.getMessage());
TailMinusFConfBuilder tailMinusFConfBuilder
= new TailMinusFConfBuilder()
.setFile(new File("/var/log/syslog"))
.setLogstatementProcessor(logstatementProcessor)
.setExceptionListener(exceptionListener);
TailMinusF tailMinusF = new TailMinusF(tailMinusFConfBuilder.build());
tailMinusF.start();
Thread.sleep(60 * 1000);
tailMinusF.stop();
}
}
tail4j itself produces some log statements that can be helpful in tracing and debugging conditions.
However, logging is disabled and no runtime dependency must be fulfilled by default.
For turning on logging, system property de.arthurpicht.tail4j.logging needs to be configured. Set it to slf4j and tail4J will pass all generated log statements to SLF4J. When doing so make sure that SLF4J and the respective underlying logging framework is on classpath and properly configured.
Setting system property to stdout will simply write log statements to console without any further dependency on a particular logging framework.
All other values are ignored and thus tail4j will behave in default mode.
Apache License 2.0