You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-user@logging.apache.org by Scott Doherty <sd...@kc.rr.com> on 2002/10/23 07:58:26 UTC

Log4J design question: this.getClass() in super class

Design question about using Log4J in an application's framework. 

 

I wish to leverage Log4j in applications being built at my company. I've
been reading quite a bit and watching this list for awhile now. I would
like your input into architecture and design using Log4j.

 

Logger log = Logger.getLog(myClass.class);

Logger log = Logger.getLog(this.getClass());

 

I'm debating the above choice for logger naming. It is sometimes common
that applications built in my company inherit from an Abstract class for
that application. 

 

For example, if I am writing a Banking Application for my company, an
abstract class called BankingSkeleton might be used. Most of the objects
in this application would inherit from BankingSkeleton. BankingSkeleton
would provide behavior common to all objects in this application.

Public abstract class BankingSkeleton extends Object

{

}

Public abstract class Account extends BankingSkeleton

{

}

public class CheckingAccount extends Account

{

}

 

In the reading material about Log4j, it appears that the standard
approach to provide hierarchical based logging in each of these classes
would be to create a static attribute in each class using the class name
as the category's name. 

 

package com.company.banking;

 

abstract class BankingSkeleton extends Object

{

}

class Account extends BankingSkeleton

{

static Logger log = Logger.getLog(Account.class);

}

class CheckingAccount extends Account

{

static Logger log = Logger.getLog(CheckingAccount.class);

}

 

If I were to log a message from a method in each of these classes, it
would look something like this if displaying the logger in the appender
using %c in the PatternLayout:

631   [main] DEBUG com.company.banking.Account  - A message

1071 [main] DEBUG com.company.banking.CheckingAccount  - A message

 

This is great with the exception of a few things. Many of our projects
are completed by a team of developers with varying experience. Each
developer needs to remember to place the log attribute in their class
instead of inheriting log from its super class. Each developer needs to
properly provide the logger name to honor the hierarchy of the logger
naming, for example, "CheckingAccount.class" instead of "Account.class"
when getting the log. When writing this email, I myself copied the log
attribute from the Account class to the CheckingAccount class and at
first, simply forgot to update the logger name in the Logger.getLog
method. If a developer of a class simply doesn't write any logging and
never creates the log attribute for that class, I can foresee production
support developers who need to get something logged to troubleshoot a
problem might sloppily add code inside a method that obtains a logger
something like the following:

 

class sloppyAccount extends BankingSkeleton

{

            public void aSloppyMethod()

            {

                        Logger.getLog("IDunno").debug("A message");

            }

}

 

Notice that the logger, IDunno,  is no longer in the hierarchy and
becomes less manageable via the Log4j configuration properties. 

1452 [main] DEBUG IDunno  - A message

 

I would like the BankingSkeleton to provide the log attribute to all of
its sub-classes, eliminating the need for each class developer to
concern themselves with getting the correct logger.

 

package com.company.banking;

 

abstract class BankingSkeleton extends Object

{

static Logger log = Logger.getLog(BankingSkeleton.class);

}

class Account extends BankingSkeleton

{

}

class CheckingAccount extends Account

{

}

 

Problem above is that all logging is from the BankingSkeleton logger
which eliminates the logger hierarchy. Modifying to "this.getClass()" in
order to obtain the class name from the object's instance re-instates
the logging name hierarchy and enforces desired logger hierarchy.

 

package com.company.banking;

 

abstract class BankingSkeleton extends Object

{

static Logger log = Logger.getLog(this.getClass());

}

class Account extends BankingSkeleton

{

}

class CheckingAccount extends Account

{

}

 

However, since its static, the last object instantiated changes the
logger for all instances of BankingSkeleton, including all subclasses,
so its now necessary to also make log non-static.

package com.company.banking;

 

abstract class BankingSkeleton extends Object

{

Logger log = Logger.getLog(this.getClass());

}

class Account extends BankingSkeleton

{

}

class CheckingAccount extends Account

{

}

 

