Custom logging framework based solution
Spawn a thread to execute your command, and then use the answer to the following question:
Which will log the messages from the process launched by your spawned thread back to the UI in a thread-safe manner.
You can use an ExecutorService to assist with thread management if you wish. If you do, remember to shut it down cleanly (usually in the stop()
method for your JavaFX app).
JavaFX concurrency utilities based solution
You can also make use of JavaFX concurrency utilities, such as Task
, Service
and Platform.runLater
if you wish. See the "A Task Which Returns Partial Results" or "A Task Which Modifies The Scene Graph" sections of the Task
java documentation for more information on this approach.

Example of using JavaFX concurrency utilities.
import javafx.application.*;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ConsoleLogger extends Application {
@Override
public void start(Stage stage) throws Exception {
TextArea outputArea = new TextArea();
outputArea.setStyle("-fx-font-family: monospace");
outputArea.setEditable(false);
TextField commandField = new TextField();
commandField.setOnAction(event ->
executeTask(
commandField.getText(),
outputArea
)
);
VBox layout = new VBox(
10,
new Label("Enter a command and press return to execute it."),
commandField,
outputArea
);
VBox.setVgrow(outputArea, Priority.ALWAYS);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
private void executeTask(String commandString, TextArea outputArea) {
CommandExecutor commandExecutor = new CommandExecutor(
commandString,
outputArea
);
new Thread(commandExecutor).start();
}
public class CommandExecutor extends Task<Void> {
private final String commandString;
private final TextArea outputArea;
private final ProcessBuilder processBuilder;
public CommandExecutor(
String commandString,
TextArea outputArea
) {
this.commandString = commandString;
this.outputArea = outputArea;
processBuilder = new ProcessBuilder(
commandString.trim().split("\\s+")
)
.redirectErrorStream(true);
exceptionProperty().addListener((observable, oldException, newException) -> {
if (newException != null) {
newException.printStackTrace();
}
});
}
@Override
protected Void call() throws IOException {
Process process = processBuilder.start();
try (
BufferedReader reader =
new BufferedReader(
new InputStreamReader(
process.getInputStream()
)
)
) {
String line;
while ((line = reader.readLine()) != null) {
final String nextLine = line;
Platform.runLater(
() -> outputArea.appendText(nextLine + "\n")
);
}
}
return null;
}
}
public static void main(String[] args) {
launch(args);
}
}
Note that this is a naive solution which can flood the JavaFX runnable queue, does not include robust exception handling, has no thread pooling, does not deal with processes which take interactive input I/O, merges output from concurrent executing processes to a single text area, does not limit text area size, etc. In particular, you need to be careful if the spawned process does something like tail a large log file which is constantly being written to at a rapid pace, as the naive solution could flood the JavaFX runnable queue with many calls to Platform.runLater
, which wouldn't be good.
For a more efficient solution, the custom logging system linked earlier may be better. However, for some applications, the Task based system logging to a TextArea in this example, or some small modifications to it, may be fine.
Additional Notes
In any case, be careful you don't try to modify the text area or any of its properties directly from another thread (use Platform.runLater
to prevent that), otherwise the program may fail due to concurrency issues.
There are quite a few tricks and unexpected (undesirable) things which can happen when using the Java Process API, so if you are not very proficient in it, then google around to see what these are and how they may be addressed if you need a very robust solution.