I'm looking for best practices document (or your opinions) on how to effectively log exceptions and their stack traces. Of course, assuming one of popular logging frameworkks such as Log4J, SLF4J, java.util.logging, etc.
I'm particularly interested in your opinion about on what level stack traces should be logged.
I heard few contradicting each other opinions such as:
stack traces should be logged only on DEBUG level while ERROR level should contain only "human readable" error message
stack traces should be logged on ERROR level in order to give to the operator maximum amount of information required to find root cause of an exception
I have found couple of interesting articles however none of them touches this particular subject:
http://today.java.net/pub/a/today/2006/04/06/exception-handling-antipatterns.html
http://today.java.net/pub/a/today/2003/12/04/exceptions.html
which probably means that authors of these articles had same concerns as I do :-)
I'd be really interested in your view on this subject.
Stack trace is the most valuable piece of information you get when troubleshooting. I would never risk logging it on DEBUG level since it might be disabled. And I almost never want to suppress stack traces.
Also note that:
log.error("Houston, we have a problem", ex);
will print the human readable message in line marked as ERROR, while the stack trace is following that line. If you want your errors to be only human readable, just do grep ERROR.
I'm not sure about best-practice advice for this, but in the end, for me it boils down to this:
Exceptions should only be visible in exceptional circumstances. The concept of exception was invented to give developers a chance to handle errors internally.
In reality, most code I see doesn't even try to handle them, instead dumping them to the log, sysout, (or worst case of all) into dialog boxes. I know, that for a developer it is important in some cases to get the full stacetrace. But not nearly in all of them. Creating your own exception framework (which is definitely a best practice) might already be enough to figure out the context of an exception simply by classname.
So I would advise to do the following:
Create your own exception framework
Include specific error codes in the message, for your reference
Log the exception message on ERROR
Log the stacktrace on DEBUG
NEVER EVER display the user either of these. Instead show a useful message. Maybe include a way to report the error (with stacktrace) with minimal fuzz.
Note: If you are writing an internal "enterprise" software, forget everything I wrote. :-)
I think the stack trace should be logged at the appropriate place based on priority best practices. Depending on the nature of the exception and its place within your application, this may be one of many levels. Please see this related question:
Commons Logging priority best practices
Related
quick question. Of course the stack trace gives way more information, but is it a bad practice to use the exception itself instead in some cases? Like just getting "null pointer exception" as opposed to this huge dump of stuff? If this doesn't make any sense, the two differences would be:
(Exception e)
{
print e
}
AND
(Exception e)
{
e.printStackTrace
}
I will say use neither of them in production. You should handle exceptions in other ways, like logging the exception or saving the stacktrace somewhere to review it later and probably display a nice message to the user saying that the app or method failed.
But if you just ask about which of those approaches to use, I will say the latter is better because System.out.println(e) will call Throwable#toString that only provides the message of this exception and maybe you won't get the real cause of the problem.
It depends on the context. Anything that will (or even might accidentally) be presented to the user should not include the stack trace. More than being confusing, you could leak potentially sensitive information.
In my code, I create custom exceptions that have a UserFriendlyMessage property. Friendly messages should be in very plain English. I even have a default catch-all friendly message "There was an unexpected problem. You can try again and if the problem continues contact support".
On the other hand, having the stack trace is invaluable for debugging. In my .NET apps, we go so far as to compile our release code in a special way such that the code is optimized but the symbols are still generated in a separate file. We do this for the sole purpose of ensuring full stack traces with line numbers.
So in summary, display only friendly messages but log (and if you are going to, alert) full stack traces + the friendly message.
The difference between them is that print e returns the type of exception and error message while printStackTrace returns the whole stacktrace of the exception. printStackTrace is more beneficial to be used while debugging.
Example:
print e:
java.lang.IndexOutOfBoundsException
e.printStackTrace():
java.lang.IndexOutOfBoundsException: Index: 8, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at com.o2.business.util.Trial.test(CommonUtilsTest.java:866)
printStackTrace might be good for programmer, but it is not readable and user-friendly for end users. As far as I know, printStackTrace prints the results in the default Errorstream: your console. For better practices, you can check the link: http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 8 years ago.
Improve this question
In every project I've been working on there's always been the issue of log files becoming too large.
A quick off the shelf solution was to use the Log4j RollingFileAppender and set the maximum size allowed.
However there are situations when the same exception happens repeatedly reaching the maximum size very quickly, before somebody manually intervenes. In that scenario because of the rolling policy you end up losing information of important events that happened just before the exception.
Can anybody suggest a fix for this issue?
P.S. Something I can think of is to hold a cache of the Exceptions happened so far, so that when the same Exception re-occurs I don't log tons of stacktrace lines. Still I think this must be a well-known issue and I don't want to reinvent the wheel.
There are two directions to approach this from: The System side and the development side. There are several answers already around dealing with this from the system side (i.e. after the application is deployed and running). However, I'd like to address the development side.
A very common pattern I see is to log exceptions at every level. I see UI components, EJB's, connectors, threads, helper classes, pojos, etc, etc, logging any and all exceptions that occur. In many cases, without bothering to check for the log level. This has the exact result you are encountering as well as making debugging and troubleshooting take more time than necessary as one has to sift through all of the duplication of errors.
My advice is to do the following in the code:
THINK. Not every exception is fatal, and in many cases actually irrelevant (e.g. IOException from a close() operation on a stream.) I don't want to say, "Don't log an exception," because you certainly don't want to miss any issues, so at worst, put the log statement within a conditional check for the debug level
if(logger.isDebugEnabled()){
// log exception
}
Log only at the top level. I'm sure this will meet with some negativity, but my feeling is that unless the class is a top-level interface into an application or component, or the exception ceases to be passed up, then the exception should not be logged. Said another way, if an exception is rethrown, wrapped and thrown or declared to be thrown from the method, do not log it at that level.
For example, the first case is contributing to the issue of too many log statements because it's likely the caller and whatever was called will also log the exception or something statement about the error.
public void something() throws IllegalStateException{
try{
// stuff that throws some exception
}catch(SomeException e){
logger.error(e); // <- NO because we're throwing one
throw new IllegalStateException("Can't do stuff.",e);
}
}
Since we are throwing it, don't log it.
public void something() throws IllegalStateException{
try{
// stuff that throws some exception
}catch(SomeException e){
// Whoever called Something should make the decision to log
throw new IllegalStateException("Can't do stuff.",e);
}
}
However, if something halts the propagation of the exception, it should log it.
public void something(){
try{
// stuff that throws some exception
}catch(SomeException e){
if(logger.isLogLevelEnabled(Log.INFO)){
logger.error(e); // DEFINITELY LOG!
}
}
}
Use Log4J feature to zip the log file after a specified size is reached using "Rolling File Appender". Zips are around 85KB for a 1MB file.
For this specify the trigger policy to zip based on size and specify the zip file in the rolling policy.
Let me know if you need for info.
In my experience, logging is used as a substitute for proper testing and debugging of code. Programmers say to themselves, "I can't be sure this code works, so I'll sprinkle logging messages in it, so when it fails I can use the log messages to figure out what went wrong."
Instead of just sprinkling logging messages around without thought, consider each log message as part of the user interface of your software. The user interface for the DBA, webmaster or system administrator, but part of the user interface nonetheless. Every message should do something useful. The message should be a spur for action, or provide information that they can use. If a message could not be useful, do not log it.
Give an appropriate logging level for each message. If the message is not describing an actual problem, and is not providing status information that is often useful, the message is probably useful only for debugging, so mark it as being a DEBUG or TRACING message. Your usual Log4J configuration should not write those messages at all. Change the configuration to write them only when you are debugging a problem.
You mention that the messages are due to an exception that happens often. Not all exceptions indicate a bug in the program, or even a problem in the operation of the program. You should log all exceptions that indicate a bug in your program, and log the stack trace for them. In many cases that is almost all you need to work out the cause of the bug. If the exception you are worried about is due to a bug, you are focusing on the wrong problem: you should fix the bug. If an exception does not indicate a bug in your program, you should not log a stacktrace for it. A stacktrace is useful only to programmers trying to debug a problem. If the exception does not indicate a problem at all, you need not log it at all.
Buy bigger hard drives and set up a batch process to automatically zip up older logs on a regular basis.
(Zip will detect the repeated exception pattern and compress it very effectively).
use the strategy if reach maximum size, append to the new log file. and run scheduler like everyday to wipe the old log file
Consider some code that can throw a checked exception (an exception of type Exception). Your code catches the exception, of course. You don't just swallow the exception either, your code reports it in some way to the user through your user interface. In a log file, perhaps, or using a GUI pop-up.
Should the text you report to the user include the message text of the exception. That is, the text provided by Throwable.getMessage() or Throwable.getLocalizedMessage()?
I think not, but it seems many disagree with me. So what have I got wrong? My argument is as follows.
The message was created when the exception was thrown. It therefore at best can provide only very low level information, which can be inappropriate for reporting to a user.
Philosophically, using the message seems to me against the whole point of exceptions, which is to separate the detection and initiation of error handling (the throw part) from completion of handling and reporting (the catch part). Using the message means the message must be good for reporting, which moves responsibility for reporting to the location that should be responsible for only detection and initiation. That is, I'd argue that the getMessage() part of the design of Throwable was a mistake.
The message is not localised. Despite its name, getLocalizedMessage() is not much good because you might not know what locale you want to use until you catch the exception (is the report to go to a system log read by your English system administrators, or is it to pop up in a window for the French user of the GUI?).
I hear that Java 7 has a much improved exception hierarchy for IOException, enabling you to handle different kinds of I/O erors in diffferent catch clauses, making the getMessage() text less important. That implies even the Java designers are somewhat uncomfortable with getMessage().
I'm not asking whether reporting the stack-trace is useful. A stack-trace is only ever going to be useful for an exception that suggests a bug. That is, for an unchecked exception. I think in such circumstances providing the low-level detail of the exception message is not just useful but mandatory. But my question deals with checked exceptions, such as file-not-found.
And I am not asking about the "best practice" for the message text.
If you are presenting an error condition to the user, it should probably be a user-friendly message. Exceptions contain technical details that the user should not/does not need to know.
In some situations it could be a security concern to present stacktrace information, so the user should never be shown stack traces.
If you are displaying error messages to the user, there is some point where you consciously make the decision to show a popup, or add a message to a log window. At that point you can translate any exception into a more user friendly message. Note that you might need more information than the default Exception types provide, so you can/should probably create you own Exception types that contain all the information you need to present all the data you need to the user.
No, exceptions shouldn't be shown directly in error messages directly to the user, they're low level technical details and the user almost always wants something more understandable, even if it doesn't provide as much information as a stack trace would!
I say almost always because there are cases (such as in IDEs) where you can consider your users technically competent enough to look at stack traces; indeed in this case they will probably prefer it to a "dumbed down" error message.
However, personally I think stack traces should always be logged somewhere that the user can access so that if they complain that "the program isn't working" you can see exactly what went on if they send you that file.
In some projects, I make a special kind of exception (e.g. UserFriendlyException). This exception type must have a user friendly error message. If I catch such an exception, I can display it to the user.
This makes it possible to use exceptions for user-friendly errors, and prevents that you show very technical messages to the user.
I would argue that you should never show the exception message itself to the user, it should only ever appear in a log. Even if you have purposefully made it user friendly, it should still not be displayed because you cannot internationalize those messages easily. You should come up with some mechanism that your UI layer can understand and resolve that to a code that you can look up an internationalized message to display to your user. I have found that an exception with a "code" attribute/enum works pretty well. Very specific exceptions work too, but that can be messy to maintain.
I came across one very good library for parsing CUE files. But when I started to read its source code, I realized that it is almost unreadable:
public void setParent(final CueSheet parent) {
FileData.logger.entering(FileData.class.getCanonicalName(), "setParent(CueSheet)", parent);
this.parent = parent;
FileData.logger.exiting(FileData.class.getCanonicalName(), "setParent(CueSheet)");
}
every method has logger.entering() and logger.exiting() messages. Isn't that too much?
There's another java library for parsing audio tags. It also had like 15 log messages for each file it read. It was annoying so I commented out every call to logger. And the library became twice as fast, because they used a lot of string concatenation for log messages.
So the question is: should I really log everything, even if it is not large enterprise application? Because these libraries obviously don't need any logging, except for error messages. And my experience shows that loggers are terrible tool for debugging. Why should I use it?
How to know when is too much logging? When you know that the logged information isn't important in the long term, such as for straightforward debug actions or bug correction, or for when the application doesn't deal with too much important information.
Sometimes you need to log almost everything. Is performance or full possibility of analysis the most important part of an application? It really depends.
I've worked in the past with some integration with a lot of different webservices, like 10 in a same app. We logged all xml requests and responses. Is this an overhead? In the long term, I don't think so because we worked with a lot of credit card operations and should have every process made with the server logged. How to know what happened when there was a bug?
You wouldn't believe what I've seen in some of the xml responses. I've even received a xml without closing tags, from a BIG airplane company. Were the "excessive logs" a bad practice? Say that to your clients when you have to prove that the error came from the other vendor.
Ideally, you use a logger that allows logging levels; log4j has fatal/error/warn/debug/info, for example. That way, if you set the level to "only show errors", you don't lose speed to the software building log messages you didn't need.
That said, it's only too much logging until you wind up needing something that would have been logged. It sounds like most of the logging that's slowing you down should be "trace" level, though; it's showing you what a profiler would have.
Most logging libraries incorporate a means to confirm that logging is enabled before processing an instruction:
For example:
public void foo(ComplicatedObject bar) {
Logger.getInstance(Foo.class).trace("Entering foo(" + bar + ")");
}
Could be quite costly depending on the efficiency of the bar.toString() method. However, if you instead wrap that in a check for the logging level before doing the string concatenation:
static {
Logger log = Logger.getInstance(Foo.class);
public void foo(ComplicatedObject bar) {
if (log.isTraceEnabled()) {
log.trace("Entering foo(" + bar + ")");
}
}
Then the string concatenation only occurs if at least one appender for the class is set to Trace. Any complicated log message should do this to avoid unnecessary String creation.
This level of logging is canonically bad - in fact, I saw code exactly like this in the Daily WTF a few days ago.
But logging is in general a Very Good Thing.
It depends, it this code for an application, or a library? For an application, logger are useful once the code is in production. It should not be used to debug, but to help you replicate a bug. When a user tells you that your application crashed, you always want the maximum logging information.
I agree that it makes the code less readable. It even make the application slower!
It's a total different game for a library. You should have consistent logging with adequate level. The library SHOULD inform the development team when an error occurs.
Logging should provide you with information that a stack trace can't in order to track down a problem. This usually means that the info is some kind of historical trace of what the program did, as opposed to what state it's in at the time of failure.
Too much historical data will be ignored. If you can safely deduce that a method was called without having to actually log its entry and exit, then it's safe to remove those logging entries.
Another bad sign is if your logging files start to use up a huge amounts of disk space. You're not only sacrificing space, you're probably slowing down the app too much.
To answer the question, why should I use loggers?
Have you ever encountered a piece of software where the only error indicated presented to the end user is Fatal error occured. Would it not be nice to find out what have caused it?
Logging is a tool that can really help you narrow these kind of problems in the field.
Remember, end-user systems don't have nice IDE's to debug and the end-users usually are not knowledgeable enough to run these tools. However end-users, in most cases, are capable of copying log configuration files ( written by us, clever programmers ) into predefined location and fetch log files and email them back to us ( poor soles for having to parse megabytes of log output ) when they encounter problems.
Having said this, logging should be highly configurable and under normal conditions produce minimal output. Also, guards should protect finer level logging from consuming too many resources.
I think in the example that you have provided all logging should have been done on a TRACE level. Also, because nothing bad can really happen between function entry point and exit, it probably make sense to have only one log statement there.
Over the years I've swayed backwards and forwards between promoting logging everything at the appropriate levels (trace, info, etc...) and thinking that any is a complete waste of time. In reality it depends on what is going to be useful to track down or required (logging can be a cheap way of maintaining an audit trail).
Personally, I tend to log entry/exit at a component or service level and then log significant points in the processing such as a business logic decision or a call on another service/component. Of course errors are always logged, but once only and at the place they were handled (the stack trace and exception message should have sufficient info to diagnose the problem) and any service/component interface should always handle an errors (even if it is just converting it into another more appropriate to the caller).
The problem with logging stuff on the off chance something goes wrong is that you end up with too much information that it is impossible to identify the issue, especially if it is running under a server as you end up with loads of intertwined log entries. Obviously you can get around that by incorporating a request id in the entry and using some software to filter on that. Of course you also have the case where your application is distributed and/or cluster and you have multiple logs.
Nowadays I would never actually write trace entering/exiting entries code, the code just gets in the way and it is so much easier to use something like aspectj if it is really needed. Using aspectj also would guarantee to be consistent (you can change the log format in one place rather than having to change every operation) and accurate (in case some refactoring adds a new paramater and teh developer forgets to add it to the logging).
One thing I have thought about doing or looking to see if someone already has is a logger that will hold the entries in memory, then if an error is encountered they are written, if the operation succeeds the entries are just discarded. If anyone knows of one (ideally for log4j) please let me know, alternatively I have a few ideas on how to implement this if anyone is interested in doing one.
This is where log levels are helpful. In general, log levels in the order of verbosity and priority are TRACE, DEBUG, INFO, WARN, ERROR, FATAL.
The developer has to take a conscious call to use the correct log level while logging in the code.
While creating an instance of Logger we have to pass the correct log level by choosing it from a config (always prefer config). This decides which levels to be logged. For example, while creating the logger, if the config for log level is set to "INFO", anything below "INFO" (TRACE, DEBUG) won't be logged.
For instance, in the example you mentioned above, a TRACE OR DEBUG level would make more sense.
In runtime in production, the config for log level should always be set to INFO.
When an issue occurs in production and if the developer wants to find out the root cause, they can request for changing the log level to TRACE or DEBUG (mostly inside a QA environment where they can replicate the scenario), to see what exactly is happening (The app sometimes has to be restarted to have the log level changed, but it is helpful).
Log levels is a great practice, as most of the times, we won't be able to launch a debugger in the landscapes. As we are skipping the unnecessary file writes by choosing a higher log level, the performance won't take a hit
Would it be useful to include the class name and variable name in any NullPointerException message? I know that it might not always be possible because of changes made by a JIT but is seems like the info should be available often (class members, etc).
From: http://jamesjava.blogspot.com/2005/04/what-was-null.html
That depends. If you get the stack trace, it is clear what class threw the exception. This usually leads to making sure your environment will give you stack traces when there are unhanded exceptions.
Providing as much information as possible during errors is a good thing... Right?
Helps out tracking the bugs.
Edit: (Yes)
No, I don't think that this would at all be "useful".
Instead, you should watch out not to throw NPEs in the first place. Checking your values before you use them (null validation) and the likes. This should happen before you call a library method and after you get back a result (iff the API specifies that the method may return null. Of course, sometimes it will do so anyways, but then that's a bug).
If you think that NPEs should carry this information for debugging, think again. That's what debuggers are good for. An exception is simply there to inform you that something has gone wrong. Remember that unchecked exceptions occur at runtime - and have to be generated there. In order for the Exception to know which variable contained null, the byte code would have to know about variable names. You don't want to bloat your byte code with stuff like this. The class name is contained in every logging output I recieve from my programs. That's what logging is good for.
Java already eases the debugging process a lot by giving you the line number and full stack trace. C programs fail with Segmentation fault. You have to use strace or a debugger in order to even get so much information.
Note that javac does include a compile time option to include source file information at compile time, but this is intended to be used by a debugger, not the random Exceptions that get thrown. Quoting Sun's javac man page:
-g Generate all debugging information, including local variables.
By default, only line number and source file information is
generated.
-g:none
Do not generate any debugging information.
-g:{keyword list}
Generate only some kinds of debugging information, specified
by a comma separated list of keywords. Valid keywords are:
source
Source file debugging information
lines
Line number debugging information
vars
Local variable debugging information
Long story short: use a debugger.
Yes, that would be useful. Especially if you have a mechanism where the error message (exception.getMessage()) is displayed on-screen but the actual stacktrace gets hidden away in log files which you can't access immediately.
Are you throwing NullPointerException? I think you should probably do null validation in the code.
I would also consider using open source logging tools like Log4J.