printStackTrace() in a finished product. When and

2019-09-08 15:00发布

问题:

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.

回答1:

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.



回答2:

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