I use sl4j / logback as a logging framework. I am unsure about the right way to log errors. Namely, assuming e is an Exception I want to log, I always hesitate between:
logger.error("Something bad happened: {}\nError: {}", someInfo, e.getMessage());
I understand this is not good practice because the stack trace is lost - not great to understand what happened.
logger.error("Something bad happened: {}\nError: {}", someInfo, e.getMessage(), e);
Using both e.getMessage() and e seems redundant, although I don't know if it is possible that e.getMessage() might contain extra information that would not be seen if I used:
logger.error("Something bad happened: {}", someInfo, e);
which is the syntax I generally use - but I want to make sure I am not missing anything.
I usually use number two, although I NEVER break one line of log into 2 lines (\n), although when printing the stack trace, it won't matter much (in all other cases, it creates too much visual entropy when your logs become really huge).
Why do I use number 2?
I want to see the message right away, on the first line, since it's the first thing that tells me what happened. Some might be expected and I can safely skip them, and some might not be.
In case I need to examine exactly what happened, I take a better look at the stack trace.
I reckon number 3 is also fine, since you'll get the information you need anyway.
NEVER use option 1.
By the way, and just a particular opinion, saying that something bad happened on a ERROR line is a bit redundant ;)
If you look at the source code of Throwable (http://www.docjar.com/html/api/java/lang/Throwable.java.html) you'll find that a Throwable when asked to print its stacktrace starts by priting itself, which prints its message.
I find it unlikely that anybody would change this behaviour, so your arguments are all correct and the 3. option is fine
You definitely want the stack trace.
Message is handy in circumstances where you've done something like "Error : Unable to find customer with ID : {0}", which may not be in the stacktrace. Trivial example but you get what I mean.
Another one for message is if you do the log as say a csv so you can analyse it. You can standarise message, and make filtering easier.
Last but not least redundant info in an error log, is way way way less of a problem, then the info you need not being in it. Err on the side of extreme verbosity is my guiding principle.
Oh this is for contrrolled access to a log file ,never say put stack trace as a response in asp for instance. Hackers wet dream that.
Related
I have been tasked with logging the line number as part of the error code shown to the user. Currently I am using:
StackTraceElement[] stackTraceElement = e.getStackTrace();
lineNumber = stackTraceElement[0].getLineNumber();
I know that the above approach may fail depending on the JVM version.
Also, I have seen the PatternLayout where it is mentioned that "Generating caller location information is extremely slow. Its use should be avoided unless execution speed is not an issue.".
Since this message will be presented to the user, should I still log the line number as part of the error code? I am trying to understand the pros and cons of this approach. Also, does the log4j warning apply only to its own implementation or rather is it a warning against location information generally?
Well, generally speaking your program should report two kind of errors:
The errors that are for the user (when the user is not doing what is expected from him), which should actually be better called "feedback" to help him feed your program with the right data (that's good UX practice).
The errors that are generated because of a bug, which are actually not targeted at the user, but at you the developer, sadly through the user. Then yes, it might be a good idea to log line numbers (or give your errors unique names/identifiers so that you can trace easily where it's been sent from). But a better idea is to then use a framework to report such issues directly to you through Internet (good practice being to ask for permission first).
What you should show to the user is what went wrong and what he can do about it, if anything. The line number information needs to be available, e.g. via a 'More details' button, in case he needs to raise a support ticket, but you don't want to frighten him or confuse him with it up front. Just look at how many stack traces get misread or indeed ignored completely here, and this community is supposed to be computer programmers.
Generally its better if your program doesn't give errors, and can receive all input, and give you tips on how to use the application. This will give users a much better experience if you want them to buy your product, etc.. If your program does give errors, it will not be helpful for the user to know the line number. You however will want to know the line number, so you should make it display a message of some sort that tells the user to email you the stack trace when the error occurs. Or you could have it report the error message automatically and email it to you.
Sorry, I'm a bit late I was unclear what the question was asking, so I posted this as a comment, but clearly it is an acceptable answer.
I have my program working and all done (java). It's a short and easy program for a job interview. I handle stuff like improper input format by throwing a custom exception. Is that the best way to do it or should I just make a print statement?
Exceptions are only useful if they will be handled by other code.
If you're writing a reusable library, you should by all means throw an exception.
There is nothing more frustrating than calling a third-party library that logs errors to the console instead of telling your code about them.
However, if you're writing a standalone utility, it's nicer to print friendly error messages than an ugly stack trace.
The most flexible approach is to write reusable code that throws exceptions, then add catch blocks in main() (or elsewhere in the standalone portion) that prints friendly messages.
If you handle improper format inline is the code readable? If so - fine, if not - throw an exception and handle it elsewhere
Are you able to handle improper format properly in the place you are parsing it or maybe some more generic method/class/module is actually calling your routine and should decide what to do? If the latter is the case -> throw an exception
In general - it depends. If you can handle this special situation "inline" - you can do it (make sure it's readable). If not - throw an exception.
Here's a good reference on exception best practices. You should make sure you are following these.
In your particular case (based on the details you have provided) a user may upload/select a file that has bad data. You program should handle that by catching any basic Java runtime issues and returning information to the user (not "Exception in thread..." but something more readable to a user). If you are checking for these alpha characters then you should just handle that (with an error to the user) without throwing an exception - unless this is truly the behavior you want.
Exception are cause when the program cannot work in a normally correct manner.
The exceptions get more complicated and increase in numbers when you evolve from j2se to j2ee.
For a stand alone application
If your application is just a extremely simple calculator then you may just completely forget about exception because your user input would be filtered and one of the few exception would be division by zero
If your application is a simple utility tool say screen capture , then if your file cannot be saved (exception at file i/o) then all you need to do is simply terminate all your task and say some error message to the user.
For an advanced project of example 2 , you need to save the image in a temp , and perform saving of file once the issue is rectified
For a enterprise scaled and distributed application
Here transaction(inter related activities) is involved . Here a simple message to the user is also needed at times and also handle(do needed changes to related transactions) the exception !
If the application is distributed in many countries then exception in one traction needs alteration in another server in another country , this demands optional incorporation of a some thing that uses JMS API(message sending inside application)
JPA (java persistence api) implicitly rolls back the database on event of a exception and provides facility to do so for interrelated transactions . But still the roll back only affects the database and not the instance variable(object values)
and at all times you don't want to user to read your exact stack trace that says error at line number .....
I am looking for a way to get a stack trace when I am at a certain breakpoint. Is this possible? Ideally without having to crash the application and modifying the code. I tried playing with the Android debugger but couldn't find anything very helpful.
The reason is that sometimes I am not certain how the application arrived at a point in code, so I am open to other suggestions that would help me trace the method calls.
This can be done in Java:
new Throwable().printStackTrace();
In Eclipse, if you create an "expression" with that code in the Expressions view of Debug perspective, it will print current stack trace (i.e. the stacktrace of the breakpoint your code stopped on) in the Console view.
Log.e("AppName", "Debug exception", new Exception());
The easiest way is to throw an exception, immediately catch it and use printStackTrace().
You could also try Thread.currentThread().getStackTrace() which gives you a StackTraceElement[] in case you want to to anything else besides having the textual representation that printStackTrace() does.
Is there a cleaner way for me to write debug level log statements? In some ways one could say that the string literals are basically commenting the code and providing logging in one line and that it is already very clean. But after I add debug level log statements, I find the code much less easier to read up and down. Take this example (I may update to a real example if I get back to my home PC):
int i = 0;
logger.debug("Setting i to 0,"); //Just an example, would show something more complex
i++;
InputStream is = socket.getInputStream();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
IOUtils.write(request, dos);
logger.debug("request written to output");
while (!is.read(buffer))
logger.debug("Reading into buffer");
logger.debug("Data read completely from socket");
CustomObject.doStuff(buffer);
logger.debug("Stuff has been done to buffer");
You could try using aspects, although these have the limitation that you can only put log statements "around" method calls, i.e. before entering and/or after leaving a specific method.
For more detailed logging, I am afraid there is no other way than hand-coded log messages.
I typically strive to remove the not-so-much-needed debug log statements from the code once I made sure that it works the way it should (for which unit tests are a must).
Ask yourself if I run this in a different machine/country/planet, and things go wrong and all I have is only a log file what information do I need to know what has gone wrong ?
Use debug logs in a for loop, or a while loop sparingly. For example, if you are reading 1000 records from a file, performing an op for each record. You could record before the for loop that "file exists and is readable and is going to read 1000 records" and print status after the process is done. If it is say 1000000 records then you could print something every say 100 or 1000 iterations
In your code except for the logger for setting i to 0 everything else sorta makes sense to me. Also care to use log.isDebugEnabled() if your string in the logger statmeent is hard to compute..
ex:
if(log.isDebugEnabled) {
logger.debug("Here " + obj.aMethodCallThatTakes5MinsToEvaluateToString());
}
UPDATE 1: SLF4J solves only half the problem.
if(slfLog.isDebugEnabled) {
slfLog.debug(obj.getObjectThatTakes5Mins());
}
Yes the toString is prevented but if you are logging an actual object which is result of some computation you are not prevented.
If you want very fine grained debug instructions I am not sure you can separate the actual code from the debug code.
If you want it at a higher level, maybe adding your logging using AOP could help make things easier to read, maybe use a proxy object?
But if you have debug instructions as fine grained as in the example you provided, IMHO you could gain more by replacing the loggers with unit tests. Don't write in a log that something happened, test that it did.
You will not be able to do much if you dislike the log statements. The information needs to be there somehow.
What you CAN do, is strongly considering what NEEDS to be there. You are basically writing for the log file reader who per definition does not know about how your program works, so the information needs to be concise and correct. Personally I very frequently add the method name to the log statement.
Also note that slf4j allows you to use the {}-syntax which helps somewhat
log.debug("main() date={}, args={}", new java.util.Date(), args);
Also note that having unit tests, allow you to move much stuff to there simply because you know that THAT works.
how can i find out which class/method has called the actual method?
You could try to create an exception to get its stacktrace.
Throwable t = new Throwable();
StackTraceElement[] stackTraceElements = t.getStackTrace();
Now stackTraceElement[0] contains the caller of the current method.
But beware (from Throwable.getStackTrace()):
Some virtual machines may, under some
circumstances, omit one or more stack
frames from the stack trace. In the
extreme case, a virtual machine that
has no stack trace information
concerning this throwable is permitted
to return a zero-length array from
this method. Generally speaking, the
array returned by this method will
contain one element for every frame
that would be printed by
printStackTrace.
Here's one way that I've used:
StackTraceElement element=Thread.currentThread().getStackTrace()[3];
String className=element.getClassName();
String methodName=element.getMethodName();
[3] is hardcoded because:
[0] is Thread.dumpThreads()
[1] is Thread.getStackTrace()
[2] is the current method
[3] is the one before the current method
A faster but non-portable solution is to use the following. It does not create a stack trace and just gives you the information you need. However, not all JVMs will have this and future version of Java might not either.
Class callerClass = sun.reflect.Reflection.getCallerClass(2);
You can print a stack trace to do this.
If you want to do this dynamically, I'm not really sure if this is possible (aside from printing and parsing a stack trace dynamically).
You could use a debugger, or a profiler. Netbeans has both, but a lot of other options exists.
Else, if you can modify the code you can throw a new exception() and have a stacktrace printed in the console.
To echo and elaborate on matt b and yishai's comments:
If you are doing this because you are writing a logger or maintaining trace information or some such, okay, cool. I've used stack traces in production code exactly once, and even that was really a debugging issue: We had a problem with database connections not being properly closed, so I modified the "get database connection" function to save the identity of the caller, and then had a periodic sweep to look for dead connections and see where they had been created.
Java's built-in logging function does stack traces so it can write who called the logger to the log file. I worry about the overhead of this as I understand that stack traces are expensive, but whatever.
But if you're doing this because your function is going to behave differently depending on where it was called from, like "if called from class X update customer data else if called from class Y update employee data" or something like that: Really really bad idea. Pass a parameter or write separate functions.