Brad
Brad

Reputation: 4547

How to print logs from another jar line by line?

I have created a Java application that has 2 Jar files. Jar1 is used to initialize and run Jar2, using this code :

Process process = runtime.exec( "java -jar Jar2.jar" );
printLogs( process );
.
.
.
private static boolean printLogs( Process process ) {
    try {
        BufferedInputStream logStream = new BufferedInputStream( process.getInputStream() );
        String logs = "";
        int buffer = 0;

        while ( ( buffer = logStream.read() ) != -1 ) {
            logs += (char)buffer;
        }

        if( !logs.isEmpty() ) logger.debug( logs );
    } catch (IOException e) {}  

    return true;
}

I print many logs from Jar2 using Log4J, i.e.

logger.debug( "..." );

But none of the logs in Jar2 were printed to the console. I figured out it's because the logs are returned to Jar1 and not to the console, So i printed the returning stream using the above code. Logs are now printed fine but after all Jar2 process ends up, then all logs are printed at once in Jar1.

The question is: Can i print each log line in Jar2 in time instead of waiting all Jar2 process to end ?

Because Jar2 is a long process, and it is important that i can see those logs while the application is processing.

Upvotes: 0

Views: 1677

Answers (3)

Brad
Brad

Reputation: 4547

With the help of this post i was able to fix this :

Runtime.exec never returns when reading system.in

I have used the ProcessBuilder too.

Upvotes: 0

Raffaele
Raffaele

Reputation: 20885

The whole thing is quite messed up. You shouldn't need two separate archives and Runtime.exec()

However, one usually uses BufferedReader.readLines to read text lines. Note that the problem simply vanishes if you log each line at the moment you read it:

BufferedReader input = new BufferedReader(
  new InputStreamReader(process.getInputStream())
);
String line = null;

while ((line = input.readLine()) != null) {
  System.out.println(line);
}

Your code waits to the child process to complete because you logged the line after the stream ends (ie after the subprocess has terminated)

Here is a demo program which uses a long running Ruby program as the watched process

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Subprocess {

    static final String[] program = new String[] {
        "ruby",
        "-e" ,
        "(1..5).each{|i|sleep 1;puts i;STDOUT.flush}"
    };

    public static void main(String[] args) throws IOException {
        ProcessBuilder builder = new ProcessBuilder(program);
        builder.redirectErrorStream();

        Process child = builder.start();

        String line = null;
        BufferedReader in = new BufferedReader(
                new InputStreamReader(child.getInputStream()));

        while ((line = in.readLine()) != null)
            System.out.println(line);
    }

}

Upvotes: 2

Faelkle
Faelkle

Reputation: 483

Your code seems to be waiting for the logStream to get to EOF before actually writing logs (which occurs when the process exits). Try refactoring it to read it character-by-character, then logging the accumulated character buffer whenever you see a newline (and EOF, of course - so you get the last line).

Upvotes: 0

Related Questions