# Ablaufverfolgung eines Java-Programmes



## gravitex (6. September 2006)

Hallo.
Ich versuche ein komplexes Java-Projekt zu verstehen.
Sehr schön wäre ein Tool, welches einem beim
Laufenlassen des Programmes ausgeben kann, welche Funktionen
betreten und verlassen werden (am besten mit Parameterwerten),
ohne das man jetzt in alle Fkt. Breakpunkte setzt.
Sowas muß ja über die Debugger-Schnittstelle möglich sein.
Habe mal gegoogelt, gibt ja einige externe Java-Debugger.
Weiß jemand, ob einer von diesen sowas kann ?
Gruß,
Stefan

Ich stelle mir in etwa so eine Ausgabe vor 
(damit ihr versteht, was ich meine):

--->main()
------>ClassIrgndwas.func1()
--------->ClassABC.funcX()
---------<ClassABC.funcX()
--------->ClassABC.funcY()
----------->ClassDEF.funcZ()
-----------<ClassDEF.funcZ()
---------<ClassABC.funcY()
------<ClassIrgndwas.func1()
<---main()


----------



## munuel (6. September 2006)

Hallo,
Wenn du eclipse als IDE verwendest kannst du bequem von Funktion zu Funktion springen wenn du im Debug-Modus bist.Allerdings bekommst du dabei keine Ausgabe, das müsstest du dann selber noch notieren.
gruss munuel


----------



## gravitex (6. September 2006)

Genau das wollte ich vermeiden...


----------



## Thomas Darimont (6. September 2006)

Hallo!

Das kann man wunderbar per AOP über einen (tracing) Aspect machen. Ich mach dazu heute Abend mal ein kleines Beispiel.

Gruß Tom


----------



## Thomas Darimont (6. September 2006)

Hallo!

hier mal ein Beispiel wie man mit AspectJ per Load Time Weaving eine Anwendung Tracen kann:

Unser TracingAspect:

```
/**
 * 
 */
package de.tutorials.aop;

import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * @author Tom
 * 
 */
@Aspect
public class TracingAspect {

	static Set<MethodCall> methodCalls = new TreeSet<MethodCall>();

	static {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				for (MethodCall methodCall : methodCalls) {
					System.out.println(methodCall);
				}
			}
		});
	}

	@Pointcut("call(* de.tutorials..*(..)) && !within(de.tutorials.aop..*)")
	public void anyMethodCall() {
	}

	@Around("anyMethodCall()")
	public Object traceMethodCall(ProceedingJoinPoint proceedingJoinPoint) {

		String currentThreadName = Thread.currentThread().getName();
		String calledMethodSignature = proceedingJoinPoint.getSignature()
				.toLongString();
		String arguments = Arrays.toString(proceedingJoinPoint.getArgs());
		String resultAsString = null;

		long timeStamp = System.nanoTime();

		Object result = null;

		MethodCall methodCall = new MethodCall(currentThreadName,
				calledMethodSignature, arguments, timeStamp);

		methodCalls.add(methodCall);

		try {
			result = proceedingJoinPoint.proceed();
			resultAsString = String.valueOf(result);
		} catch (Throwable e) {
			e.printStackTrace();
			result = null;
			resultAsString = "Invocation of " + calledMethodSignature
					+ " produced Exception: " + e;
		}

		methodCall.setResult(resultAsString);

		return result;
	}
}
```

Unsere MethodCall Abstraktion:

```
/**
 * 
 */
package de.tutorials.aop;

import java.text.MessageFormat;

class MethodCall implements Comparable<MethodCall>{
	
	long timeStamp;
	
	String currentThreadName;

	String calledMethodSignature;

	String arguments;

	String result;

	static final MessageFormat MESSAGE_FROMAT = new MessageFormat(
			"[{0}] called Method {1} with arguments:({2}) and got result:({3})");

	public MethodCall(String currentThreadName,
			String calledMethodSignature, String arguments,  long timeStamp) {
		super();
		this.currentThreadName = currentThreadName;
		this.calledMethodSignature = calledMethodSignature;
		this.arguments = arguments;
		this.timeStamp = timeStamp;
	}

	/**
	 * @return the arguments
	 */
	public String getArguments() {
		return arguments;
	}

	/**
	 * @param arguments
	 *            the arguments to set
	 */
	public void setArguments(String arguments) {
		this.arguments = arguments;
	}

	/**
	 * @return the calledMethodSignature
	 */
	public String getCalledMethodSignature() {
		return calledMethodSignature;
	}

	/**
	 * @param calledMethodSignature
	 *            the calledMethodSignature to set
	 */
	public void setCalledMethodSignature(String calledMethodSignature) {
		this.calledMethodSignature = calledMethodSignature;
	}

	/**
	 * @return the currentThreadName
	 */
	public String getCurrentThreadName() {
		return currentThreadName;
	}

	/**
	 * @param currentThreadName
	 *            the currentThreadName to set
	 */
	public void setCurrentThreadName(String currentThreadName) {
		this.currentThreadName = currentThreadName;
	}

	/**
	 * @return the result
	 */
	public String getResult() {
		return result;
	}

	/**
	 * @param result
	 *            the result to set
	 */
	public void setResult(String result) {
		this.result = result;
	}

	public String toString() {
		return MESSAGE_FROMAT.format(new Object[] { this.currentThreadName,
				this.calledMethodSignature, this.arguments, this.result });
	}

	public int compareTo(MethodCall otherMethodCall) {
		return (int)Math.signum( this.timeStamp - otherMethodCall.timeStamp);
	}
}
```

Das passende aop.xml:

```
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
    <aspects>
        <aspect name="de.tutorials.aop.TracingAspect" />
    </aspects>
    
    <weaver options="-XlazyTjp">
        <include within="de.tutorials..*"/>
    </weaver>
</aspectj>
```

Unsere MiniAnwendung die wir Tracen wollen:

```
/**
 * 
 */
package de.tutorials;

/**
 * @author Tom
 * 
 */
public class TracingExample {
    public static void main(String[] args) {
        String a = "W";

        System.out.println(operation1(a));

    }

    private static Object operation1(String a) {
        String b = "X";
        return operation2(a, b);
    }

    private static Object operation2(String a, String b) {
        String c = "Y";
        return operation3(a, b, c);
    }

    private static Object operation3(String a, String b, String c) {

        return a + b + c + "Z";
    }
}
```

Ausgabe ohne Tracing:

```
E:\eclipse\3.2\eclipse\workspace\de.tutorials.training>java -cp bin de.tutorials.TracingExample
WXYZ
```

Ausgabe mit Tracing:

```
E:\eclipse\3.2\eclipse\workspace\de.tutorials.training>java -Daj.weaving.verbose=true  -javaagent:c:/aspectjweaver.jar  -cp c:/aspectjrt.jar;c:/de.tutorials.aop.tracing.jar;bin de.tutorials.TracingExample
info AspectJ Weaver Version 1.5.1a built on Monday Apr 10, 2006 at 10:52:04 GMT
info register classloader sun.misc.Launcher$AppClassLoader@10469011
info using file:/C:/de.tutorials.aop.tracing.jar!/META-INF/aop.xml
info register aspect de.tutorials.aop.TracingAspect
info weaving 'de/tutorials/TracingExample'
info generating class 'de.tutorials.TracingExample$AjcClosure1'
info generating class 'de.tutorials.TracingExample$AjcClosure3'
info generating class 'de.tutorials.TracingExample$AjcClosure5'
info weaving 'de/tutorials/aop/TracingAspect'
info processing reweavable type de.tutorials.aop.TracingAspect: de\tutorials\aop\TracingAspect.java
info successfully verified type de.tutorials.aop.TracingAspect exists.  Originates from de\tutorials\aop\TracingAspect.java
info weaving 'de/tutorials/aop/TracingAspect$1'
info weaving 'de/tutorials/aop/MethodCall'
WXYZ
[main] called Method private static java.lang.Object de.tutorials.TracingExample.operation1(java.lang.String) with arguments:([W]) and got result:(WXYZ)
[main] called Method private static java.lang.Object de.tutorials.TracingExample.operation2(java.lang.String, java.lang.String) with arguments:([W, X]) and got result:(WXYZ)
[main] called Method private static java.lang.Object de.tutorials.TracingExample.operation3(java.lang.String, java.lang.String, java.lang.String) with arguments:([W, X, Y]) and got result:(WXYZ)
```

Die Ausagbe ohne das verbose-Flag schaut so aus:

```
E:\eclipse\3.2\eclipse\workspace\de.tutorials.training>java -javaagent:c:/aspectjweaver.jar  -cp c:/aspectjrt.jar;c:/de.tutorials.aop.tracing.jar;bin de.tutorials.TracingExample
WXYZ
[main] called Method private static java.lang.Object de.tutorials.TracingExample.operation1(java.lang.String) with arguments:([W]) and got result:(WXYZ)
[main] called Method private static java.lang.Object de.tutorials.TracingExample.operation2(java.lang.String, java.lang.String) with arguments:([W, X]) and got result:(WXYZ)
[main] called Method private static java.lang.Object de.tutorials.TracingExample.operation3(java.lang.String, java.lang.String, java.lang.String) with arguments:([W, X, Y]) and got result:(WXYZ)
```

Die AspectJ Bibliotheken findet man dann bei der AspectJ Distribution oder im lib Verzeichnis des Springframeworks.

Das Ausgeben/Aufsammeln von TraceStatements wird insbesondere in Multithreaded Umgebungen recht mühsam. Hier könnte man beispielsweise das Tracing in eine Textdatei vornehmen die man mit TimeStamps versieht und dann in einem späteren Schritt die darin mitgeschriebenen Statements anhand der Threadkennung und Timestamp- angaben wieder in die richtige Reihenfolge bringen.

Gruß Tom


----------



## gravitex (7. September 2006)

Uiiiiii.....
das sieht ja aus wie das was ich brauche !!
danke schonmal.
ich werde es mal ausprobieren.
danke,
stefan


----------



## gravitex (7. September 2006)

Hallo.
So richtig komem ich nicht klar...
also ich hab folgendes getan :
Ich habe mir ein AJDT-Plugin für Eclipse geladen und installiert, 
auch, kann auch jetzt sagen : Runs As...--> AspectJ/Java Application
Desweiteren habe ich das von Dir mitgelieferte ZIP-File in ein Java-Eclipse-Projekt eingebunden. Darin sind ja die Dateien MethodCall.class, TracingAspect.class sowie die XML-Datei.

Sieht dann aus wie angefügt (Project.jpg):

Ich verwende folgenden Aufruf (in der LaunchConfiguration unter "Arguments") :

-Daj.weaving.verbose=true  -javaagent:c:/aspectjweaver.jar  -cp c:/aspectjrt.jar;de.tutorials.aop.tracing.jar;bin de.tutorials.TracingExample

Habe auch die Dateien aspectjweaver.jar und aspectjrt.jar brav auf C: abgelegt.

de.tutorials.aop.tracing.jar hab ich ja eingebunden
und das Package wo die TracingExample-Datei drin ist hat ja auch den richtigen Namen.

Nun sage ich "Run", aber er kommt nur die Ausgabe "WXYZ" (wie ohen Tracing).

Was mach ich denn noch falsch ?

Danke,
Stefan


----------



## Thomas Darimont (7. September 2006)

Hallo!


```
-Daj.weaving.verbose=true  -javaagent:c:/aspectjweaver.jar
```
Hast du das auch bei VM Arguments angegeben?

Gruß Tom


----------



## gravitex (7. September 2006)

Also meine LaunchConfig sieht nun aus wie angefügt, allerdings kommt dann
beim Starten eine (ebenfalls angefügte Fehlermeldung) mit der Begründung :


```
Unrecognized option: -javaagent:c:/aspectjweaver.jar
```

Wenn ich 


```
-javaagent:c:/aspectjweaver.jar
```

weglasse, dann kommt wieder die Ausgabe

WXYZ.

Stefan


----------



## Thomas Darimont (7. September 2006)

Hallo!

verwendest du eine Java 5 Sun JVM?

Gruß Tom


----------



## gravitex (7. September 2006)

Also, ich habe den JDK 1.4.2_04 eingebunden.
Ich hab mal gegoogelt und rausgeunden, das man
das bei Eclipse (was ich benutze), einstellen kann,
welche VM benutzt wird. Aber wo ich das sehen kann, weiß ich jetzt nicht so genau.

Gruß,
Stefan


----------



## Thomas Darimont (7. September 2006)

Hallo!

AFAIK gibt es die javaagent JVM Option bei Sun erst ab den 5er JVMs. (es gibt auch JVMs wie die JRockit von BEA die das auch schon unter java 1.4 können...)
Einstellen kannst du die verwendete JVM beispielsweise in den Project Properties
unter -> Java Build Path -> Libraries -> JRE System Library ... -> Edit
Unter Run kannst du für die entsprechende LaunchConfiguration auch über das Tab JRE die verwendete JVM angeben.

Zusätzlich kannst du über Window -> Preferences -> Java -> Installed JREs neue JVMs hinzufügen und die default JVM setzen.

Gruß Tom


----------

