0

I'm trying to write on a log file the output or a Java program launched via Runtime.getRuntime().exec(). I'm using the following code.

public class Thread_Write extends Thread {
 int id;
 public void run() {
 try {
 File log = new File("./log"+id+".txt");
 log.createNewFile();
 FileWriter fw = new FileWriter("./"+"log"+id+".txt",true);
 Runtime runtime = Runtime.getRuntime();
 Process process = runtime.exec("java WriteToFile "+id);
 InputStream is = process.getInputStream();
 InputStreamReader isr = new InputStreamReader(is);
 BufferedReader br = new BufferedReader(isr);
 String line;
 while ((line = br.readLine()) != null) {
 fw.write(line);
 }
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 public Thread_Write(int i) {
 super();
 this.id = i;
 }
 public static void main(String[] args) {
 for (int i =0 ; i<10;i++) {
 (new Thread_Write(i)).start();
 }
 }
}

"java WriteToFile id" is suppose to write an exception on the terminal, but unfortunately, I'm not getting anything. What's odd is that if I change this command bye "echo test", "test" will be properly added at the end of the log file. Any idea why ?

Cheers.

asked Jan 16, 2014 at 10:01
1
  • 4
    Probably because it's written to the error stream of the process, not its input stream. Commented Jan 16, 2014 at 10:04

3 Answers 3

2

The likeliest reason is that the exception goes to the error stream. One option is to redirect the error stream too: process.getErrorStream().

Alternatively you can use a ProcessBuilder:

ProcessBuilder pb = new ProcessBuilder("java", "WriteToFile", String.valueOf(id));
pb.redirectErrorStream(true);
pb.redirectOutput(log);
Process p = pb.start();
answered Jan 16, 2014 at 10:08
Sign up to request clarification or add additional context in comments.

1 Comment

Not only that, one can forego the use of InputStream entirely and use redirectOutput(log) instead.
1

Errors are not available through process.getInputStream(), you need to instead use process.getErrorStream(). An alternative is to first use processBuilder.redirectErrorStream(true). This will cause both stdout and stderr to be available on process.getInputStream().

answered Jan 16, 2014 at 10:07

Comments

0

There are several issues here. Here's how I would write the run() method (rationale follows):

public void run() {
 try {
 Process process = Runtime.getRuntime().exec("java WriteToFile " + id);
 Thread err = consume(process.getErrorStream(), 
 new FileOutputStream("./" + "log" + id + ".txt"));
 Thread std = consume(process.getInputStream(), 
 new FileOutputStream("./" + "log_stdout" + id + ".txt"));
 err.join();
 std.join();
 } catch (Exception e) {
 e.printStackTrace();
 } 
}
private Thread consume(final InputStream stream, 
 final OutputStream out) {
 Thread result = new Thread() {
 public void run() {
 PrintWriter pw = new PrintWriter(out, true);
 try (Scanner sc = new Scanner(stream)) {
 while (sc.hasNext()) {
 pw.println(sc.nextLine());
 }
 }
 }
 };
 result.start();
 return result;
}

(1) Most importantly: if WriteToFile writes to both stderr and stdout, your process will block: as it only reads from stderr, there's no one to read the bytes off of the stdout buffer. Once this buffer fills up WriteToFile will block on the next println(). Assuming this happens before an exception was written both processes will be deadlocked, each one waiting for the other one to make the first move. The solution: spawn two threads, one for consuming stdout and the other for consuming stderr.

Other (minor) issues: (2) Instead of wrapping InputStream in an InputStreamReader which, in turn, is wrapped inside a BufferedReader you can use the Scanner class: its constructor can take an InputStream and it gives you the readLine() method that you need.

(3) No need to create the log variable if it sole purpose is to be used in log.createNewFile(); - the output file will be created for you by your FileWriter object.

(4) You'd probably want to use a PrintWriter object rather than a FileWriter. The former gives you println() which lets you print the output line-by-line.

answered Jan 16, 2014 at 10:50

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.