Monday, July 2, 2012

Log4j - Logging Framework

Logging basics

Logging can be defined as a process of storing information about events that occurred during program execution. There are different options to show/store log messages:

- show on console
- store in a file
- send to a remove monitor

Choosing the right option depends on the requirements and type of application.

Normally every java coder does logging even if he is not uing any logging framework. For instance, System.out.println statement is used to print informative message on the console. These messages can also contain the timestamp and other useful information which will make these messages interesting for the viewer and can help in error tracking and performance monitoring. But if you use a logging framework, then there is a big plus. The logging framework adds contextual information like line number, timestamp etc which prevents the developers from writing extra code. Result is better logging and less cost.

Importance of logging applications

Logging helps in debugging as well. Although debuggers are available but frankly it takes time to debug an application using a debugger. An application can be debugged more easily with few well-placed logging messages. So we can safely say that logging is a very good debugging tool. If logging is done sensibly and wisely, it can provide detailed context for application failures.

In distributed applications (e.g. web/remote applications), the logging is very important. The administrator can read logs to learn about the problems that occurred during some interval.

Java's built-in APIs provide logging options but they are not that flexible. Another option is to use Apache’s open source logging framework called log4j.

Drawbacks of logging applications

There are some drawbacks of use logging in your application. For example: logging will

- pollute the code
- increase the size of the code
- reduce the speed

These are important points because, we ultimately want efficient applications. Log4J has the solution to this. You may turn on or turn off the logging at runtime by changing the configuration file. This means no change in the Java source code (binary).

Log4j

log4j is an open source project created by Apache and is part of Apache Logging Services Project. Currently Apache has 3 logging frameworks:

- log4j for Java
- log4cxx for C++
- log4net for the Microsoft .NET framework

Apache also provides a tool called Chainsaw, which can be used for log analysis. If you are interested to learn about Chainsaw, visit the following link:
Apache Chainsaw -
API docs available at:
Logger (Apache Log4j 1.2.15 API)

The log4j package can be downloaded from
Apache Logging Services Project - Apache log4j

Standard API vs log4j

A common question asked by Java developers is:

Why we should use log4j logging framework when Java provides an API for logging (java.util.logging)?

Log4j has following advantages over standard logging API:
- log4j provides robust logging
- log4j has more features available than standard logging API
- configuring and using log4j is easier
- log4j also has a much more robust formatting system
- many add-on programs and handlers are available for log4j

Configuring log4j

Configuring log4j is very simple. You have to download the log4j-xxx.jar (xxx is the version no) file from the Apache logging services web site which is:
Apache Logging Services Project - Apache log4j

Currently there are 3 different versions available which are log4j 1.2, log4j 1.3 and log4j 2.0.

Once you have the jar file, you have to include that in your CLASSPATH. In Eclipse, you can simply import that jar file in your project.

Categories of log messages

Before using log4j framework, one should be aware of different categories of log messages. Following are 5 categories:

DEBUG
The DEBUG Level is used to indicate events that are useful to debug an application. Handling method for DEBUG level is: debug().

INFO
INFO level is used to highlight the progress of the application. Handling method for INFO level is: info().

WARN
The WARN level is used to indicate potentially harmful situations. Handling method for WARN level is: warn().

ERROR
The ERROR level shows errors messages that might not be serious enough and allow the application to continue. Handling method for ERROR level is: error().

FATAL
The Fatal level is used to indicate severe events that will may cause abortion of the application. Handling method for FATAL level is: fatal().

If you declare log level as debug in the configuration file, then all the other log messages will also be recorded.
If you declare log level as info in the configuration file, then info, warn, error and fatal log messages will be recorded.
If you declare log level as warn in the configuration file, then warn, error and fatal log messages will be recorded.
If you declare log level as error in the configuration file, then error and fatal log messages will be recorded.
If you declare log level as fatal in the configuration file, then only fatal log messages will be recorded.

Main Components

There are 3 main components that are used to log messages based upon type and level. These components also control the formatting and report place at runtime. These components are:

- loggers
- appenders
- layouts


log4j.properties file

log4j.properties file is a configuration file (not in XML format). If you have a stand alone application, then log4j.properties should be in the directory where you issued the java command. In case of web application (JSP/Servlet), place log4j.properties at /WEB-INF/classes/.

