2

I'm very new java world in general. I have a javafx application where i'm trying to setup file watcher on log4j log file to watch for changes and display the changes in the textarea. I have the below code which is working fine on any file other than log4j log file.

Also, I notice that when I refresh the folder containing the log4j file in windows explorer it seem to work. I'm confused and not sure what am i doing wrong or not sure if this is even possible.

Please advise.

package application;

import java.io.IOException;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.text.TextFlow;

public class MainappWindowController implements Initializable {

    @FXML
    private Button btn_appendtext;
    @FXML
    private TextArea txtarea_logview;
    @FXML
    private TextFlow txtflow_logview;

    // FOR Logging
    public static final Logger log = Logger.getLogger(Main.class);

    String log4jConfPath = "./log4j_properties/log4j.properties";

    Path watchPath = Paths.get("C:/temp/mylogfile_being_watched_by_java.txt");

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // TODO Auto-generated method stub

        btn_appendtext.setOnAction(e -> {
            testlogger();
        });

        // load file initially
        if (Files.exists(watchPath)) {
            loadFile();
        } else {
            log.info("File does not exist");
        }

        // watch file
        WatchThread watchThread = new WatchThread(watchPath);
        watchThread.setDaemon(true);
        watchThread.start();

        // Add log4j properties file to configuration
        PropertyConfigurator.configure(log4jConfPath);

    }

    public void testlogger() {
        log.info("This is an information message");
    }

    private void loadFile() {
        try {
            String stringFromFile = Files.lines(watchPath).collect(Collectors.joining("\n"));
            txtarea_logview.setText(stringFromFile);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private class WatchThread extends Thread {
        Path watchPath;

        public WatchThread(Path watchPath) {
            this.watchPath = watchPath;
        }

        @Override
        public void run() {
            try {
                WatchService watcher = FileSystems.getDefault().newWatchService();
                WatchKey key = watchPath.getParent().register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
                        StandardWatchEventKinds.ENTRY_MODIFY);

                while (true) {
                    // wait for key to be signaled
                    try {
                        key = watcher.take();
                    } catch (InterruptedException x) {
                        return;
                    }

                    for (WatchEvent<?> event : key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();

                        if (kind == StandardWatchEventKinds.OVERFLOW) {
                            continue;
                        }

                        WatchEvent<Path> ev = (WatchEvent<Path>) event;
                        Path path = ev.context();
                        if (!path.getFileName().equals(watchPath.getFileName())) {
                            continue;
                        }
                        // process file
                        Platform.runLater(() -> {
                            loadFile();
                        });
                    }

                    boolean valid = key.reset();
                    if (!valid) {
                        break;
                    }
                }
            } catch (IOException x) {
                System.err.println(x);
            }
        }
    }
}
Kevin
  • 33
  • 1
  • 8
  • 1
    How large is the log file you are monitoring? If it is large and changed often, then the strategy you use (load the entire log file into a string and then set as text into a TextArea), is going to be really inefficient. You might want to use some kind of [stream based approach](https://stackoverflow.com/questions/557844/java-io-implementation-of-unix-linux-tail-f) coupled with an [efficient log display mechanism](https://stackoverflow.com/questions/24116858/most-efficient-way-to-log-messages-to-javafx-textarea-via-threads-with-simple-cu). – jewelsea Feb 13 '18 at 01:02
  • 1
    The file is not going be large at all given the functionality i have in the application. But in the example i posted above i'm just trying to test it with one line and can't figure out why it is not working on log4j file while it works on other files fine. – Kevin Feb 13 '18 at 01:12
  • 1
    Oracle provide a [sample watch service app](https://docs.oracle.com/javase/tutorial/essential/io/notification.html). If you run that against the directory containing your log file, does it detect the changes to the log file? Also, what OS is this? It is obviously Windows, but which version? – jewelsea Feb 13 '18 at 07:46
  • 1
    Log4J [built their own file watcher](https://docs.oracle.com/javase/tutorial/essential/io/notification.html) into their framework [for various reasons](https://docs.oracle.com/javase/tutorial/essential/io/notification.html), you might want to try that if you can't get your current approach to work on your platform, especially as performance is not an issue for you. – jewelsea Feb 13 '18 at 07:56

0 Answers0