Okay, here is another answer as a variation of my previous one for changes at any file position (diff). Now the somewhat simpler case is files only being appended (tail).
As you can see, we use Apache Commons IO here. (Why a snapshot version? Follow the link in the XML comment if you are interested.)
Source code:
package de.scrum_master.app;
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListenerAdapter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
public class FileTailWatcher {
public static final String DEFAULT_WATCH_DIR = "watch-dir";
public static final int DEFAULT_WATCH_INTERVAL = 5;
private Path watchDir;
private int watchInterval;
private WatchService watchService;
public FileTailWatcher(Path watchDir, int watchInterval) throws IOException {
if (!Files.isDirectory(watchDir))
throw new IllegalArgumentException("Path '" + watchDir + "' is not a directory");
this.watchDir = watchDir;
this.watchInterval = watchInterval;
watchService = FileSystems.getDefault().newWatchService();
}
public static class MyTailerListener extends TailerListenerAdapter {
public void handle(String line) {
System.out.println(line);
}
}
public void run() throws InterruptedException, IOException {
try (DirectoryStream dirEntries = Files.newDirectoryStream(watchDir)) {
for (Path file : dirEntries)
createTailer(file);
}
watchDir.register(watchService, ENTRY_CREATE);
while (true) {
WatchKey watchKey = watchService.take();
for (WatchEvent> event : watchKey.pollEvents())
createTailer(watchDir.resolve((Path) event.context()));
watchKey.reset();
Thread.sleep(1000 * watchInterval);
}
}
private Tailer createTailer(Path path) {
if (Files.isDirectory(path))
return null;
System.out.println("Creating tailer: " + path);
return Tailer.create(
path.toFile(), // File to be monitored
Charset.defaultCharset(), // Character set (available since Commons IO 2.5)
new MyTailerListener(), // What should happen for new tail events?
1000, // Delay between checks in ms
true, // Tail from end of file, not from beginning
true, // Close & reopen files in between reads,
// otherwise file is locked on Windows and cannot be deleted
4096 // Read buffer size
);
}
public static void main(String[] args) throws IOException, InterruptedException {
String watchDirName = args.length > 0 ? args[0] : DEFAULT_WATCH_DIR;
int watchInterval = args.length > 2 ? Integer.getInteger(args[2]) : DEFAULT_WATCH_INTERVAL;
new FileTailWatcher(Paths.get(watchDirName), watchInterval).run();
}
}
Now try appending to existing files and/or creating new ones. Everything will be printed to standard output. In a production environment you would maybe display multiple windows or tabs, one for each log file. Whatever...
@Simon: I hope this one suits your situation better than the more general case and is worth a bounty. :-)