A sample properties file is given below:

log4j.appender.stdout=org.apache.log4j.ConsoleAppe nder
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.Patt ernLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{MMM dd HH:mm:ss}] %-5p (%F:%L) - %m%n
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.file=C:\\Log4J\\src\\tmp\\logs \\log.txt
log4j.appender.FILE.layout=org.apache.log4j.Patter nLayout
log4j.appender.FILE.layout.ConversionPattern=[%d{MMM dd HH:mm:ss}] %-5p (%F:%L) - %m%n
log4j.rootLogger=debug, FILE,stdout

We have used only two appenders (ConsoleAppender and FileAppender)in the example above. All the possible appender options are:

AppenderSkeleton, AsyncAppender, ConsoleAppender, DailyRollingFileAppender, ExternallyRolledFileAppender, FileAppender, JDBCAppender, JMSAppender, LF5Appender, NTEventLogAppender, NullAppender, RollingFileAppender, SMTPAppender, SocketAppender, SocketHubAppender, SyslogAppender, TelnetAppender, WriterAppender

We have used PatternLayout with both the appenders. All the possible options are:

DateLayout, HTMLLayout, PatternLayout, SimpleLayout, XMLLayout

So interesting thing is, you can generate log in HTML and in XML format as well.

If you use HTMLLayout or XMLayout, then you should not mention ConversionPattern.

Example

Time for an example. I have written a class named LogTest. Its purpose is to create a Vector and populate it. After populating, I tried to add the element at its 10th index to an integer value. I want to create log for this application. My concerns are to track the vector size as well. Vector, if created using default constructor has initial capacity of 10. When capacity is reached, Vector’s capacity will be doubled which is a costly activity. That’s why I want to log the size and capacity of vector and want to know when capacity is increased. It can help me in application tuning. Also I am interested in knowing how much time it took to populate the Vector with 50 elements. Although logging activity also takes time (for printing on console, for rating to the log file), but let’s ignore this for the time being.

log4j.properties file for the application described above is as follows:

log4j.appender.stdout=org.apache.log4j.ConsoleAppe nder
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.Patt ernLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{MMM dd HH:mm:ss}] %-5p (%F:%L) - %m%n
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.file=C:\\Log4J\\src\\tmp\\logs \\log.txt
log4j.appender.FILE.layout=org.apache.log4j.Patter nLayout
log4j.appender.FILE.layout.ConversionPattern=[%d{MMM dd HH:mm:ss}] %-5p (%F:%L) - %m%n
log4j.rootLogger=debug, FILE,stdout

We have used two options for logging. On console and on file. We can use other options as well. The list line
log4j.rootLogger=debug, FILE,stdout

is very important. It is used to control logging at runtime without altering the Java code. It declares that output log should be generated on console and on to file. File path is mentioned above in the file. It also declares the logging level. Logging level is DEBUG, which means that all the log messages (debug, info, warn, error, fatal) will be recorded.

LogTest.java
Java Code:






















































public class LogTest {
private static org.apache.log4j.Logger log = Logger.getLogger(LogTest.class);

public static void main(String[] args) {

Vector<String> vector = new Vector<String>();
log.info("Vector created with size: " + vector.capacity());

boolean limitReached = false;

Long start = System.currentTimeMillis();
for(int i=0;i<50; i++)
{
vector.addElement("Element" + i);

if(limitReached)
{
limitReached = false;
log.debug("Current index: " + i);
log.info("Vector limit increased. Now the capacity is: " +  vector.capacity());
}

if(vector.capacity()-vector.size() == 1)
{
log.debug("Current index: " + i);
log.info("Current vector capacity is: " + vector.capacity());
log.info("Current vector size is: " + vector.size());
log.warn("Vector size is about to increase.");
}
if(vector.capacity()-vector.size() == 0)
{
limitReached = true;
log.debug("Current index: " + i);
log.info("Current vector capacity is: " + vector.capacity());
log.info("Current vector size is: " + vector.size());
log.warn("Vector limit reached.");
}

}

Long stop = System.currentTimeMillis();

log.info("Time for populating (in millisec): " + (stop - start));

try{
int sum = (Integer.parseInt(vector.elementAt(10)) + 10);
}
catch(java.lang.NumberFormatException e)
{
log.error(vector.elementAt(10) + " cannot be converted into integer.");
}

log.shutdown();
}
}
It is a good programming practice to shut down the logging subsystem when you finish logging.

