tags:

views:

226

answers:

5

Hello,

I am looking for an easy way (say, a single script/batch file or a simple program) to instrument a set of Java source files so that each method has an added System.out.println statement on entry and exit.

I could not find such a utility. The reason I need this (and why it has to work on source files and not .class files) is that the target system is an embedded Java system..

Thanks in advance, pd

+1  A: 

You probably didn't find much because using System.out would be a pretty horrendous way to instrument an application.

What are you trying to do - analyze performance, code coverage, etc? If so, there are plenty of tools for either.

matt b
I am trying to do first stage analysis of a tricky bug - first get coverage info, then add some more printouts in relevant places to see what goes one. I should have mentioned that I cannot use a debugger to step through the code at the moment (the system's debugging support is broken for the time being) and so have to rely on printouts. I am well aware that this is a horrendous way to do this, but nonetheless something I want to try.
In this case, perhaps you can use some sort of AOP to interweave advice at each method call to print a statement before/after? Not sure if that is an option with embedded device.
matt b
It's still the case that you should be looking at log4j rather than System.out.println(). Won't help you with automating the insertion, but you get far more control once those lines are present.
PanCrit
+6  A: 

This is an excellent use case for Aspect Oriented Programming.

Kees de Kooter
.. together with logging (log4j) instead of using 'System.out.println'
Andreas_D
A: 

I've done it before when stuck in a situation where nothing else works. I've actually gone in and inserted a sysout every other lines once I had it down to the correct method.

(For instance, I was just working on a JVM where RMI calls that threw an exception were silently eaten and the calling thread just hung indefinitely! Oh, and of course, we couldn't use a debugger. How else do you find that??)

Anyway, just running a program that inserts debug output EVERYWHERE won't help. You'll get lost analyzing the pages of output. Instead try to bracket where the problem is and manually insert output lines there.

If your thread "Vanishes" on a single line or takes an unexpected turn, break that line up into it's minimal runnable pieces, figure out which piece is failing, then dive into that and repeat--not much else to do.

By the way, another helpful tool--even on a very old JVM, at any point you can throw in a "(new Exception()).printStackTrace();" to dump out the stack without effecting program flow. If you find yourself at a location and don't know how you got there, this can help.

Finally if you want to be really lazy, you can use a single static method to do all your debug output (one that just delegates to System.out.println), and add a couple lines to get a stack trace, grab only the "Calling" line/method and print it out before the debug statement giving you a poor-man's logging utility.

Just some manual debugging tricks I've learned from years of messing with old versions of java on embedded platforms.

Bill K
A: 

I agree with Kees, you should use Aspect Oriented Programming to automatically add logging to every function. I do something similar for timing with the following code:

import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.util.StopWatch;

@Aspect
public class ProfilingAspect {

    @Around("methodsToBeProfiled()")
    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch sw = new StopWatch(pjp.getSignature().getClass().getSimpleName());
        try {
            sw.start(pjp.getSignature().getName());
            return pjp.proceed();
        } finally {
            sw.stop();
            LogFactory.getLog(pjp.getSignature().getClass()).debug(sw.shortSummary());
        }
    }

    @Pointcut("execution(public * *.*(..))")
    public void methodsToBeProfiled(){}
}

This is pretty much the simplest kind of aspect you can add. The key parts are the pointcut annotation which declares that you want this aspect to be applied to every public method of every public class in every package no matter what its return type or input parameters. You probably want to make that more specific. The @Around annotation refers to the pointcut and specifies a bunch of code that you want executed 'around' the function. In your case, if you only want logging on a function being called you could replace the @Around with @Before or @AfterReturning depending on where you want the logging. If you're doing all the building of the application, aim for 'compile time weaving' as opposed to load time. It reduces the runtime requirements of your application.

Jherico
A: 

I have written an extension for slf4j which provides the functionality you are looking for (except as a logger call instead of System.out, but it is simple to send logger calls to System.out).

Have a look at http://www.slf4j.org/extensions.html#javaagent

Thorbjørn Ravn Andersen