}
private DirWatcher createWatcher(File dir, final String regex,
final int recurseDepth) {
// 250 ms between checks
DirWatcher watcher = new DirWatcher(dir, new RegexFileFilter(regex), 250);
watcher.addHandler(new DirChangeHandler() {
Map<String, Cursor> curmap = new HashMap<String, Cursor>();
@Override
public void fileCreated(File f) {
if (f.isDirectory()) {
if (recurseDepth <= 0) {
LOG.debug("Tail dir will not read or recurse "
+ "into subdirectory " + f + ", this watcher recurseDepth: "
+ recurseDepth);
return;
}
LOG.info("added dir " + f + ", recurseDepth: " + (recurseDepth - 1));
DirWatcher watcher = createWatcher(f, regex, recurseDepth - 1);
watcher.start();
subdirWatcherMap.put(f.getPath(), watcher);
subdirsAdded.incrementAndGet();
return;
}
// Add a new file to the multi tail.
LOG.info("added file " + f);
Cursor c;
if (delimRegex == null) {
if (startFromEnd && !dirChecked) {
// init cursor positions on first dir check when startFromEnd is set
// to true
c = new Cursor(tail.sync, f, f.length(), f.length(), f
.lastModified());
try {
c.initCursorPos();
} catch (InterruptedException e) {
LOG.error("Initializing of cursor failed", e);
c.close();
return;
}
} else {
c = new Cursor(tail.sync, f);
}
} else {
// special delimiter modes
if (startFromEnd && !dirChecked) {
// init cursor positions on first dir check when startFromEnd is set
// to true
c = new CustomDelimCursor(tail.sync, f, f.length(), f.length(), f
.lastModified(), delimRegex, delimMode);
try {
c.initCursorPos();
} catch (InterruptedException e) {
LOG.error("Initializing of custom delimiter cursor failed", e);
c.close();
return;
}
} else {
c = new CustomDelimCursor(tail.sync, f, delimRegex, delimMode);
}
}
curmap.put(f.getPath(), c);
tail.addCursor(c);
filesAdded.incrementAndGet();
}
@Override
public void fileDeleted(File f) {
LOG.debug("handling deletion of file " + f);
String fileName = f.getPath();
// we cannot just check here with f.isDirectory() because f was deleted
// and f.isDirectory() will return false always
DirWatcher watcher = subdirWatcherMap.remove(fileName);
if (watcher != null) {
LOG.info("removed dir " + f);
LOG.info("stopping watcher for dir: " + f);
// stop is not thread-safe, but since this watcher belongs only to
// this current thread it is safe to call it
watcher.stop();
// calling check explicitly to notify about deleted subdirs,
// so that subdirs watchers can be stopped
watcher.check();
subdirsDeleted.incrementAndGet();
return;
}
Cursor c = curmap.remove(fileName);
// this check may seem unneeded but there are cases which it handles,
// e.g. if unwatched subdirectory was removed c is null.
if (c != null) {
LOG.info("removed file " + f);
tail.removeCursor(c);
filesDeleted.incrementAndGet();
}
}
});
// Separate check is needed to init cursor positions
// (to the end of the files in dir)
if (startFromEnd) {
watcher.check();
}
return watcher;
}