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 }