Everything is fine, except now I must have an instance of the class to
log. This means I cannot log from a static method to the log as I could
previously. Since log is no longer static, I also have an instance of
log for every instance of every class resulting in additional object
creation and cleanup whereas in the beginning I only had one logger for
each class..or am I wrong about that? Do I actually have a reference to
the same logger for each class since Logger.getLogger(this.getClass())
would return the same object reference for every instance of the same
class? Anything else wrong with this approach? 

 

To solve the lack of logging from my static methods, I contemplated the
following:

 

abstract class BankingSkeleton extends Object

{

Logger log = Logger.getLog(this.getClass());

static Logger staticLog = Logger.getLog(BankingSkeleton.class);

}

 

Now when a developer needs to log from a static method from one of the
sub-classes, they call staticLog instead.

 

Your thoughts and experience for integrating Log4j into application's
framework would be greatly appreciated.

 

 


Re: Log4J design question: this.getClass() in super class

Posted by Ceki Gülcü <ce...@qos.ch>.
The following will not compile:

package com.company.banking;
abstract class BankingSkeleton extends Object {
   static Logger log = Logger.getLog(this.getClass());
}

You do not have an instance, so "this.getClass()" is illegal.

What are you trying to achieve? If it is to eliminate the probability of 
error when creating a logger in a new class, I suggest defining a template 
in your development environment.

An alternative pattern for defining loggers in your classes is through a 
getter method in each class:

package com.company.banking;
abstract class BankingSkeleton extends Object {
   Logger logger;

   Logger getLogger() {
      if(logger == null) {
         logger = Logger.getLogger(this.getClass());
      }
      return logger;
   }

   void foo() {
      getLogger().debug("hi");
   }
}

public abstract class Account extends BankingSkeleton {
   Logger logger;

   Logger getLogger() {
      if(logger == null) {
         logger = Logger.getLogger(this.getClass());
      }
      return logger;
   }

   void bar() {
      foo();
      getLogger().debug("hi again");
   }
}

So the pattern is:

public class XYZ {
   Logger logger;

   Logger getLogger() {
      if(logger == null) {
         logger = Logger.getLogger(this.getClass());
      }
      return logger;
   }
}

which you can safely cut and paste to new classes.

The disadvantages are that the logger field is no longer static. Second, we 
have replaced one line of code with seven lines of code, albeit completely 
generic.

