Saving errors to a file handler - java

With the code below, I'm trying to simulate the command shell, I even created a command and called it (Showerrlog) to help the user seeing his invalid commands that he entered during his current work session, as you can see, I did that using filehandler, which will save the wrong commands in a log file. But as you know filehandler will start a new file for each new working session, and the new file will be named as (file.log, file.log.1, file.log.2, etc) and so on, the question is: how to make the program to avoid opening a new file everytime, in other words isn't there any other way that the program will just format the previous work session and add the new one instead?
Or at least how to make the program open the last log file which belongs to the current work session ?
public class WithEyul implements Runnable {
String command;
public WithEyul(String command) {
this.command = command;
}
#Override
public void run() {
List<String> input = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(command);
while (tokenizer.hasMoreTokens()) {
input.add(tokenizer.nextToken());
}
ProcessBuilder pb = new ProcessBuilder(input);
// ProcessBuilder creates a process corresponding to the input command
// now start the process
BufferedReader br = null;
try {
Process proc = pb.start();
// obtain the input and output streams
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
// read what the process returned
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} catch (java.io.IOException ioe) {
try {
System.err.println("Error");
Logger logger = Logger.getLogger("Testing");
FileHandler fh = new FileHandler("E:/MyLogFile.log");
logger.addHandler(fh);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
logger.info(command);
} catch (SecurityException e) {
printStackTrace();
} catch (IOException ex) {
Logger.getLogger(WithEyul.class.getName()).log(Level.SEVERE, null, ex);
}
} finally {
if (br != null) {
try {
br.close();
} catch (IOException ex) {
Logger.getLogger(WithEyul.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
and here is the main method class
public class TestProcessBuilder {
static void createProcess(String command) throws java.io.IOException {
Thread t = new Thread(new WithEyul(command));
t.start();
}
public static void main(String[] args) throws java.io.IOException {
String commandLine;
File wd;
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.println("\n\n***** Welcome to the Java Command Shell *****");
System.out.println("If you want to exit the shell, type END and press RETURN.\n");
// we break out with ‘END’
while (true) {
// show the Java shell prompt and read what command they entered
System.out.print("jsh>");
commandLine = console.readLine();
// if user entered a return, just loop again
if (commandLine.equals("")) {
continue;
}
if (commandLine.equalsIgnoreCase("Showerrlog")) {
try {
// Runtime.getRuntime().exec("E:\\MyLogFile.log");
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(new File("E:\\MyLogFile.log"));
}
} catch (IOException ex) {
Logger.getLogger(WithEyul.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (commandLine.toLowerCase().equals("end")) { //User wants to end shell
System.out.println("\n***** Command Shell Terminated. See you next time. BYE for now. *****\n");
System.exit(0);
}
createProcess(commandLine);
}
}
}

You could use the FileHandler constructor that allows you to specify the rotation, limit, and append options.
new FileHandler("E:/MyLogFile.log", 0, 1, true);
The FileHandler can rotate for a number of reasons that are out of your control. If you don't want to deal with file rotation you could open a FileOutputStream and wrap that with a StreamHandler. However, you will have to handle file locking conflicts.
You should also avoid creating and adding a handler that points to the same target file everytime an error is generated. You should install the handler on startup and store a string reference to your logger.

Related

Run a shell file in java

In Java you can call a shell file like this:
public class Shell {
private static Shell rootShell = null;
private final Process proc;
private final OutputStreamWriter writer;
private Shell(String cmd) throws IOException {
this.proc = new ProcessBuilder(cmd).redirectErrorStream(true).start();
this.writer = new OutputStreamWriter(this.proc.getOutputStream(), "UTF-8");
}
public void cmd(String command) {
try {
writer.write(command+'\n');
writer.flush();
} catch (IOException e) { }
}
public void close() {
try {
if (writer != null) {
writer.close();
if(proc != null) {
proc.destroy();
}
}
} catch (IOException ignore) {}
}
public static void exec(String command) {
Shell.get().cmd(command);
}
public static Shell get() {
if (Shell.rootShell == null) {
while (Shell.rootShell == null) {
try {
Shell.rootShell = new Shell("su"); //Open with Root Privileges
} catch (IOException e) { }
}
}
return Shell.rootShell;
}
}
Shell.exec("echo " + bt.getLevel() + " > "+ flashfile);
right.
but I have a shell which giving an argument after executing it.
how can I pass that argument? I don't want user type anything to run this shell file. in another word, I want to fully automate a shell file.
If you want to automate a shell file with a Java programme, this can be done. You could even pipe a series of commands to this programme saved in a file and executing these as a batch.
You can execute commands batches of commands from like this:
java -cp experiments-1.0-SNAPSHOT.jar ConsoleReader < commands.txt
commands.txt is a file with a series of commands:
cmd /k date
cmd /k dir
netstat
ipconfig
Or you can with the same programme allow the user to execute commands on the command line.
Below you can find a sample programme which you can compile and be run in the above described manner.
What does it do?
It hooks a java.util.Scanner to the console input and consumes each line.
Then it spawns two threads which listen to the error and input streams and write out either to stderr or stdin.
Empty lines on the console are ignored
If you type "read " it will execute the commands on that file.
Source:
public class ConsoleReader {
public static void main(String[] args) throws IOException, DatatypeConfigurationException {
try(Scanner scanner = new Scanner(new BufferedInputStream(System.in), "UTF-8")) {
readFromScanner(scanner);
}
}
private static final Pattern FILE_INPUT_PAT = Pattern.compile("read\\s*([^\\s]+)");
private static void readFromScanner(Scanner scanner) {
while (scanner.hasNextLine()) {
try {
String command = scanner.nextLine();
if(command != null && !command.trim().isEmpty()) {
command = command.trim();
if("exit".equals(command)) {
break; // exit shell
}
else if(command.startsWith("read")) { // read from file whilst in the shell.
readFile(command);
}
else {
Process p = Runtime.getRuntime().exec(command);
Thread stdout = readFromStream(p.getInputStream(), System.out, "in");
Thread stderr = readFromStream(p.getErrorStream(), System.err, "err");
stdout.join(200);
stderr.join(200);
}
}
}
catch(Exception e) {
Logger.getLogger("ConsoleReader").log(Level.SEVERE, String.format("Failed to execute command %s", e));
}
}
}
private static void readFile(String command) throws FileNotFoundException {
Matcher m = FILE_INPUT_PAT.matcher(command);
if(m.matches()) {
String file = m.group(1);
File f = new File(file);
if (f.exists()) {
try (Scanner subScanner = new Scanner(f)) {
readFromScanner(subScanner);
}
}
}
else {
System.err.printf("Oops, could not find '%s'%n", command);
}
}
private static Thread readFromStream(InputStream stdin, PrintStream out, String name) throws IOException {
Thread thread = new Thread(() -> {
try (BufferedReader in = new BufferedReader(new InputStreamReader(stdin))) {
String line;
while ((line = in.readLine()) != null) {
out.println(line);
}
} catch (IOException e) {
Logger.getLogger("ConsoleReader").log(Level.SEVERE, "Failed to read from stream.", e);
}
}, name);
thread.setDaemon(true);
thread.start();
return thread;
}
}
Runtime.getRuntime().exec("src/[FILE LOCATION]");
I think this is the command you're looking for. Let me know if it works!

Starting external application inside Java

I'm having trouble starting an application from my JavaFX GUI. I'm using ProcessBuilder. It creates the process, but the application won't launch until I close my Java program. Is it because that specific program is waiting for arguments or something wrong with my code?
#FXML
private void runWorldpac() {
try {
ProcessBuilder process = new ProcessBuilder("C:\\speedDIAL\\speedDIAL.exe");
Process p = process.start();
} catch (IOException e) {
e.printStackTrace();
}
}
External application starts but won't allow any interaction with the original application until i close this external program. Tried running a new thread, same result.
Here's the new code:
try {
ProcessBuilder process = new ProcessBuilder("C:\\speedDIAL\\speedDIAL.exe");
Map<String, String> environ = process.environment();
Process p = process.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
//System.out.println(line);
}
System.out.println("Program terminated!");
} catch (IOException e) {
e.printStackTrace();
}
Read that article, good info. Also read another good example on here. It's running in a new thread now, but my program is waiting for the external application to finish before it continues, I understand that's usually desired, but not in this case, how can i disable that?
Wait for the production of the exit value in a new thread. Something like:
try {
ProcessBuilder pBuilder = new ProcessBuilder("C:\\speedDIAL\\speedDIAL.exe");
// don't forget to handle the error stream, and so
// either combine error stream with input stream, as shown here
// or gobble it separately
pBuilder.redirectErrorStream(true);
final Process process = pBuilder.start();
final InputStream is = process.getInputStream();
// in case you need to send information back to the process
// get its output stream. Don't forget to close when through with it
final OutputStream os = process.getOutputStream();
// thread to handle or gobble text sent from input stream
new Thread(() -> {
// try with resources
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is));) {
String line = null;
while ((line = reader.readLine()) != null) {
// TODO: handle line
}
} catch (IOException ex) {
ex.printStackTrace();
}
}).start();
// thread to get exit value from process without blocking
Thread waitForThread = new Thread(() -> {
try {
int exitValue = process.waitFor();
// TODO: handle exit value here
} catch (InterruptedException e) {
e.printStackTrace();
}
});
waitForThread.start();
// if you want to join after a certain time:
long timeOut = 4000;
waitForThread.join(timeOut);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}

Obtaining process CPU usage

I have a program that loads a text file holding some information and based on that information it runs multiple thread. Each thread is a process. Here is my code:
public class runMultiClient {
public static void main(String[] args){
List<Process> PRlist = new ArrayList<Process>();
List<String[]> commandsList = new ArrayList<String[]>();
boolean running = true;
if (args.length == 2 && args[0].matches("-f")){
String dir = System.getProperty("user.dir");
String path = dir + "/" + args[1];
FileReader fr;
try {
fr = new FileReader(path);
BufferedReader bf = new BufferedReader(fr);
String line = "";
while ((line = bf.readLine()) != null){
String[] tk = line.split(" ");
String[] cmd = {"java", "-jar", "Client.jar", "-a", tk[0], "-p", tk[1],
"-u", tk[2], "-pw", tk[3], "-m", tk[4], "-s", tk[5]};
Process pr = new ProcessBuilder().inheritIO().command(cmd).start();
PRlist.add(pr);
commandsList.add(cmd);
System.out.println(tk[4] + " streaming process is established.");
}
}
catch (FileNotFoundException ex) {ex.printStackTrace();}
catch (IOException ex) {ex.printStackTrace();}
} else {
System.out.println("No stream file was specified.");
}
}}
Inside my Client.jar file, i have a variable that monitors the cpu load of that class:
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
cpuLoad = osBean.getProcessCpuLoad();
Is there any way i can reach that variable from the runMultiClient class?
If not, is there any way of using the OperatingSystemMXBean on the running process?
I have tried pr.getClass(), but it got me nowhere.
Any help would be appreciated.
Option #1: Add agent library and expose JMX over HTTP
You can bundle Jolokia agent with your monitored application (another similar thing is SimpleJMX. It exposes JMX beans over http/json so this works for interacting with JMX from other languages like python (and super comfy when troubleshooting from command like). After that you can access mbeans of your interest via apache http client or the like.
Option #2: JMX client
allow remote connections by adding the following params when starting your monitored application:
-Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false
Then you should be able to access the mbeans by jconsole and hand written JMX client code, like in the tutorial
Not sure if you need to call ProcessBuilder().inheritIO() for some other requirement, but if not, you could start a daemon thread in your Client.jar process that periodically writes the cpu load to System.out. Then your runMultiClient thread[s] could read those from the InputStream representing the process's System.out. Or, have the thread accept commands and print accordingly. Rough example:
Run this in the spawned Client.jar:
public static void startCmdListener() {
try {
Thread t = new Thread("CmdListener") {
BufferedReader br = null;
InputStreamReader isr = null;
final OperatingSystemMXBean os = (OperatingSystemMXBean) ManagementFactoryHelper.getOperatingSystemMXBean();
public void run() {
try {
isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);
} catch (Exception ex) {
ex.printStackTrace(System.err);
return;
}
try {
String cmd = null;
while(true) {
cmd = br.readLine();
if("cpu".equalsIgnoreCase(cmd)) { // cpu command, print the process load
System.out.println(os.getProcessCpuLoad());
} else if("exit".equalsIgnoreCase(cmd)) { // exit command, break
break;
}
}
} catch (Exception ex) {
ex.printStackTrace(System.err);
return;
}
}
};
t.setDaemon(true);
t.start();
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
Run this in the runMultiClient to get the cpu load:
public static double getCpu(OutputStream processIn, InputStream processOut) {
PrintStream ps = null;
BufferedReader br = null;
InputStreamReader isr = null;
try {
ps = new PrintStream(processIn);
isr = new InputStreamReader(processOut);
br = new BufferedReader(isr);
ps.println("cpu");
ps.flush();
return Double.parseDouble(br.readLine());
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if(ps!=null) try { ps.close(); } catch (Exception x) {}
if(br!=null) try { br.close(); } catch (Exception x) {}
if(isr!=null) try { isr.close(); } catch (Exception x) {}
}
}

Detecting terminal command errors in Java

In my Java application I am using the exec() command to call a terminal function:
p = Runtime.getRuntime().exec(command);
p.waitFor();
The call uses the zip and unzip calls. Originally I call:
zip -P password -r encrypted.zip folderIWantToZip
When I call the unzip function through java, I specify the password as the method parameter. If the correct password is specified then the call should unzip the encrypted folder:
unzip -P password encrypted.zip
I want a way to find out if the password entered is incorrect. For example, if password is correct, then the call will correctly unzip the zip file. But I notice that no exception is thrown for an incorrect password. How can I determine this?
You could read the process's ErrorStream and InputStream to determine the process output. Sample code given below
public static void main(String[] args) {
try {
String command = "zip -P password -r encrypted.zip folderIWantToZip";
Process p = Runtime.getRuntime().exec(command);
InputStream is = p.getInputStream();
int waitFor = p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
System.out.println("line:" + line);
}
is = p.getErrorStream();
reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
System.out.println("ErrorStream:line: " + line);
}
System.out.println("waitFor:" + waitFor);
System.out.println("exitValue:" + p.exitValue());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You could use the exitcode to validate the process status as well but it is specific to to program. Normally zero means successfully terminated otherwise abnormal termination.
As per my comment, first thing I would do would be to capture the Process's InputStream and ErrorStream via getInputStream() and getErrorStream(), but especially the latter, the ErrorStream, and check to see what it outputs if the input is in error. Note that these would have to be done in their own thread, else you'll tie up your program. I usually use some type of StreamGobbler class for this. Also, don't ignore the int returned by p.waitFor().
e.g.,
ProcessBuilder pBuilder = new ProcessBuilder(COMMAND);
Process process = null;
try {
process = pBuilder.start();
new Thread(new StreamGobbler("Input", process.getInputStream())).start();
new Thread(new StreamGobbler("Error", process.getErrorStream())).start();
int exitValue = process.waitFor();
System.out.println("Exit Value: " + exitValue);
process.destroy();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (process != null) {
process.destroy();
}
}
And:
class StreamGobbler implements Runnable {
private String name;
private Scanner scanner;
public StreamGobbler(String name, InputStream inputStream) {
this.name = name;
scanner = new Scanner(inputStream);
}
#Override
public void run() {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(name + ": " + line); // or better, log the line
}
scanner.close();
}
}

Java: Redirecting output of .bat file in other text file using exec() method?

Java is new to me.
I am executing a batch file using Runtime.getRuntime.exec(filename.bat) and this batch file executes a commandant encrypt.password -Dvalue=somevalue>log.txt and redirects its output to a log.txt file.
Problem that I am facing is batch file is working fine if I run it manually however when program executes it ,it just creates blank 'log.txt'
Content of mybat.bat batch file is as below:
cd/
c:
cd c:/ant_builds/thinclient
ant encrypt.password -Dvalue=someValue >C:/log.txt
Java code is as below:
Process p=Runtime.getRuntime.exec("C:\mybat.bat");
p.waitFor();
It seems that after creating the log file,meantime command is executing control comes out from process.
I have read almost 50 threads here however did not get the solution. Please help me out.
Use ProcessBuilder to create your process and call redirectOutput(File) to redirect and append output to a file.
Try this code:
public class Test {
ProcessBuilder builder;
Path log;
public Test() {
try
{
log = Paths.get("C:\\log.txt");
if (!Files.exists(log))
{
Files.createFile(log);
}
builder = new ProcessBuilder("ant", "encrypt.password", "-Dvalue=someValue");
builder.directory(Paths.get("C:\\ant_builds\\thinclient").toFile());
builder.redirectOutput(ProcessBuilder.Redirect.appendTo(log.toFile()));
builder.start();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) {
new Test();
}
}
For jdk 1.6 or less, use the following code:
public class Test {
ProcessBuilder builder;
Path log;
Process process;
BufferedReader br;
PrintWriter pw;
Charset charset = Charset.forName("UTF-8");
public Test() {
try {
log = new File("C:\\log.txt");
if (!log.exists()) {
log.createNewFile();
}
builder = new ProcessBuilder("ant", "encrypt.password","-Dvalue=someValue");
builder.directory(new File("C:\\ant_builds\\thinclient"));
builder.redirectErrorStream(true);
process = builder.start();
br = new BufferedReader(new InputStreamReader(process.getInputStream(),charset));
pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(log, true), charset));
(new Thread() {
public void run() {
try {
while (process.isAlive()) {
String s = null;
while ((s = br.readLine()) != null) {
pw.print(s);
pw.flush();
}
}
br.close();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Test();
}
}
I'm not sure about the order and list of ProcessBuilder arguments so try to play with them to get your code working.
You can also read commands from a common file and redirect output and erros to a sepearate files. Redirect.appendTo is to avoid the process from overiting the existing logs.
Try this code:
try {
File commands = new File("D:/Sample/Commands.txt");
File output = new File("D:/Sample/Output.txt");
File errors = new File("D:/Sample/ErrorsLog.txt");
ProcessBuilder pb = new ProcessBuilder("cmd");
System.out.println(pb.redirectInput());
System.out.println(pb.redirectOutput());
System.out.println(pb.redirectError());
pb.redirectInput(commands);
pb.redirectError(Redirect.appendTo(errors));
pb.redirectOutput(Redirect.appendTo(output));
pb.redirectInput();
pb.redirectOutput();
pb.redirectError();
pb.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Categories