I have used debug, info, warn and error log messages according to the logic. Of course, one can argue and can use debug in case of info or any other option. As I said, it depends on your domain and logic.

Output: log.txt
Java Code:

































[Dez 13 11:51:39] INFO  (LogTest.java:12) - Vector created with size: 10
[Dez 13 11:51:39] DEBUG (LogTest.java:30) - Current index: 8
[Dez 13 11:51:39] INFO  (LogTest.java:31) - Current vector capacity is: 10
[Dez 13 11:51:39] INFO  (LogTest.java:32) - Current vector size is: 9
[Dez 13 11:51:39] WARN  (LogTest.java:33) - Vector size is about to increase.
[Dez 13 11:51:39] DEBUG (LogTest.java:38) - Current index: 9
[Dez 13 11:51:39] INFO  (LogTest.java:39) - Current vector capacity is: 10
[Dez 13 11:51:39] INFO  (LogTest.java:40) - Current vector size is: 10
[Dez 13 11:51:39] WARN  (LogTest.java:41) - Vector limit reached.
[Dez 13 11:51:39] DEBUG (LogTest.java:24) - Current index: 10
[Dez 13 11:51:39] INFO  (LogTest.java:25) - Vector limit increased. Now the capacity is: 20
[Dez 13 11:51:39] DEBUG (LogTest.java:30) - Current index: 18
[Dez 13 11:51:39] INFO  (LogTest.java:31) - Current vector capacity is: 20
[Dez 13 11:51:39] INFO  (LogTest.java:32) - Current vector size is: 19
[Dez 13 11:51:39] WARN  (LogTest.java:33) - Vector size is about to increase.
[Dez 13 11:51:39] DEBUG (LogTest.java:38) - Current index: 19
[Dez 13 11:51:39] INFO  (LogTest.java:39) - Current vector capacity is: 20
[Dez 13 11:51:39] INFO  (LogTest.java:40) - Current vector size is: 20
[Dez 13 11:51:39] WARN  (LogTest.java:41) - Vector limit reached.
[Dez 13 11:51:39] DEBUG (LogTest.java:24) - Current index: 20
[Dez 13 11:51:39] INFO  (LogTest.java:25) - Vector limit increased. Now the capacity is: 40
[Dez 13 11:51:39] DEBUG (LogTest.java:30) - Current index: 38
[Dez 13 11:51:39] INFO  (LogTest.java:31) - Current vector capacity is: 40
[Dez 13 11:51:39] INFO  (LogTest.java:32) - Current vector size is: 39
[Dez 13 11:51:39] WARN  (LogTest.java:33) - Vector size is about to increase.
[Dez 13 11:51:39] DEBUG (LogTest.java:38) - Current index: 39
[Dez 13 11:51:39] INFO  (LogTest.java:39) - Current vector capacity is: 40
[Dez 13 11:51:39] INFO  (LogTest.java:40) - Current vector size is: 40
[Dez 13 11:51:39] WARN  (LogTest.java:41) - Vector limit reached.
[Dez 13 11:51:39] DEBUG (LogTest.java:24) - Current index: 40
[Dez 13 11:51:39] INFO  (LogTest.java:25) - Vector limit increased. Now the capacity is: 80
[Dez 13 11:51:39] INFO  (LogTest.java:48) - Time for populating (in millisec): 94
[Dez 13 11:51:39] ERROR (LogTest.java:55) - Element10 cannot be converted into integer.
Ok, we have the log file. It shows the log messages with date/time stamp.

Log messages are appended to the file so you don’t need to worry about lose of information in the log files.

Using XMLLayout

If you are interested in getting XML file with log messages, then you don’t need to change anything in the Java code. That’s the beauty of log4j framework. You simple have to add the following line in the configuration file:

log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.file=C:\\Log4J\\src\\tmp\\logs \\log.xml
log4j.appender.FILE.layout=org.apache.log4j.xml.XM LLayout
log4j.rootLogger=debug, FILE

