[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Using Log4j across classes

Posted on 2011-10-19
20
Medium Priority
?
1,313 Views
Last Modified: 2012-05-12
Hi Experts...
I use looging from log4j in my java programs.
I get the logger using the below command:
static Logger logger = Logger.getLogger(TestLogging.class.getName());
How do i have a common logger for say more than one java class.
Please help...
0
Comment
Question by:gaugeta
  • 7
  • 6
  • 5
  • +2
20 Comments
 
LVL 47

Expert Comment

by:for_yan
ID: 36991049

this is from:
http://logging.apache.org/log4j/1.2/manual.html
Calling the getLogger method with the same name will always return a reference to the exact same logger object.

For example, in

   Logger x = Logger.getLogger("wombat");
   Logger y = Logger.getLogger("wombat");

x and y refer to exactly the same logger object.

Thus, it is possible to configure a logger and then to retrieve the same instance somewhere else in the code without passing around references. In fundamental contradiction to biological parenthood, where parents always preceed their children, log4j loggers can be created and configured in any order. In particular, a "parent" logger will find and link to its descendants even if it is instantiated after them.
0
 
LVL 4

Expert Comment

by:reijnemans
ID: 36991051
What do you exactly mean, When I use log4J I always define a new logger, de "default" log4j will get the class and writes the log were ever you configured it

static Logger logger = Logger.getLogger([i]classname[/i].class);

Open in new window


Unless I want to have somecode logged to a special file, then I define other/second logger

static Logger logger = Logger.getLogger("loggerToOtherFile");

Open in new window

0
 
LVL 47

Expert Comment

by:for_yan
ID: 36991056
Further they point out that it is often convenient and good organization to name by class
but  it is not necessary, do you can invoke the same logger in different classes
and the logeger named by one clas can be clled and used in another calss
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 47

Expert Comment

by:for_yan
ID: 36991090



I think tyhis is a good explanation of all options

from

http://stackoverflow.com/questions/3038079/using-same-log4j-logger-in-standalone-java-application
(in particuylar option B applies directly to yourt question):
      

A) in Log4J, you have logger hierarchies, not a single logger. This typically boils down to one logger per class, where loggers are identified by classname. The logger is initialized like this:

private static final Logger logger = Logger.getLogger(MyClass.class);

This is a good practice in that it allows you to fine-tune logging behaviour for modules (packages) or even individual classes within your app. So you may disable logging for some packages, log at INFO level in others, and log on DEBUG level for some critical classes e.g. when you want to catch a bug.

B) However, if you want a single logger everywhere, simply use the root logger in every class:

private static final Logger logger = Logger.getLogger();

C) for calls to not too complex methods, the performance difference is likely negligible, as the JIT compiler will agressively inline calls anyway. For complicated methods it is more of an open question.

Note that the method you show does unnecessary work by loading logger configuration - this is done automatically by Log4J if you name your config file log4j.properties and put it on the classpath. However, even if you need to use a nonstandard config file name, you could still load the Log4J configuration in a single place upon startup, and omit the lazy loading of the logger. Then what is left is

private static final Logger logger = Logger.getLogger(ExtractData.class);

private static Logger getLogger() {
    return logger;
}

and this will surely be inlined by the compiler. You may want to retain getLogger nevertheless, to avoid modifying a lot of caller code.

Note that it is unnecessary for getLogger to be public, as all classes are supposed to have their own logger reference anyway.
0
 

Author Comment

by:gaugeta
ID: 36991112
@for_yan:Thanks for the reply.
Considering the case B)
private static final Logger logger = Logger.getLogger();
returns an error stating:  The method getLogger(String) in the type Logger is not applicable for the arguments ().
How do i solve this.
Please help...
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36991148
I assume they meant this method:

public static Logger getRootLogger()

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 36991154
>>How do i have a common logger for say more than one java class.

Why would you want that actually? It's not usually a good way of organizing logging
0
 

Author Comment

by:gaugeta
ID: 36991175
@for_yan:Thanks for replying.
I added the below method and it works fine.But i have to add this method in all the classes of the application.Or do i have an alternative.

@CEHJ:Thanks for the reply.
So how else can i improve this?Or what other option do i have?

Please help...
0
 

Author Comment

by:gaugeta
ID: 36991181
Code added in all classes
public static Logger getLogger() { 
	   if (logger != null) return logger; 
	   try { 
		   
	   PropertyConfigurator.configure("log4j.properties"); 
	   logger = Logger.getLogger(ClassName.class); 
	    
	   } catch (Exception exception) { 
	   exception.printStackTrace(); 
	   } 
	   return logger;
	   }

Open in new window

0
 
LVL 47

Expert Comment

by:for_yan
ID: 36991184
No, I think once you say in the your MainClass



static Logger mylogger = Logger.getRootLoger();

then everywher youjust use

MainClass.mylogger

as any static variable
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 36991200
>>
So how else can i improve this?Or what other option do i have?

Please help...
>>

Normally speaking, you want logging to be as granular as possible, so that the behaviour of individual classes can be observed in isolation from others. What you're asking for is the opposite. Nearly always you want the following
Logger logger = Logger.getLogger(TestLogging.class);

Open in new window

0
 

Author Comment

