views:

85

answers:

3

for example I want to replace before compilation:

#debug("${enclosing_method} this is debug message for " + userName)

with:

if (log.isDebugEnabled())
{
  log.debug("<real method name> this is debug message for " + userName);
}
+2  A: 

I would recommend AspectJ to accomplish your goal. It is not a preprocessor, but an aspect-oriented metaprogramming language for Java. You get all sorts of advantages by using AspectJ, like type safety and IDE support. It is quite a powerful language.


To do what I think you want, I would recommend specifying a pointcut to match everything you would like to put your logging into. For example, this matches all the methods in MyType (you'll want something specific to your own code):

pointcut loggedMethod() execution(* *(..)) && this(MyType);

Then, you'll want to give advice to inject your logging statements:

before() : loggedMethod() {
    Log log = iDontKnowWhereLogComesFrom();
    if (log.isDefaultEnabled()) {
        String methodName = thisJoinPoint.getKind();
        log.debug(methodName + " is the debug message for " + iDontKnowWhereUsernameComesFrom);
    }
}

Which looks way wordier, except that you automatically support adding logging to any method that matches the pointcut without any changes, which means your actual methods can just look like:

public void foo() {
    // do whatever processing you want here without having to worry about the
    // cross-cutting concern of logging, since it is not at all associated with
    // your business logic
}

In my personal experience, this is a way more sustainable pattern than trying to implement and maintain your own custom preprocessor for this.

Travis Gockel
but it is done in runtime, therefore I have performance penalty
ohadshai
@ohadshai: using performance cycles on getting the program to do what you want isn't really a penalty.
Graham Lee
You can choose to do either *compile-time* or *load-time* weaving, each with its own relative merits.
Travis Gockel
I think getting the method name in runtime will have to use reflection, and I would like to spare that time.
ohadshai
That's the advantage to AspectJ, you *don't* have to do it at runtime. It will literally do *exactly* what you're looking for. At compile time, if you so desire. AspectJ with compile-time weaving is *exactly* what you're looking for.
Travis Gockel
can you give an example?
ohadshai
I've updated my answer to provide a quick-and-dirty example.
Travis Gockel
I have 2 questions regarding the example: 1. can I use strings that are in the method, in the example : " is the debug message for ". 2. is there a way to call it just in a specific point that was defined in the method? I mean not doing it before the method.
ohadshai
1: No. 2: No, you can call it only at AspectJ's supported advice points, which do not include "arbitrary." After reconsidering your problem, why is it the callee's responsibility to filter itself? It makes more sense to me if the `log` object performed the filtering for you.
Travis Gockel
by filtering you mean the check isDebugEnabled()? the reason I am asking the question is two: if debug is not enabled I want to save string concatenation and other manipulations that are done in the log.debug before it is called. in addition I want it to be robust to method name change or code movement between method (ie: I dont want to specify the name).
ohadshai
Yes. But you can easily create a method with a signature like `void writeMessage(String format, Object... args)` to do lazy string formatting for you. And moving that to a centralized class is *more* robust, since you're only doing 1 method call, not two (or more).
Travis Gockel
+2  A: 

Consider using log4j if your example reflects your primary aim.

Quote needed: Preprocessor usage is bad OO practice could be of interest as well.

zellus
the example is using log4j. I didnt supply the full source code. I want the code to be robust to method name change and to be short and elegant :)
ohadshai
Thanks for the reference
ohadshai
Sorry for not getting your point at first. Are you looking for an elegant way to determine the class name. http://www.java2s.com/Code/Java/Reflection/Getthecurrentmethodname.htm could be a starting point.
zellus
It is a start, but not elegant one...:)
ohadshai
I agree, it's far from being elegant!
zellus
apperanly this is going to be possible in java 7: http://weblogs.java.net/blog/forax/archive/2010/10/26/how-get-current-class-java I hope they will do it also for method name
ohadshai
+1  A: 

Don't. Use slf4j instead which allows you to avoid the check with {}.

Thorbjørn Ravn Andersen
from a quick look over there, I didnt see any way to get the method name easily. Is there?
ohadshai
Depends on the actual logger used behind slf4j. With logback use the %method conversion in a PatternLayout: http://www.slf4j.org/manual.html#typical_usage
Thorbjørn Ravn Andersen
do you know if log4j have such pattern?
ohadshai