Log4j hanging my application - java

Im trying to get console output from an external application in my application. When i call the externall app from my code it hangs with the message:
Configuring logging...
Configuring log4j from: C:\GPAT\log4j.cfg
and nothing happens. I searched through internet and it seems that it might be thread issue. But i cant modify this external application and i must go through log4j. I read the external app like this:
StringBuffer output = new StringBuffer();
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(GSATCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
System.out.println("Test running...");
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line); // Writes the test output to console
output.append(line); output.append("\n");
}
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
System.out.println("Test successfully executed");
} catch (Throwable t) {
t.printStackTrace();
}
Thanks for reading.

You need to consume both stdout and stderr from a spawned process in separate threads, to prevent blocking behaviour (your spawned process will write to buffers, and block if those buffers aren't being emptied by your consuming process).
See the 2nd paragraph of this answer for more details and a link to a suitable fix.

Related

Wait for process to finish before proceeding in Java

Essentially, I'm making a small program that's going to install some software, and then run some basic commands afterwards to prep that program. However, what is happening is that the program starts its install, and then immediately moves on to the following lines (registration, updates, etc). Of course, that can't happen until it's fully installed, so I'd like to find a way of waiting on the first process before running the second. For example,
Main.say("Installing...");
Process p1 = Runtime.getRuntime().exec(dir + "setup.exe /SILENT");
//Wait here, I need to finish installing first!
Main.say("Registering...");
Process p2 = Runtime.getRuntime().exec(installDir + "program.exe /register aaaa-bbbb-cccc");
Main.say("Updating...");
Process p4 = Runtime.getRuntime().exec(installDir + "program.exe /update -silent");
Call Process#waitFor(). Its Javadoc says:
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
Bonus: you get the exit value of the subprocess. So you can check whether it exited successfully with code 0, or whether an error occured (non-zero exit code).
you can use Process.waitFor() method
and the doc says
Causes the current thread to wait, if necessary, until the process
represented by this Process object has terminated. This method returns
immediately if the subprocess has already terminated. If the
subprocess has not yet terminated, the calling thread will be blocked
until the subprocess exits.
If you are running a system command that returns a very long response string, stdin buffer fills up and the process appears to hang. This happened to me with sqlldr. If that appears to be the case then just read from stdin as the process is running.
try {
ProcessBuilder pb = new ProcessBuilder("myCommand");
Process p = pb.start();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
StringBuffer response = new StringBuffer();
StringBuffer errorStr = new StringBuffer();
boolean alreadyWaited = false;
while (p.isAlive()) {
try {
if(alreadyWaited) {
// read the output from the command because
//if we don't then the buffers fill up and
//the command stops and doesn't return
String temp;
while ((temp = stdInput.readLine()) != null) {
response.append(temp);
}
String errTemp;
while ((errTemp = stdError.readLine()) != null) {
errorStr.append(errTemp);
}
}
Thread.sleep(1000);
alreadyWaited = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug("Response is " + response);
logger.debug("Error is: " + errorStr);
}
} catch (IOException e) {
logger.error("Error running system command", e);
}
Include waitFor(). In your case, your code will look something like below.
Main.say("Installing...");
Process p1 = Runtime.getRuntime().exec(dir + "setup.exe /SILENT");
p1.waitFor()
Main.say("Registering...");
Process p2 = Runtime.getRuntime().exec(installDir + "program.exe /register aaaa-bbbb-cccc");
Main.say("Updating...");
Process p4 = Runtime.getRuntime().exec(installDir + "program.exe /update -silent");

Redirect a system call output to a file with Java

Currently having troubles to redirect the output of a small windows batch console to a log file. My Java application needs to start the Runtime.exec() call without waiting it to finish and still log the output. Here is my logger class :
public class BatchThreadLogger extends Thread {
private Process process;
private String logFilePath;
private static final Logger logger = Logger.getLogger(BatchThreadLogger.class);
public BatchThreadLogger(Process process, String logFilePath) {
this.process = process;
this.logFilePath = logFilePath;
}
public void run() {
try {
// create logging file
File file = new File(logFilePath);
file.createNewFile();
// create a writer object
OutputStream os = new FileOutputStream(file);
PrintWriter pw = new PrintWriter(os);
// catch the process output in an InputStream
InputStreamReader isr = new InputStreamReader(process.getInputStream());
BufferedReader br = new BufferedReader(isr);
// wait for the process to complete
int processStatus = process.waitFor();
// redirect the output to the log file
String line = null;
while ((line = br.readLine()) != null) {
pw.println(line);
}
// add a small message with the return code to the log
pw.println("********************************************");
pw.println("********************************************");
pw.println("Batch call completed with return status " + processStatus);
pw.flush();
os.close();
}
catch (IOException e) {
logger.error("IOException raised during batch logging on file " + logFilePath, e);
}
catch (InterruptedException e) {
logger.error("InterruptedException raised during batch process execution", e);
}
}
}
My call is quite simple :
Process process = Runtime.getRuntime().exec(command);
BatchThreadLogger logger = new BatchThreadLogger(process, logFilePath);
logger.start();
My command is currently just calling my test.bat with two parameters. My test batch now just do :
echo "BATCH CALLED WITH PARAMETER %1 AND %2"
exit
My log file however does contains only :
********************************************
********************************************
Batch call completed with return status 0
I tried to place the waitFor()call before and after the code redirecting the output to the log file, without success. I always see the black screen of the command being launched, but nothing in logs...
Any help would be greatly appreciated, I'm missing something, but cannot understand what...
You're not reading from the standard error of the process you create.
I suspect that an error message is being written to the standard error, and because you're only reading from standard output, you're not picking up this error.
I would recommend replacing your use of Runtime.getRuntime().exec(...) with a ProcessBuilder, using something like the following:
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "test.bat", "One", "Two");
pb.redirectErrorStream(true);
Process process = pb.start();
The line pb.redirectErrorStream(true); redirects the process' standard error into its standard output, so that you don't have to read from two streams (standard output and standard error) in two separate threads.

How to write output of child process in Java

I have written a java code in Eclipse and i am developing a plug-in which embed a button on workbench. When this button is clicked, it opens a batch file (located in c:/program file/prism 4.0/bin)
The code successfully opens the .bat file ! But my next task is write the output of that batch file on my console. I am using Eclipse IDE version 3.
My code is
MessageConsoleStream out = myConsole.newMessageStream();
out.println("We are on console ! \n Shubham performed action");
try {
ProcessBuilder pb=new ProcessBuilder("C:\\Program Files\\prism-4.0\\bin\\prism.bat");
pb.directory(new File("C:\\Program Files\\prism-4.0\\bin"));
Process p=pb.start();
int exitVal=p.waitFor();
out.println("Exited with error code "+exitVal+" shown and action performed \n");
out.println("Shubham Process Successful");
out.println("Printing on console");
}
catch (Exception e)
{
out.println(e.toString());
e.printStackTrace();
}
}
Do like this:
.....
Process p = pb.start();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String in;
while((in = input.readLine()) != null) {
out.println(in);
}
int exitVal = p.waitFor();
.....
Note that if the batch file writes to standard error your java program must consume it otherwise the p.waitFor() will never return.
Do yourself a big favor and check http://commons.apache.org/exec/. It will take care of all the awful details about managnig an external process: timeout, handling input/output, even creating the command line will be easier and less error prone
Note that to correctly read from the InputStreams of a Process, you should do so on separate Threads. See this similar question.