by:gaugeta
ID: 36991344
@for_yan::Thanks for replying.
But is i do that i will not know the class in which any exception occurs since the logger was defined in the parent class.
I have my appender status as log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n and the class displayed is the main class in which it was defined as static and public and not the class in which exception occured.
Please help...
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 36991349
You still haven't said WHY you want a common logger...
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36991352
but I guess you still can have printStackTrace with full information where exception occurred
0
 

Expert Comment

by:chinhw
ID: 36991361
@gaugeta
I do not recommend you use log4J in this manner. You can make use of the "Named Hierarchy" nature of log4J to archieve what you are trying to do.

Suppose you have 2 java classes.
1) A.B.C.D1
2) A.B.C.D2

In (1)
static Logger logger = Logger.getLogger("A.B.C.D1");
In (2)
static Logger logger = Logger.getLogger("A.B.C.D2");

In your log4J settings.
Set a logger for "A.B.C"

Log4J in (1) and (2) will use logger "A.B.C" because of "Name Hierarchy".

Alternatively.
You can also define 2 logger in log4J settings.
One for "A.B.C.D1" and another for "A.B.C.D2".
The logger for (1) and (2) uses the same appender.

--------------------------
The benefit of this is that you will have more control over what you are going to log without changing code.
Example: You can choose not to log (2) by just changing the log4J settings without having the need to change code.

0
 
LVL 47

Expert Comment

by:for_yan
ID: 36991363


tht's how you can put stacktrace of exception to logger:
http://stackoverflow.com/questions/4347797/how-to-send-a-stacktrace-to-log4j
0
 

Author Comment

by:gaugeta
ID: 36993041
@for_yan:Thanks for the reply.
I have the following two java files and the log4j properties files as well.
When the exception occurs i get the message as shown below as well.
I want to retain the same format but add a user defined message at each function as well in which exception occurs.
How do i achieve this.
Please help...

import java.util.Properties;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

 public class TestLogging {

   //static Logger logger = Logger.getLogger(TestLogging.class.getName());
   public static Logger logger =TestLogging.getLogger();


   public static void main(String[] args) {
	   PropertyConfigurator.configure("log4j.properties");
try
{
	TestLogging2.main1();
	//String s=args[4];
     // BasicConfigurator replaced with PropertyConfigurator.
     

     logger.debug("Entering application.");
     logger.info("Exiting application.");
}
catch(Exception e)
{
	  
	  String stackStr = null;
	  StackTraceElement[] stk = e.getStackTrace();
	  for (int i = 0; i < stk.length ; i++)
	  {                                               
		  stackStr += "Level [" + Integer.toString(i) + "] - File Name: '" + stk[i].getFileName() + "' Method Name: '" + stk[i].getMethodName() +"' Line Number: '" + stk[i].getLineNumber()+"' Message: '" + e.toString() + "'\n";
	  }   
	  
	  logger.debug("Exception occured "+stackStr);
	  logger.debug("Exception ended");
}
   }
   public static Logger getLogger() 
   { 
	   if (logger != null) return logger; 
	   try 
	   { 
		   PropertyConfigurator.configure("log4j.properties"); 
		   logger = Logger.getLogger(TestLogging.class); 
	    
	   } 
	   catch (Exception exception) 
	   { 
		   exception.printStackTrace(); 
	   } 
	   return logger;
   } 


 }

Open in new window

import java.util.Properties;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

 public class TestLogging2  {

	 


   public static void main1() throws Exception {
	   PropertyConfigurator.configure("log4j.properties");

	main2();
     // BasicConfigurator replaced with PropertyConfigurator.
     

     TestLogging.logger.debug("Entering application.");
     TestLogging.logger.info("Exiting application.");


   }
   
   public static void main2() throws Exception
   {
	 
	   String args[]={"hello"};
		String s=args[4];
	     // BasicConfigurator replaced with PropertyConfigurator.
	     

	     TestLogging.logger.debug("Entering application.");
	     TestLogging.logger.info("Exiting application.");
	 
	  
   }
   
   }

Open in new window

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%m%n

Open in new window

Exception occured nullLevel [0] - File Name: 'TestLogging2.java' Method Name: 'main2' Line Number: '30' Message: 'java.lang.ArrayIndexOutOfBoundsException: 4'
Level [1] - File Name: 'TestLogging2.java' Method Name: 'main1' Line Number: '16' Message: 'java.lang.ArrayIndexOutOfBoundsException: 4'
Level [2] - File Name: 'TestLogging.java' Method Name: 'main' Line Number: '18' Message: 'java.lang.ArrayIndexOutOfBoundsException: 4'

Exception ended

Open in new window

0
 
LVL 86

Accepted Solution

by:
CEHJ earned 2000 total points
ID: 36993076
>>but add a user defined message at each function as well in which exception occurs.

The question seems to have wandered somewhat, but
logger.error("My user message", e); // 'e' is the Exception

Open in new window

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 36993092
You also need to read up on formatting - you don't need to do anything but use the correct format string:

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 37082002
:)
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I had a project requirement for a displaying a user workbench .This workbench would consist multiple data grids .In each grid the user will be able to see a large number of data. These data grids should allow the user to 1. Sort 2. Export the …
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
The viewer will learn how to implement Singleton Design Pattern in Java.
Suggested Courses
Course of the Month17 days, 18 hours left to enroll

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question