-2

What can I use to read log file in real time in Java 8? I read blogs to understand BufferedReader is a good option for reading fine. I tried below:

BufferedReader reader = new 
BufferedReader(new 
InputStreamReader(inputStream));
String line;
while(true) {
line = reader.readLine(); // blocks until next line 
available
// do whatever You want with line
}

However it keeps printing null irrespective of file is updated or not. Any idea what can be going wrong.

Any other options?

Details are as below : I am trying to create an utility in Java 8 or above, where I need to read log file of an application at real time (as live transactions are occurring and getting printed in logs).

I can access log file as I am on sme server, so that is not an issue.

So some of the specifics are below -> I don't want to poll the log files for Changes, I want to keep it the bridge open to read log file in "while true" loop. So ideally i want to block my reader if there are no new lines getting printed.

-> I don't want to store the entire content of the file in memory at all time as I want it to be memory efficient.

-> my code will run as a separate application to read log file of another application.

-> only job of my code is to read log, match against a pattern, if matched then send a message with log content.

Kindly let me know if any detail is ambiguous.

Any help is appericiated, thanks.

DarkKnight
  • 225
  • 1
  • 2
  • 10

1 Answers1

0

For this to work, your inputStream must block until new data becomes available, which a standard FileInputStream does not when reaching the end-of-file.

I suppose, you initialize inputStream to just new FileInputStream("my-logfile.log");. This stream will only read to the current end of the log file and signal the "end of file" condition to the BufferedReader. This in turn will signal "end of file" by returning null from readLine().

Have a look at the utility org.apache.commons.io.input.Tailer. This allows to write programs like the Unix utility tail -f.

To make your code work, you would have to use an "infinite" input stream that could be realized using a RandomAccessFile as in the following example:

package test;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;

public class TestRead {

    public static void main(String[] args) throws IOException, InterruptedException {
        File logFile = new File("my-log.log");
        // Make sure to start form a defined condition.
        logFile.delete();
        try (OutputStream out = Files.newOutputStream(logFile.toPath(), StandardOpenOption.CREATE)) {
            // Just create an empty file to append later on.
        }

        Thread analyzer = Thread.currentThread();

        // Simulate log file writing.
        new Thread() {
            @Override
            public void run() {
                try {
                    for (int n = 0; n < 16; n++) {
                        try (OutputStream out = Files.newOutputStream(logFile.toPath(), StandardOpenOption.APPEND)) {
                            PrintWriter printer = new PrintWriter(out);
                            String line = "Line " + n;
                            printer.println(line);
                            printer.flush();
                            System.out.println("wrote: " + line);
                        }
                        Thread.sleep(1000);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    analyzer.interrupt();
                }
            }
        }.start();

        // The original code reading the log file.
        try (InputStream inputStream = new InfiniteInputStream(logFile);) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream), 8);
            String line;
            while (true) {
                line = reader.readLine();
                if (line == null) {
                    System.out.println("End-of-file.");
                    break;
                }
                System.out.println("read: " + line);
            }
        }
    }

    public static class InfiniteInputStream extends InputStream {

        private final RandomAccessFile _in;

        public InfiniteInputStream(File file) throws IOException {
            _in = new RandomAccessFile(file, "r");
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            if (b == null) {
                throw new NullPointerException();
            } else if (off < 0 || len < 0 || len > b.length - off) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }

            int c = read();
            if (c == -1) {
                return -1;
            }
            b[off] = (byte)c;

            int i = 1;
            try {
                for (; i < len ; i++) {
                    c = readDirect();
                    if (c == -1) {
                        break;
                    }
                    b[off + i] = (byte)c;
                }
            } catch (IOException ee) {
            }
            return i;
        }

        @Override
        public int read() throws IOException {
            int result;
            while ((result = readDirect()) < 0) {
                // Poll until more data becomes available. 
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {
                    return -1;
                }
            }
            return result;
        }

        private int readDirect() throws IOException {
            return _in.read();
        }

    }
}
haui
  • 567
  • 5
  • 18