Screenshot of output:
Log4j (Logging Framework)-xmloutput.jpg

Using HTMLLayout

Lets generate HTML log files. Put the following in the configuration file:

log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.file=C:\\Log4J\\src\\tmp\\logs \\log.html
log4j.appender.FILE.layout=org.apache.log4j.HTMLLa yout
log4j.rootLogger=debug, FILE

Screenshot of output:
Log4j (Logging Framework)-htmloutput.jpg

Conclusion

Log4J is very flexible, easy to learn and configure. It is ideal for distributed applications but it can also be used as good debugging tool for standalone applications. Logs can be generated on the console or on a text file in simple format, in XML format or in HTML format. A must use framework.

Java logical programs

Fibonacci Series

This Program generates Fibonnaci Series for a given number of times.
Output: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
public class FibonnaciSeries {
/*
* Generates the Fibonnaci Series
*/
public void generateSeries(int num) {
int f1, f2 = 0, f3 = 1;
System.out.println(“fib(0) = ” + f2);
for (int i = 1; i <= num; i++) {
System.out.println("fib(" + i + ") = " + f3);
f1 = f2;
f2 = f3;
f3 = f1 + f2;
}
}
public static void main(String[] args) {
System.out.println("*****Fibonnaci Series*****");
FibonnaciSeries fb = new FibonnaciSeries();
fb.generateSeries(10);
}
}

Highest Prime Number

Given a number this program generates the highest prime number.
Output: If the input is 25, the highest prime number close to 25 is 23. It prints 23.

public class PrimeNumber {
/*
* Given a number, finds the highest prime number.
*/
public static int highestPrime(int n) {
int value = 1;
for (int i = 2; i <= n; i++) {
// System.out.println("n: " + n + " i: " + i + " mod: " + n%i);
if (i == n) {
value = n;
break;
}
if (n % i == 0) {
n--;
}
}
return value;
}
public static void main(String[] args) {
int value = highestPrime(25);
System.out.println("Prime:" + value);
}
}

Triangle Printing

Given a number, this program prints the numbers in the right angle manner.
Output:
1
2 3
4 5 6
7 8 9 10
11 12 13 14

public class TrianglePrinting {
/*
* Prints the numbers in the right angle manner.
*/
public static void trianglePrinting(int n) {
int counter = 0, i = 1;
while (i <= n) {
counter++;
for (int j = 0; j < counter; j++) {
if (i > n)
break;
System.out.print(i + ” “);
i++;
}
System.out.println();
}
}
public static void main(String[] args) {
trianglePrinting(14);
}
}
Print Reverse number example 123 as 321

public class ReverseTest
{

public static void main(String[] args)
{
int n = 345897;
int sum = 0, rev = 0;
while(n!=0)
{
rev= n%10;
sum = (sum*10)+rev;
n = n/10;
}
System.out.println("Reverse number is "+sum);
}

}

Prime Number program

public class PrimeTest
{


public static boolean isPrime(int num)
{
boolean prime = true;
int limit = (int)Math.sqrt(num);
for(int i=2; i<=limit;i++)
{
if(num%i==0)
{
prime = false;
break;
}

}
return prime;
}
public static void main(String[] args)
{
for(int i=2;i<1000;i++)
{
if(isPrime(i))
{
System.out.print(" "+i);
}
}
}
}

Fibonacci Series

public class FibTest
{
public static void main(String[] args)
{
int f1=0,f2=0, f3 =1;
for (int i=1;i<20;i++)
{
f1 = f2;
f2= f3;
f3 = f1+f2;
System.out.print(" "+f3);
}

}

}


SumTest


public class SumTest
{
public static void main(String args[])
{
int n = 4566;
int sum =0;
while(n!=0)
{
sum = sum + (n%10);
n = n/10;
}
System.out.println("Sum is "+sum);
}
}

// Recursion

public class StringReverseTest
{
public static void main(String[] args)
{
String str = "Gangadhararao Bommasani";
str = reverse(str, str.length());
System.out.println(str);
}
public static String reverse(String input, int index)
{
if(index==0) return "";
return input.charAt(index-1)+ reverse(input, index-1);
}

}

