001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.activemq.util; 018 019 import java.util.HashMap; 020 import java.util.Map.Entry; 021 022 import org.slf4j.Logger; 023 import org.slf4j.LoggerFactory; 024 025 /** 026 * Debugging tool to track entry points through code, useful to see runtime call paths 027 * To use, add to a method as follows:<code> 028 * public void someMethod() { 029 * ThreadTracker.track("someMethod"); 030 * ... 031 * }</code> 032 * and at some stage call <code>result</code> to get a LOG 033 * output of the callers with an associated call count 034 * 035 */ 036 public class ThreadTracker { 037 038 static final Logger LOG = LoggerFactory.getLogger(ThreadTracker.class); 039 static HashMap<String, Tracker> trackers = new HashMap<String, Tracker>(); 040 041 /** 042 * track the stack trace of callers 043 * @param name the method being tracked 044 */ 045 public static void track(final String name) { 046 Tracker t; 047 final String key = name.intern(); 048 synchronized(trackers) { 049 t = trackers.get(key); 050 if (t == null) { 051 t = new Tracker(); 052 trackers.put(key, t); 053 } 054 } 055 t.track(); 056 } 057 058 /** 059 * output the result of stack trace capture to the log 060 */ 061 public static void result() { 062 synchronized(trackers) { 063 for (Entry<String, Tracker> t: trackers.entrySet()) { 064 LOG.info("Tracker: " + t.getKey() + ", " + t.getValue().size() + " entry points..."); 065 for (Trace trace : t.getValue().values()) { 066 LOG.info("count: " + trace.count, trace); 067 } 068 LOG.info("Tracker: " + t.getKey() + ", done."); 069 } 070 } 071 } 072 073 } 074 075 @SuppressWarnings("serial") 076 class Trace extends Throwable { 077 public int count = 1; 078 public final long id; 079 Trace() { 080 super(); 081 id = calculateIdentifier(); 082 } 083 private long calculateIdentifier() { 084 int len = 0; 085 for (int i=0; i<this.getStackTrace().length; i++) { 086 len += this.getStackTrace()[i].toString().intern().hashCode(); 087 } 088 return len; 089 } 090 } 091 092 @SuppressWarnings("serial") 093 class Tracker extends HashMap<Long, Trace> { 094 public void track() { 095 Trace current = new Trace(); 096 synchronized(this) { 097 Trace exist = get(current.id); 098 if (exist != null) { 099 exist.count++; 100 } else { 101 put(current.id, current); 102 } 103 } 104 } 105 }