Skip to Content
Author's profile photo Former Member

Generic logger

I guess everyone will agree that proper logging and tracing is crucial for quick and easy problem diagnostics and solving. Yet, it is still not used as it should be. Often logging is used in places which are not that critical and is not used enough on places where it’s a must.
The main reason for this, in my opinion, is that yet the logging infrastructure in SAP NetWeaver is a bit clumsy and it takes relatively big effort to log something. What I mean, classic example of logging is as follows:

In the beginning of the class one would define

private static final Location location = Location.getLocation(MyClass.class); 

 

then at every beginning of method

location.pathT(“MyClass”, “Entering default constructor”, new Object[] {param1, param2, param3} );

 

some people make it even more extravagant (for the sake of clarity in the code) like this

final String SIGNATURE = “init(Channel, Handler, boolean)”;
location.entering(SIGNATURE, new Object[] { channel.getName(),  handler.getName(), startup});

So, what it would be like if we could log everything with one simple line and this line differs a little bit in the different locations in the code so that logging could be easier? And when it’s easier, it will be used much more frequently.
The best would be if we could supply only custom message and list of parameters and then it works out the method name (and its signature) on its own.
Then I started thinking of how we could identify the method name and it came to my mind that a StackTraceElement has the method and class name and a StackTraceElementcould be obtained only through Exception. But Exception would be available only if we had an exceptional situation in our logic, then what about if we manually created one and used it just to extract our information from its stack trace? So, this would look like this:

public class MyLogger {
    public static void logParameters(Object param1, Object param2){
        Exception ex = new Exception();
        if(ex.getStackTrace() == null || ex.getStackTrace().length< 2){
            return;
        }
        String className = ex.getStackTrace()[1].getClassName();
        String method = ex.getStackTrace()[1].getMethodName();
        int line = ex.getStackTrace()[1].getLineNumber();
       
        Location location = Location.getLocation(className);
        location.pathT(method+line, “param: {0} \n\r\n\rparam:  {1}\n\r\n\r”, new Object[]{param1, param2});
    }

    public static void logExit(){
        Exception ex = new Exception();
        if(ex.getStackTrace() == null || ex.getStackTrace().length< 2){
            return;
        }
        String className = ex.getStackTrace()[1].getClassName();
        String method = ex.getStackTrace()[1].getMethodName();
        int line = ex.getStackTrace()[1].getLineNumber();
       
        Location location = Location.getLocation(className);
        location.exiting(method + line);
    }
}
 

Then at the beginning and at the end of each method in my code I would put as follows:

public void myMethod(String param1, Object param2){
    MyLogger.logParameters(param1, param2);
    //code goes here…
    MyLogger.logExit();
}
 

Of course, custom message parameter could be added to each one of the series (e.g. logParameter(String message, Object param1)) and common logic could be extracted in another (private) method.  Also, logic for identifying the exact method signature (through java.lang.Class) and other types of logging (catching, throwable, error, info etc.) could be included.

So far so good. The only not so good thing I see here is that the majority of the logic is executed each time regardless of what is the current level of logging. Furthermore it might be not so efficient to create an Exception object just to recognize that current logging level is ERROR and you wanted to log something with lover priority. In that situation there could be many solutions; however, the easiest one that I see is to avoid this dynamic creation of location. Something like that:

Have your location defined at the beginning of your class definition

private static final Location location = Location.getLocation(MyClass.class);

and then all logging methods modified like that:

    public static void logParameters(Location location, Object param1, Object param2){
        if(location.bePath()){
            Exception ex = new Exception();
            if(ex.getStackTrace() == null || ex.getStackTrace().length<2){
                return;
            }
            String className = ex.getStackTrace()[1].getClassName();
            String method = ex.getStackTrace()[1].getMethodName();
            int line = ex.getStackTrace()[1].getLineNumber();
           
            location.pathT(method+line, “param: {0} \n\r\n\rparam: {1}\n\r\n\r”, new Object[]{param1, param2});
        }
    }
    

I would also go one step further and have some methods for default logging of some predefined types, for example Map, so that it goes through all key value pairs and appropriately invokes toString() for each key and value.

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Siarhei Pisarenka
      Siarhei Pisarenka
      The utility seems to be useful and elegant.

      Small note: for tracing of method invocations this is the pair that should be used:

      Location.entering(methodName, params);
      ...
      Location.exiting(methodName, result);

      /* exit in short form: */
      Location.exiting(result);