What is the best way to have a (Java) program recognize it crashed last time it ran and show a message along the lines of "it looks like this program crashed on you last time. Report this problem here: bla#foo.com ...."
Is there a recommended way of doing this? (Bad?) ideas I had would be:
Have the program store a temporary key file at startup and then delete it when closing regularly. If the file exists at startup, show the message.
Recognize deadlocks and store an "error file" in this case. If an "error file" exists at startup, show the error message and move the file into an archive or something similar.
There are three reasons why a Java program can crash:
Unhandled RuntimeException. This is easy to solve with a try-catch in main.
Unhandled Errors. These are rare but can be caught in main also. I usually catch Throwable in main. See below for a template.
If you use threads, then look at Thread.setDefaultUncaughtExceptionHandler().
Bugs in the VM, or program killed by the user, or hardware violent shutdown. These will lead to a crash which can't be caught. Here, your best option is to create a flag file somewhere with new File(...).deleteOnExit(). Java will clean it up for you if it gets a chance.
The problem with deadlocks is how to detect that you have a deadlock. I haven't seen a consistent way to do that, yet.
import org.apache.commons.lang.exception.ExceptionUtils;
public class Demo
{
public static void main (String[] args)
{
try
{
Demo obj = new Demo ();
obj.run (args);
System.out.println ("Done.");
}
catch (Throwable t)
{
ExceptionUtils.printRootCauseStackTrace (t);
}
}
}
Crash as in an uncaught exception? The use a Thread.setDefaultUncaughtExceptionHandler, and display the message as part of the crash.
On the first idea, how do you handle multiply instances of the applications running at the same time? (Also think about multi-user environments).
Recognize deadlocks - How often are deadlocks the problem? I guess you could monitor the thread states on all the "key" threads.
You then have external forces killing the application, should they be considered a problem that you should report? After all your application was not at fault in this case.
Finally, always store an "error file" in the form of a log. Use a proper logging framework (i.e. Java Logging or Log4J). You could check the last lines of this for a signal that the application exited normally but again you will need to be careful in multi-instance environments.
A variant of the first solution you propose is common enough on Un*x for processes: store the pid file of a running process in a file at startup. When the program is launched again you can check if this file still exists (and even if the process with this pid is running).
With Java you could probably adapt this idea using Threadid defined in ThreadMXBean. But any file would do. A file that contains a key as you propose seems a good enough way. You could also put some usefull information in it like last execution time. If it's still there at startup the program didn't stopped cleanly.
It could also become something like a launch log file that trace program events including startup and clean stops, and maybe locks.
What I do is redirect System.err to a file, so that any error message (like crashes) end up in a file I can later process...
The code to do this is quite simple...
String errLog = "c:\\myLog";
try
{
java.io.PrintStream err = new java.io.PrintStream(new java.io.FileOutputStream(errLog));
System.setErr(err);
}
catch (java.io.FileNotFoundException fnfe) {}
I'm going to mimic Marcos here. Create a configuration or log file that will host the last error message and last run date of the program. Then read that file during program load.
Many of these answers are about tracking exceptions that caused your app to quit working.
Another possibility is that the application just quit (i.e. user killed it, computer shutdown, power outage, etc.). I think your temporary key idea will work for that. It's similar to how text editing programs, such as vi or Word, automatically create a special copy of the file being edited. Upon opening it checks to see if the special copy exists and asks if you want to recover the file.
Related
I've come to the conclusion after reading from many sources that using printStackTrace for error handling is bad practice. Here's one.
Now I'm struck curious: in what cases is printing the stacktrace a valid solution? For the sake of the argument, let's assume we aren't working on a system such as a microwave or a banana, but a basic out-of-the-shelf PC.
The reason I'm asking this could be seen as a question in itself, but I'll tell you about it anyhoo:
I'm developing a snake-like game that can be played with AIs, and is intended for that purpose. All such AIs should extend an abstract class called SnakeLogic. All such AIs should also reside in their standalone .jar archives in a specific folder, from where the main program can find them and list them using classloaders.
The user can then choose one of his/her AIs from a list, should all stars fall in line, and play a game with this AI.
Now, I have a method in my main program that gets the next move from the AI like so:
public void startGame(int speed) {
gameInterface.showWindow();
Runnable moveCmd = () -> {
try {
for (Player player : snakeGame.getPlayers()) {
if (player.isDead()) {
continue;
}
String move = player.getLogicHandler().getMove();
Direction direction = Direction.directionFromString(move);
snakeGame.makeMove(player, direction);
}
gameInterface.getFrame().repaint();
snakeGame.wait(speed);
if (snakeGame.gameOver()) {
stopGame();
}
} catch (Exception ex) {
ex.printStackTrace();
stopGame();
}
};
/* moveSchedule is an instance of ScheduledExecutorService */
moveSchedule.scheduleAtFixedRate(moveCmd, 1000, speed, TimeUnit.MILLISECONDS);
}
I'm not going to get too involved with the code above. I'd like to draw your attention to the try-catch statement, however. As you can see I print the stacktrace and end the game, should an exception occur somewhere during the execution of the moveCmd runnable. This is the source of my curiosity: If I don't print the stacktrace like this, or if I remove the try-catch entirely, I never get any errors in the case of a runtime exception during the execution of that block. Why? Is it because it's wrapped inside the runnable? Note also that the line snakeGame.makeMove(player, direction); doesn't call any code in the main program; snakeGame is an instance of a SnakeLogic, which resides in an external .jar.
Why don't I get any errors if I remove the try-catch? Also, in this case, is printing the stacktrace a good idea?
I understand this imposes two questions for you: the topic and the above. I want to emphasize the topic, so don't get too sidetracked with the second question; though insight is duly noted, there's nothing broken in my code.
You need to shift your thought process a bit when dealing with error and exceptions. It is always a good practice to print the error trace. Now the question is where to print. by default printStackTrace prints to your standard console. of course you can redirect that output to a log file like Tomcat does but that is a work around, if you ask me.
In production and pre-prod systems and even in distributable spftware where you distribute a desktop application to users for running on PCs you may or may not have dedicated access to console. Further more what prints on console is lost once the console is closed or app finishes. You need to persist the errors somewhere for analysis later. Normally folks design the app to zip and send error logs periodically to developers for analysis.
Now if you think about the whole scenarios the bottom line is to preserve the errors somewhere for analysis later. So usually do it in a rotating log file or in DB. Console wont suffice. Thus incidentally the catch block should have a log statement to log the exception.
The problem with Exception.printStackTrace() is that it writes to your console (most probably) which is a synchronous operation. Not to mention that writing to console is slow in most platforms. You dont want to hold off your execution thread until the full stack trace is written. So its better to hand it over to a log framework like log4j which has the ability to write the complete stack trace into to file asynchronously (other appenders are available), so that the execution thread returns immediately to the callee and yet the log contains necessary details.
So its a question of synchronous write or asynchronous write. As Nazgul pointed out, you have to log exceptions in a system for later analysis where ever applicable.
NotE: A problem with asynchronous logging is that if the process dies abruptly, like in kill -9 or system powered down, you may loose the buffered content before OS has chance to write it to disk
I have, a game bot which runs through console. I don't think i'm going to code a gui for it but i would like to have the possibility to close the program without CTRL+C cause this just interrupts my program instead of properly cleaning up the code and ensure that theres no leaks.
Should i use som kind of Key Bindings or am i bound to, make a GUI ?
Or how could i go about this ?
I think thats what a shutdown hook is for.
Runtime.getRuntime().addShutdownHook( new Thread() {
#Override
public void run() {
System.out.println("Application shutdown");
}
});
David's answer is good. It may well work for you.
I generally prefer not to deliberately abort a process and then detect that it's coming down to avoid dangling operations. So I'd probably do more like:
Are you processing console inputs as they are entered? IF so, you could just have a console command that tells the app to shut down, and check for this in whatever your process is of handling console inputs. Or if you mean that the app just runs with no user input, you could just periodically check if the console buffer is empty (Console.reader().ready()), and if not, read the console and see if it's the quit command.
I am running Ubuntu 10.10 using Java 6 and can not get FreeTTS to output any audio. I have tried it now on 3 different computers and even asked a buddy of mine to try it on his Ubuntu PC and he had the same problem. There is absolutly no errors that are displayed, after getting the MBROLA i no longer even get the warning about No MBROLA voices detected. blah blah blah..
Using the same computer I ran a virtual box and started Windows XP, i was actually able to get audio when running the HelloWorld.jar and TTSHelloWorld.jar however the freetts.jar is still silent when I try to input my own text.
Command I use.
java -jar lib/freetts.jar -text Hello
When I hit enter it starts up and used to give me the missing MBROLA warning message but now it just sits there until i CTRL-C to stop it.
I dont understand what I am doing wrong and why nobody else is having this problem, when I expierence it on every computer, well it works somewhat on Windows. Can anyone Help me?
Thanks,
John
I'm not sure whether you already managed to solve this one, but I ran into the same problem (Ubuntu 10.10 / JavaSE6). After some investigation of the FreeTTS source I found the culprit, a deadlock, in com.sun.speech.freetts.audio.JavaStreamingAudioPlayer. This deadlock occurs when a Line is opened and the Line is of the type org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine (which is likely to be the default in Ubuntu 10.10 w JavaSE6). Since you'd always want to open a Line to get audio out, this deadlock will always occur.
The cause of this deadlock lies in the fact that in the JavaStreamingAudioPlayer an assumption is made about Line, namely that all LineListeners will be notified of a LineEvent of type open from the same Thread as Line.open() was called, or after the Line has been opened (and the call to Line.open() can return). This is not the case for the PulseAudioSourceDataLine; it first calls all LineListeners from the PulseAudio event Thread, waits for all of them to return and then returns from the open call. With the JavaStreamingAudioPlayer forcing synchronization around the call of Line.open() and the handling of a specific LineListener which task is to see whether the Line ís actually open, the deadlock occurs.
The workaround I chose for solving this problem is to implement an AudioPlayer which doesn't has this problem. I basically copied JavaStreamingAudioPlayer and altered the synchronization blocks on line 196 and line 646 ( full source for reference : http://www.javadocexamples.com/java_source/com/sun/speech/freetts/audio/JavaStreamingAudioPlayer.java.html ).
___: // This is the actual JavaStreamAudioPlayer source, not the fix
195: ...
196: synchronized (openLock) {
197: line.open(format, AUDIO_BUFFER_SIZE); // Blocks due to line 646
198: try {
199: openLock.wait();
200: } catch (InterruptedException ie) {
201: ie.printStackTrace();
202: }
203: ...
643: ...
644: public void update(LineEvent event) {
645: if (event.getType().equals(LineEvent.Type.OPEN)) {
646: synchronized (openLock) { // Blocks due to line 196
647: openLock.notifyAll();
648: }
649: }
650: }
651: ...
I removed both synchronization blocks and instead of ensuring both parts are mutually excluded I used a Semaphore to signal that the Line is in fact open. Of course this is not really a necessity since the PulseAudioSourceDataLine already guarantees being opened upon returning, but it is more likely to play nice when testing the same code on another platform. I didn't dive into the code long enough to say what is going to happen when you open/close/open the line by multiple Threads at the same time. If you're going to do this you are probably looking at a larger rewrite of the JavaStreamingAudioPlayer ;).
Finally, after you have created your new AudioPlayer you'll have to instruct FreeTTS to use your implementation rather than the default JavaStreamingAudioPlayer. This can be done by using
System.setProperty("com.sun.speech.freetts.voice.defaultAudioPlayer", "classpath.to.your.AudioPlayer");
somewhere early in your code.
Hopefully this all works for you.
I am a student who has been trying to make FreeTTS working on its Ubuntu for one week. And finally I found the answer here : thank you so much hakvroot !
Your answer was perfect but you did not put your implementation and this took me quite one hour to understand what was going on in the JavaStreamingAudioPlayer class. To help the other people like me who are not used in "diving" in a completely unknown Java code (I am still a student), I will put here my code and hope it will help other people :) .
First, a more detailed explanation : around line 152, the JavaStreamingAudioPlayer opens a Line. However this operation can require some time so before using it, it wants to check it is opened. In the current implementation, the solution used is to create a LineListener listening to this line and then to sleep (using the wait() method of the threads).
The LineListener will "wake up" the main Thread using a notifyAll() and will do this only when it receives a LineEvent of type "OPEN" which will guarantee that the line has been opened.
However as explained by hakvroot here the problem is that the notification is never sent because of the specific behavior of the DataLine used by Ubuntu.
So I removed the synchronized, wait() and notifyAll() parts of the code but as hakvroot, then your JavaStreamingAudioPlayer might try to use your Line before it is opened : you need to wait for the confirmation with a new mechanism to stop the JavaStreamingAudioPlayer and to wake it up later, when the confirmation arrived.
So I used the Semaphore which havkroot used (see Javadoc for explanations on this lock system) initiated with 1 stack :
when the line is opened it acquires one stack (so 0 remains)
when it wants to use the line it tries to acquire another (so it is stopped)
when the listener gets the event we are looking for, it releases the semaphore
this frees the JavaStreamingAudioPlayer who can go for the next part
do not forget to release again the semaphore so it has again 1 stack for the next line to open
And here is my code :
Declare a Semaphore variable :
private Semaphore hackSemaphore;
Initiate it in the constructor :
hackSemaphore = new Semaphore(1);
Then the first part to replace (see hakvroot to see where to put it) :
line = (SourceDataLine) AudioSystem.getLine(info);
line.addLineListener(new JavaStreamLineListener());
line.open(format, AUDIO_BUFFER_SIZE);
hackSemaphore.acquire();
hackSemaphore.acquire();
opened = true;
hackSemaphore.release();
And the second part :
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.OPEN)) {
hackSemaphore.release();
}
}
I guess had the same issue on Ubuntu 12.04/OpenJDK-6, the execution get stuck in Voice.allocate() with no errors and no response.
I tried using the Oracle/Sun JDK-6 instead of OpenJDK, and it worked fine.
P.S. Nice guide to install SunJDK on Ubuntu and configuring as default
http://www.devsniper.com/ubuntu-12-04-install-sun-jdk-6-7/
I have a java JAR file that is triggered by a SQL server job. It's been running successfully for months. The process pulls in a structured flat file to a staging database then pushes that data into an XML file.
However yesterday the process was triggered twice at the same time. I can tell from a log file that gets created, it looks like the process ran twice simultaneously. This caused a lot of issues and the XML file that it kicked out was malformed and contained duplicate nodes etc.
My question is, is this a known issue with Java JVM's spawning multiple instances of itself? Or should I be looking at sql server as the culprit? I'm looking into 'socket locking' or file locking to prevent multiple instances in the future.
This is the first instance of this issue that I've ever heard of.
More info:
The job is scheduled to run every minute.
The job triggers a .bat file that contains the java.exe - jar filename.jar
The java program runs, scans a directory for a file and then executes a loop to process if the file if it finds one. After it processes the file it runs another loop that kicks out XML messages.
I can provide code samples if that would help.
Thank you,
Kevin
It's not a Java problem. If you want the app to run alone, no copies, you should use the shell script or the java app to make and remove a lock somewhere.
You actually start multiple java's by starting more than 1 batch job with the same command. Windows nor Java can now that's not what you want. You could solve that by something like:
public static void main(String [ ] args)
{
createLockIfNotExists();
try {
yourstuff;
} finally {
releaseLock();
}
}
private static void createLockIfNotExists() throws MyLockAlreadyExists {
// A bit tricky
// check if LOCKFILE exists, if yes throw MyLockAlreadyExists
// try to create LOCKFILE, can fail if at 1 ms earlier an other app created
// that file, so an exception while creating also results in LockAlreadyExists
}
Are there good examples somewhere which handle this locking? Maybe in Apache Commons?
Here seems to be a functioning example for Windows.
You could also use the database to write your lock. Lock the locking table before you use it of course so no 2 processes write their lock at the same time, and afterwards read the lock record to check whether you actually got the lock. Something like pseudo code:
SELECT * FROM lock_table;
if locks.length > 0: someone else is running
LOCK lock_table;
INSERT INTO lock_table VALUES(my_pid);
UNLOCK lock_table;
SELECT pid FROM lock_table;
if pids.length > 1: what happened?
if pids[0] != my_pid: someone else got the lock
A bit more juice and you also add not only the PID but also a timestamp, and check whether that timestamp is stale (too old).
My project generates some text/binary files. If I run it normally, some files will have a pretty low size ( which indicates something went wrong ). If I run it from debug mode ( stepping through code ), the files will be generated correctly.
What can cause this behaviour? I'm pretty sure I don't have any unclosed files.
EDIT: I've gone through the code in a more focused way, and I've found the problem. At one point in time, the files get compressed, and this explains the decrease in size. I'm stupid :)
A moderator can close this question if he sees fit.
Try adding:
System.gc();
try { Thread.sleep(4000); } catch (Exception e) {}
System.gc();
...at the end of your program. If the problem goes away then you did forget to close() a file. The above code is no solution, it is a hacky attempt to increase the likelyhood finalizers will run.
Is your code multithreaded? Are you trying to read something that you haven't given another thread a chance to finish constructing, which doesn't manifest when you're stepping through it?
Do you call some kind of "read" method, to read from a file, for example, and assume that you will always get back the number of bytes that you request?