Unable to perform any action before Process.Runtime.exec statement line

my very first post here after long time of searching but yet get an answer regarding this issue, please help me in this issue.
I am using Netbean 6.9.1 to build a Java application which massive call to few different external program, therefore I used process and runtime function to call for external program.
The whole application process is separated into few stages and I wish to inform the user till which stage the application is currently running by updating the GUI textarea, the code is showed as below:
public void executeCommand (String cmd, File path)
{
try
{
****areaOutput.setText("Executing audio decoding, please wait till process is done\n");****
btnTranscribe.setEnabled(false);
areaOutput.setEditable(false);
areaOutput.setEnabled(false);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd , null, path);
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
areaOutput.append("\n\nConversion is done, processing with features extraction....");
} catch (Throwable t)
{
t.printStackTrace();
}
}
As showed in the code above, I wish to set the Textarea and disable some button before executing the command, but when the application ran, all of these line seems unable to work and nothing is changed at the application itself till the command is finish executed, any solution to run the pre-command code execute first before the .exec() start to run?
I appreciate your great help and advice regarding this issue.
Best regards,
Striky
P/S:
hi there, I have make a Thread class for this CmdExec in order to execute cmd in different thread:
public class CmdExec extends Thread
{
private String cmd;
private File path;
public CmdExec() {
}
public CmdExec(String cmd, File path) {
this.cmd = cmd;
this.path = path;
}
public void run(){
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd , null, path);
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</ERROR>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
and in order to call to this class,
CmdExec tryDemo = new CmdExec();
tryDemo = new CmdExec(strSegment, fSegment);
tryDemo.run();
is used to start the thread, but I failed to put SwingUtilities.invokeLater in any part of these process, it simply won't run the tryDemo.run() because it is void...
Also, may I know so far am I doing right?? Very thank you for your kind help regarding this issue
P/S 2: I have just added another runnable code (so threads for process executing, runnable to GUI update) for GUI update command as below:
Runnable doWorkRunnable = new Runnable() {
public void run() {
System.out.println("hello world");
btnTranscribe.setEnabled(false);
areaOutput.setEditable(false);
areaOutput.setEnabled(false);
areaOutput.setText("Performing segmentation, please wait till process is done\n"); }
};
and I used SwingUtilies.invokeLater before the execution of process as below:
SwingUtilities.invokeLater(doWorkRunnable);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd , null, path);
But all these failed, am I get the wrong sequence for the GUI and process thread coordination?
you are executing this work on the EDT (the thread which updates the gui). so, the gui cannot update until all this work finishes. what you want to do is run a separate thread which does all the work and periodically calls SwingUtilities.invokeLater with a status update.
Try to put sleep before execute method. To verify what is happening.