Write a java Program to display Pyramid.
public class Pyramid {
    public static void main(String...strings){
        int i,j,k;
        for(i=1;i<=5;i++){
            for(j=5;j>=i;j--){
                System.out.print(" ");
            }
            for(k=1;k<=i;k++){
                System.out.print(" @");
            }
            System.out.println("");
        }
    }
}
Output :
           @
        @ @
      @ @ @
    @ @ @ @
  @ @ @ @ @

Check wheather String is palindrome or not?

import java.util.Scanner;
public class Practical1 {
public static void main(String argv[]){
System.out.print("Enter String ");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
StringBuffer sb = new StringBuffer(input);
String revStr = sb.reverse().toString();
if(revStr.equals(input)){
System.out.println("String is Palindrome");
}
else {
System.out.println("String is Not Palindrome");
}
}
}
/*Write a program to Find Factorial of Given no. */
class Factorial{
      public static void main(String args[]){
          int num = Integer.parseInt(args[0]);                 //take argument as command line
          int result = 1;
          while(num>0){
                result = result * num;
                num--;
          }
          System.out.println("Factorial of Given no. is : "+result);
   }
}
/* Write a program to find sum of all integers greater than 100 and
   less than 200 that are divisible by 7 */
class SumOfDigit{
      public static void main(String args[]){
      int result=0;
      for(int i=100;i<=200;i++){
           if(i%7==0)
              result+=i;
      }
      System.out.println("Output of Program is : "+result);
   }
}
/* Write a program to Swap the values */
class Swap{
      public static void main(String args[]){
      int num1 = Integer.parseInt(args[0]);
      int num2 = Integer.parseInt(args[1]);
      System.out.println("\n***Before Swapping***");
      System.out.println("Number 1 : "+num1);
      System.out.println("Number 2 : "+num2);
      //Swap logic
      num1 = num1 + num2;
      num2 = num1 - num2;
      num1 = num1 - num2;
      System.out.println("\n***After Swapping***");
      System.out.println("Number 1 : "+num1);
      System.out.println("Number 2 : "+num2);
      }
}
/*Write a program to find whether given no. is Armstrong or not.
  Example :
           Input - 153
           Output - 1^3 + 5^3 + 3^3 = 153, so it is Armstrong no. */
class Armstrong{
      public static void main(String args[]){
      int num = Integer.parseInt(args[0]);
      int n = num; //use to check at last time
      int check=0,remainder;
      while(num > 0){
           remainder = num % 10;
           check = check + (int)Math.pow(remainder,3);
           num = num / 10;
      }
      if(check == n)
            System.out.println(n+" is an Armstrong Number");
      else
            System.out.println(n+" is not a Armstrong Number");
   }
}
/* Write a program to Find whether number is Prime or Not. */
class PrimeNo{
      public static void main(String args[]){
          int num = Integer.parseInt(args[0]);
         int flag=0;
         for(int i=2;i<num;i++){
             if(num%i==0)
              {
                 System.out.println(num+" is not a Prime Number");
                 flag = 1;
                 break;
              }
         }
         if(flag==0)
             System.out.println(num+" is a Prime Number");
    }
}
/* Write a program to generate Harmonic Series.
   Example :
           Input - 5
           Output - 1 + 1/2 + 1/3 + 1/4 + 1/5 = 2.28 (Approximately) */
class HarmonicSeries{
      public static void main(String args[]){
      int num = Integer.parseInt(args[0]);
      double result = 0.0;
      while(num > 0){
            result = result + (double) 1 / num;
            num--;
      }
      System.out.println("Output of Harmonic Series is "+result);
  }
}
/* Display Triangle as follow
    0
    1 0
    1 0 1
    0 1 0 1 */
class Output2{
      public static void main(String args[]){
           for(int i=1;i<=4;i++){
              for(int j=1;j<=i;j++){
                            System.out.print(((i+j)%2)+" ");
                    }
                    System.out.print("\n");
                 }
     }
}       

Advance Java Blogging

Java New Articles

Javas Latest News

Java Web Services and XML

Ajax Latest News

Mac OS Java Features

Advance Spotlights

Patterns Features