At 00:58 23.10.2002 -0500, you wrote:
>Design question about using Log4J in an application's framework.
>
>
>
>I wish to leverage Log4j in applications being built at my company. I've
>been reading quite a bit and watching this list for awhile now. I would
>like your input into architecture and design using Log4j.
>
>
>
>Logger log = Logger.getLog(myClass.class);
>
>Logger log = Logger.getLog(this.getClass());
>
>
>
>I'm debating the above choice for logger naming. It is sometimes common
>that applications built in my company inherit from an Abstract class for
>that application.
>
>
>
>For example, if I am writing a Banking Application for my company, an
>abstract class called BankingSkeleton might be used. Most of the objects
>in this application would inherit from BankingSkeleton. BankingSkeleton
>would provide behavior common to all objects in this application.
>
>Public abstract class BankingSkeleton extends Object
>
>{
>
>}
>
>Public abstract class Account extends BankingSkeleton
>
>{
>
>}
>
>public class CheckingAccount extends Account
>
>{
>
>}
>
>
>
>In the reading material about Log4j, it appears that the standard
>approach to provide hierarchical based logging in each of these classes
>would be to create a static attribute in each class using the class name
>as the category's name.
>
>
>
>package com.company.banking;
>
>
>
>abstract class BankingSkeleton extends Object
>
>{
>
>}
>
>class Account extends BankingSkeleton
>
>{
>
>static Logger log = Logger.getLog(Account.class);
>
>}
>
>class CheckingAccount extends Account
>
>{
>
>static Logger log = Logger.getLog(CheckingAccount.class);
>
>}
>
>
>
>If I were to log a message from a method in each of these classes, it
>would look something like this if displaying the logger in the appender
>using %c in the PatternLayout:
>
>631   [main] DEBUG com.company.banking.Account  - A message
>
>1071 [main] DEBUG com.company.banking.CheckingAccount  - A message
>
>
>
>This is great with the exception of a few things. Many of our projects
>are completed by a team of developers with varying experience. Each
>developer needs to remember to place the log attribute in their class
>instead of inheriting log from its super class. Each developer needs to
>properly provide the logger name to honor the hierarchy of the logger
>naming, for example, "CheckingAccount.class" instead of "Account.class"
>when getting the log. When writing this email, I myself copied the log
>attribute from the Account class to the CheckingAccount class and at
>first, simply forgot to update the logger name in the Logger.getLog
>method. If a developer of a class simply doesn't write any logging and
>never creates the log attribute for that class, I can foresee production
>support developers who need to get something logged to troubleshoot a
>problem might sloppily add code inside a method that obtains a logger
>something like the following:
>
>
>
>class sloppyAccount extends BankingSkeleton
>
>{
>
>             public void aSloppyMethod()
>
>             {
>
>                         Logger.getLog("IDunno").debug("A message");
>
>             }
>
>}
>
>
>
>Notice that the logger, IDunno,  is no longer in the hierarchy and
>becomes less manageable via the Log4j configuration properties.
>
>1452 [main] DEBUG IDunno  - A message
>
>
>
>I would like the BankingSkeleton to provide the log attribute to all of
>its sub-classes, eliminating the need for each class developer to
>concern themselves with getting the correct logger.
>
>
>
>package com.company.banking;
>
>
>
>abstract class BankingSkeleton extends Object
>
>{
>
>static Logger log = Logger.getLog(BankingSkeleton.class);
>
>}
>
>class Account extends BankingSkeleton
>
>{
>
>}
>
>class CheckingAccount extends Account
>
>{
>
>}
>
>
>
>Problem above is that all logging is from the BankingSkeleton logger
>which eliminates the logger hierarchy. Modifying to "this.getClass()" in
>order to obtain the class name from the object's instance re-instates
>the logging name hierarchy and enforces desired logger hierarchy.
>
>
>
>package com.company.banking;
>
>
>
>abstract class BankingSkeleton extends Object
>
>{
>
>static Logger log = Logger.getLog(this.getClass());
>
>}
>
>class Account extends BankingSkeleton
>
>{
>
>}
>
>class CheckingAccount extends Account
>
>{
>
>}
>
>
>
>However, since its static, the last object instantiated changes the
>logger for all instances of BankingSkeleton, including all subclasses,
>so its now necessary to also make log non-static.
>
>package com.company.banking;
>
>
>
>abstract class BankingSkeleton extends Object
>
>{
>
>Logger log = Logger.getLog(this.getClass());
>
>}
>
>class Account extends BankingSkeleton
>
>{
>
>}
>
>class CheckingAccount extends Account
>
>{
>
>}
>
>
>
>Everything is fine, except now I must have an instance of the class to
>log. This means I cannot log from a static method to the log as I could
>previously. Since log is no longer static, I also have an instance of
>log for every instance of every class resulting in additional object
>creation and cleanup whereas in the beginning I only had one logger for
>each class..or am I wrong about that? Do I actually have a reference to
>the same logger for each class since Logger.getLogger(this.getClass())
>would return the same object reference for every instance of the same
>class? Anything else wrong with this approach?
>
>
>
>To solve the lack of logging from my static methods, I contemplated the
>following:
>
>
>
>abstract class BankingSkeleton extends Object
>
>{
>
>Logger log = Logger.getLog(this.getClass());
>
>static Logger staticLog = Logger.getLog(BankingSkeleton.class);
>
>}
>
>
>
>Now when a developer needs to log from a static method from one of the
>sub-classes, they call staticLog instead.
>
>
>
>Your thoughts and experience for integrating Log4j into application's
>framework would be greatly appreciated.
>
>
>
>

--
Ceki

TCP implementations will follow a general principle of robustness: be
conservative in what you do, be liberal in what you accept from
others. -- Jon Postel, RFC 793



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>