Runtime exec and a custom built RTF editor

I have a class that manages the creation of RTF documents and a method in that class that calls the RTF editor with a XML file for display.
All but one user can access this editor without any issues. This one user consistently runs into an issue where their application just hangs. There are no errors in any logs. Normally this kind of problem is easily identified, reproduced and corrected, however, I can't for the life of my reproduce it so my attempts at debugging are failing.
Basically the code is as follows:
int exitVal = CUBSRTFEditor.runRTFEditor("c:\\tmp\\control"+ap_doc_id+".xml", xml,"I:\\AppealsLetters.exe /process \"c:\\tmp\\control"+ap_doc_id+".xml\"");
public static int runRTFEditor(String xmlLocation, String xmlContent, String executePath)
{
int exitVal = 0;
createLocalFile(xmlLocation, xmlContent);
try
{
System.out.println("executePath must = "+executePath);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(executePath);
System.out.println("after executePath runs");
//exhaust that stream before waiting for the process to exit
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
// read the ls output
String line;
while ((line = bufferedreader.readLine())!= null)
{
System.out.println(line);
}
exitVal = proc.waitFor();
}
catch (Throwable t)
{
t.printStackTrace();
}
CUBSRTFEditor.deleteTempFile(xmlLocation);
return exitVal;
}
The last output is the first System.out. When I take the xml file and execute this on any other PC it executes without issue. I see no useful info in proc.getErrorStream() or proc.getOutputStream().
The JDK's Javadoc documentation on this problem (exec hanging):
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
I try exhausting that stream before waiting for the process to exit and that does not seem to help as it never seems to get to that point (the second System.out is not displayed)
Have I implemented this incorrectly? Am I missing something important? Any ideas on how to get more info out of the process would be great.
I am stuck....
Runtime.exec() is a deceptively nasty little spud to work with. I found this article (old, but still relevant) to be quite helpful. You can always skip to Page 4 for some highly gankable sample code. :-)
At a glance, your code needs to handle both proc.getOutputStream() and proc.getErrorStream(), which is a good reason to handle those streams in separate threads.
I wanted to update this because the change went into Production today and worked. Based off of BlairHippo's suggestions I got it to work with an anonymous inner class to create a separate thread to exhaust both the Error and Input streams.
new Thread(new Runnable(){
public void run()
{
try
{
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line;
while ((line = br.readLine())!= null)
{
System.out.println(line);
}
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}).start();

Categories

Resources