001 package org.apache.activemq.util; 002 003 import java.util.HashMap; 004 import java.util.Map.Entry; 005 006 import org.apache.commons.logging.Log; 007 import org.apache.commons.logging.LogFactory; 008 009 /** 010 * Debugging tool to track entry points through code, useful to see runtime call paths 011 * To use, add to a method as follows:<code> 012 * public void someMethod() { 013 * ThreadTracker.track("someMethod"); 014 * ... 015 * }</code> 016 * and at some stage call <code>result</code> to get a LOG 017 * output of the callers with an associated call count 018 * 019 */ 020 public class ThreadTracker { 021 022 static final Log LOG = LogFactory.getLog(ThreadTracker.class); 023 static HashMap<String, Tracker> trackers = new HashMap<String, Tracker>(); 024 025 /** 026 * track the stack trace of callers 027 * @param name the method being tracked 028 */ 029 public static void track(final String name) { 030 Tracker t; 031 final String key = name.intern(); 032 synchronized(trackers) { 033 t = trackers.get(key); 034 if (t == null) { 035 t = new Tracker(); 036 trackers.put(key, t); 037 } 038 } 039 t.track(); 040 } 041 042 /** 043 * output the result of stack trace capture to the log 044 */ 045 public static void result() { 046 synchronized(trackers) { 047 for (Entry<String, Tracker> t: trackers.entrySet()) { 048 LOG.info("Tracker: " + t.getKey() + ", " + t.getValue().size() + " entry points..."); 049 for (Trace trace : t.getValue().values()) { 050 LOG.info("count: " + trace.count, trace); 051 } 052 LOG.info("Tracker: " + t.getKey() + ", done."); 053 } 054 } 055 } 056 057 } 058 059 @SuppressWarnings("serial") 060 class Trace extends Throwable { 061 public int count = 1; 062 public final long id; 063 Trace() { 064 super(); 065 id = calculateIdentifier(); 066 } 067 private long calculateIdentifier() { 068 int len = 0; 069 for (int i=0; i<this.getStackTrace().length; i++) { 070 len += this.getStackTrace()[i].toString().intern().hashCode(); 071 } 072 return len; 073 } 074 } 075 076 @SuppressWarnings("serial") 077 class Tracker extends HashMap<Long, Trace> { 078 public void track() { 079 Trace current = new Trace(); 080 synchronized(this) { 081 Trace exist = get(current.id); 082 if (exist != null) { 083 exist.count++; 084 } else { 085 put(current.id, current); 086 } 087 } 088 } 089 }