Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional printing of stack trace in Java

I am creating a java application in which there is a possibility that exceptions might be thrown. I am handling these exceptions in a try-catch block and printing appropriate messages so that the business users don't have to see the ugly stack trace in case of a failure.

But now when I debug, I would like to invoke the JAR file in such a way that it will print the stack traces for me, so that I can know where exactly the problem lies.

Can someone enlighten me on how this can be achieved?

like image 758
aa8y Avatar asked Sep 12 '12 07:09

aa8y


2 Answers

Why not use Logging levels.?

DEBUG for your technical errors and INFO or ERROR with the business codes that your users understand.

like image 182
Ajay George Avatar answered Oct 22 '22 09:10

Ajay George


You could use slf4j as a facade in order to be able to change quickly implementations and logback as the implementation for your logging. The combination of slf4j and logback are currently a very efficient logging system. In case you would want to use another implementation such as log4j, JDK 1.4, or Jacarta Commons logging you could just change the jar of the implementation(binding) with the one you want. It follows a quick user manual of how to use slf4j with logback.

Setting Your Environment

First of all you should import the necessary jars that are required to use slf4j.

  • Go to slf4j download page and download slf4j-1.7.0.zip
  • Extract slf4j-1.7.0.zip
  • Go to logback download page and download logback-1.0.7.zip
  • Extract logback-1.0.7.zip

Eclipse Guide

  • Go to your project in eclipse and right click on it. Select Properties.

  • From the left panel select Java Build Path

  • Select Libraries tab

  • Click Add External Jars

  • Locate your extracted folders and add logback-core-1.0.7.jar, logback-classic-1.0.7.jar from the logback-1.0.7 folder and slf4j-api-1.7.0.jar from the slf4j-1.7.0 folder. Click ok to return to the project.

Netbeans Guide

  • Go to your project in Netbeans and right click on it. Select Properties.

  • From the left panel select Libraries

  • Select Compile tab

  • Click Add Jar/Folder

  • Locate your extracted folders and add logback-core-1.0.7.jar, logback-classic-1.0.7.jar from the logback-1.0.7 folder and slf4j-api-1.7.0.jar from the slf4j-1.7.0 folder. Click ok to return to the project.

*In case you are not using any of the above environments you should add the above 3 jars in your classpath manually. Dependening your operating system there is a different procedure to follow.


Using the logging framework

First of all you should import the required dependencies:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Each class that you would like to log should have a private logger:

private final Logger logger = (Logger) LoggerFactory.getLogger(this.getClass())

By having a seperate logger for each class you provide more flexibility and easier change of your logging levels(WARN,ERROR,INFO,DEBUG).

According to the log level that would like to use you should have

logger.info("Your info message");

logger.error("Your error message");

logger.debug("Your debug message");

logger.warn("Your warn message");

There is also the possibility to use more complex method calls dependening on your needs. For example if you want to debug and show also the stacktrace you should use

logger.debug("Your debug message",e);
(e stands for a catched exception).

For example:

try{       
   //some code  
}catch (IOException e){
   logger.debug("An IOException was thrown at this method ",e);       
   logger.error("An IOException was thrown at this method ",e); 
}

*At this point without adding any other configuration you have a simple logging system. In case you want more advanced configuration read the advanced settings of logback that i have posted below.


Advanced Settings of logback

In order to have a more advanced logging system you should create an additional file which will contain all the logging configuration. For this example i am going to use the logback.xml. For more info regarding the different files of logback please refer to logback configuration.

At this point you should create a folder named resources and add it in the buildpath of your project.

Eclipse Guide

  • Create a folder named resources(You must see the folder in your project)

  • Go to your project in eclipse and right click on it. Select Properties.

  • From the left panel select Java Build Path

  • Select Source tab

  • Click Add Folder

  • Tick the resources folder that you have created and click ok. Click ok to return to the project.

  • At this point you should see the resources folder as a package.

Netbeans Guide

  • Create a folder named resources(it will not be visible yet on the projects view..Only in the files view)

  • Go to your project in Netbeans and right click on it. Select Properties.

  • From the left panel select Sources

  • In the Source package folders click Add Folder.

  • Select the resources folder and click ok.

  • You should see the folder created as a package.

*The name of the folder could be any name that you like. For convenience i named it resources.

The following applies in both Eclipse and Netbeans.

*In case you will not have the following file in your classpath which specify specific settings in the logging framework, the root logger level is automatically assigned in DEBUG. That means that all the logging levels are going to be logged. Debug is the higher level.

  • Create a folder named logback.xml and place it inside the resources folder.
  • Inside logback.xml place the following tag.

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>   
        <encoder>
            <pattern>[%-5level] - %msg%n
            </pattern>
        </encoder>
    </appender>
    
    
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <append>false</append>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %class - %msg%n
            </pattern>
        </encoder>
        <File>log/log.txt</File>
    </appender>
    
    
    <logger name="org.test" level="INFO" additivity="false">
        <appender-ref ref="STDOUT" />
    </logger>
    
    <logger name="org.test" level="DEBUG" additivity="false">
        <appender-ref ref="FILE" />
    </logger>
    
    <root level="OFF">
    
    </root>
    

The above configuration contains 2 different appenders,one in the console and one in a file named log.txt. The file is going to be placed in a folder named log. In case the folder log does not exist is going to be created automatically.

The pattern that you are going to use depends on you and how informative your messages will be. In the current configuration the console appender is less descriptive and shows only the logging level and the message, comparing to the file appender which contains logging level, thread name, class name, time and message. The value append is set to false in order to create a new log file after every run of your application.

The above configuration uses 2 different loggers for the same package. The first logger prints only the info messages in the console and the second logger prints the debug messages to a file. This is achieved by using the filter that is placed inside the appenders.

*In the logger name you can have the fully qualified name of your class or the package name. In this case i assumed package structure org.test and placed the class inside this package. If you have the fully qualified name of the class the logging configuration will be applied only for this class. In case you use the package name, all the classes inside this package are going to follow the above configuration.

There are many different ways to use the appenders and loggers and it depends in your needs and the complexity of your program. According to the situation that you described i believe that above solution could meet your needs.

P.S. For more descriptive definitions and more advanced configurations you could refer to the Logback manual

like image 26
Konstantinos Margaritis Avatar answered Oct 22 '22 09:10

Konstantinos Margaritis