W
W
web_dev2015-03-05 02:06:21
Java
web_dev, 2015-03-05 02:06:21

Java - WatchService - check if the file is busy by another process?

Hello,
I wrote a small service in Java that looks at the directory with logs and if something is added to the log, it reacts.
The problem arises when a log is written from nginx, monitoring is also carried out for tomcat and WildFly (the service runs on it).
AccesDeniedException - I catch and process this error, but anyway after a while - the server just goes down ....
For some reason, only nginx.
Always this error

[0m[0m23:48:21,928 INFO  [com.jdev.logsviewer.listeners.StompDisconnectEvent] (_Watcher_NGINX) Received WatchEvent: 'ENTRY_MODIFY' - for file: access.log
[0m[0m23:48:21,928 INFO  [com.jdev.logsviewer.listeners.StompDisconnectEvent] (_Watcher_NGINX) Received WatchEvent: 'ENTRY_MODIFY' - for file: access.log
[0m[0m23:48:21,928 INFO  [com.jdev.logsviewer.commons.LogsViewerCommonFunctions] (_Watcher_NGINX) Cannot read a file content or file attributes!
[0m[31m23:48:21,929 ERROR [stderr] (_Watcher_NGINX) java.nio.file.AccessDeniedException: /var/log/nginx/access.log
[0m[31m23:48:21,929 ERROR [stderr] (_Watcher_NGINX) 	at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
[0m[31m23:48:21,929 ERROR [stderr] (_Watcher_NGINX) 	at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
[0m[31m23:48:21,929 ERROR [stderr] (_Watcher_NGINX) 	at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
[0m[31m23:48:21,929 ERROR [stderr] (_Watcher_NGINX) 	at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
[0m[31m23:48:21,930 ERROR [stderr] (_Watcher_NGINX) 	at java.nio.file.Files.newByteChannel(Files.java:317)
[0m[31m23:48:21,930 ERROR [stderr] (_Watcher_NGINX) 	at java.nio.file.Files.newByteChannel(Files.java:363)
[0m[31m23:48:21,930 ERROR [stderr] (_Watcher_NGINX) 	at java.nio.file.Files.readAllBytes(Files.java:2981)
[0m[31m23:48:21,930 ERROR [stderr] (_Watcher_NGINX) 	at com.jdev.logsviewer.commons.LogsViewerCommonFunctions.createLog(LogsViewerCommonFunctions.java:48)
[0m[31m23:48:21,930 ERROR [stderr] (_Watcher_NGINX) 	at com.jdev.logsviewer.service.LogsFolderWatcher.run(LogsFolderWatcher.java:58)
[0m[31m23:48:21,930 ERROR [stderr] (_Watcher_NGINX) 	at java.lang.Thread.run(Thread.java:745)

Is there a way to check if the file is in use by another process? When to be free then and read - to stand in line or something like that ... Thanks for the tips.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
W
web_dev, 2015-03-05
@web_dev

private void createWatchService(Folder folder) {
    try {
      Path dir = Paths.get(folder.getValue());
      WatchService watcher = FileSystems.getDefault().newWatchService();
      LogsFolderWatcher fileWatcher = new LogsFolderWatcher(watcher, folder, simpMessagingTemplate);
      Thread thread = new Thread(fileWatcher, LogsViewerConstants.WATCHER_PREFIX + folder);
      thread.start();
      logger.info("Added watcher for " + folder + " folder");
      dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }


-------------------------

/**
 * @author JDev
 *
 */
public class LogsFolderWatcher implements Runnable {

  private static final Logger logger = LoggerFactory.getLogger(StompDisconnectEvent.class);

  private WatchService watcher;
  private Folder folderToWatch;
  private SimpMessagingTemplate simpMessagingTemplate;

  public LogsFolderWatcher(WatchService watcher, Folder folderToWatch, SimpMessagingTemplate simpMessagingTemplate) {
    this.watcher = watcher;
    this.folderToWatch = folderToWatch;
    this.simpMessagingTemplate = simpMessagingTemplate;
  }

  /**
   * In order to implement a file watcher, we loop forever ensuring requesting
   * to take the next item from the file watchers queue.
   */
  @SuppressWarnings("rawtypes")
  @Override
  public void run() {
    try {
      // get the first event before looping
      WatchKey key = watcher.take();
      while (!Thread.currentThread().isInterrupted()) {
        // we have a polled event, now we traverse it and
        // receive all the states from it
        for (WatchEvent event : key.pollEvents()) {
          Path dir = (Path) key.watchable();
          Path fullPath = dir.resolve((Path) event.context());

          logger.info("Received WatchEvent: '" + event.kind() + "' - for file: " + event.context().toString());

          Log changedLog = LogsViewerCommonFunctions.createLog(fullPath.toFile(), WatchState.valueOf(event.kind().name()));
          simpMessagingTemplate.convertAndSend("/log/" + folderToWatch, changedLog);
        }
        key.reset();
        key = watcher.take();
      }
    } catch (InterruptedException e) {
      logger.info("Stopping " + Thread.currentThread().getName() + " thread");
    }
  }
}

Hmmmm, and as I just noticed myself - I'm catching an error in the wrong place, where I catch it too late, it doesn't get there ... What do you think if I catch it in run () - maybe something change?
public static Log createLog(File file, WatchState watchState) {

    Path path = Paths.get(file.getPath());
    BasicFileAttributes basicFileAttributes = null;
    Log log = null;
    try {
      basicFileAttributes = Files.getFileAttributeView(path, BasicFileAttributeView.class).readAttributes();

      log = new Log();
      log.setFileName(file.getName());
      log.setCreatedOn(new Date(basicFileAttributes.creationTime().toMillis()));
      log.setModyfiedOn(new Date(basicFileAttributes.lastModifiedTime().toMillis()));
      log.setSize(basicFileAttributes.size());
      log.setWatchState(watchState);
      log.setContent(new String(Files.readAllBytes(path)));
      logger.info("Created Log for file log: " + log.getFileName());

    } catch (Exception exception) {
      if (exception instanceof IOException) {
        logger.info("Cannot read a file " + log.getFileName() + " content or file attributes!");
      } else if (exception instanceof AccessDeniedException) {
        logger.info("The file " + log.getFileName() + " used by another process.");
      }
      exception.printStackTrace();
    }

    return log;
  }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question