This project has retired. For details please refer to its Attic page.
Source code
001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.util;
020
021import java.lang.management.LockInfo;
022import java.lang.management.MonitorInfo;
023import java.lang.management.ThreadInfo;
024import java.util.Map;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028/**
029 * Methods to log the currently active set of threads with their stack traces. This is useful to log abnormal
030 * process exit situations, for instance the Driver timeout in the tests.
031 */
032public final class ThreadLogger {
033
034  /**
035   * This is a utility class that shall not be instantiated.
036   */
037  private ThreadLogger() {
038  }
039
040  /**
041   * Same as <code>logThreads(logger, level, prefix, "\n\t", "\n\t\t")</code>.
042   */
043  public static void logThreads(final Logger logger, final Level level, final String prefix) {
044    logThreads(logger, level, prefix, "\n\t", "\n\t\t");
045  }
046
047  /**
048   * Logs the currently active threads and their stack trace to the given Logger and Level.
049   *
050   * @param logger             the Logger instance to log to.
051   * @param level              the Level to log into.
052   * @param prefix             a prefix of the log message.
053   * @param threadPrefix       logged before each thread, e.g. "\n\t" to create an indented list.
054   * @param stackElementPrefix logged before each stack trace element, e.g. "\n\t\t" to create an indented list.
055   */
056  public static void logThreads(
057      final Logger logger, final Level level, final String prefix,
058      final String threadPrefix, final String stackElementPrefix) {
059    logger.log(level, getFormattedThreadList(prefix, threadPrefix, stackElementPrefix));
060  }
061
062  /**
063   * Produces a String representation of the currently running threads.
064   *
065   * @param prefix             The prefix of the string returned.
066   * @param threadPrefix       Printed before each thread, e.g. "\n\t" to create an indented list.
067   * @param stackElementPrefix Printed before each stack trace element, e.g. "\n\t\t" to create an indented list.
068   * @return a String representation of the currently running threads.
069   */
070  public static String getFormattedThreadList(
071      final String prefix, final String threadPrefix, final String stackElementPrefix) {
072    final StringBuilder message = new StringBuilder(prefix);
073    for (final Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) {
074      message.append(threadPrefix).append("Thread '").append(entry.getKey().getName()).append("':");
075      for (final StackTraceElement element : entry.getValue()) {
076        message.append(stackElementPrefix).append(element.toString());
077      }
078    }
079    return message.toString();
080  }
081
082  /**
083   * Same as <code>getFormattedThreadList(prefix, "\n\t", "\n\t\t")</code>.
084   */
085  public static String getFormattedThreadList(final String prefix) {
086    return getFormattedThreadList(prefix, "\n\t", "\n\t\t");
087  }
088
089  /**
090   * Produces a String representation of threads that are deadlocked, including lock information.
091   * @param prefix             The prefix of the string returned.
092   * @param threadPrefix       Printed before each thread, e.g. "\n\t" to create an indented list.
093   * @param stackElementPrefix Printed before each stack trace element, e.g. "\n\t\t" to create an indented list.
094   * @return a String representation of threads that are deadlocked, including lock information
095   */
096  public static String getFormattedDeadlockInfo(
097      final String prefix, final String threadPrefix, final String stackElementPrefix) {
098    final StringBuilder message = new StringBuilder(prefix);
099
100    final DeadlockInfo deadlockInfo = new DeadlockInfo();
101
102    final ThreadInfo[] deadlockedThreads = deadlockInfo.getDeadlockedThreads();
103
104    if (0 == deadlockedThreads.length) {
105      message.append(" none ");
106      return message.toString();
107    }
108
109    for (final ThreadInfo threadInfo : deadlockedThreads) {
110      message.append(threadPrefix).append("Thread '").append(threadInfo.getThreadName())
111          .append("' with state ").append(threadInfo.getThreadState());
112
113      boolean firstElement = true;
114      for (final StackTraceElement stackTraceElement : threadInfo.getStackTrace()) {
115        message.append(stackElementPrefix).append("at ").append(stackTraceElement);
116        if (firstElement) {
117          final String waitingLockString = deadlockInfo.getWaitingLockString(threadInfo);
118          if (waitingLockString != null) {
119            message.append(stackElementPrefix).append("- waiting to lock: ").append(waitingLockString);
120          }
121          firstElement = false;
122        }
123        for (final MonitorInfo info : deadlockInfo.getMonitorLockedElements(threadInfo, stackTraceElement)) {
124          message.append(stackElementPrefix).append("- locked: ").append(info);
125        }
126      }
127      for (final LockInfo lockInfo : threadInfo.getLockedSynchronizers()) {
128        message.append(stackElementPrefix).append("* holds locked synchronizer: ").append(lockInfo);
129      }
130    }
131
132    return message.toString();
133  }
134
135  /**
136   * Same as <code>getFormattedDeadlockInfo(prefix, "\n\t", "\n\t\t")</code>.
137   */
138  public static String getFormattedDeadlockInfo(final String prefix) {
139    return getFormattedDeadlockInfo(prefix, "\n\t", "\n\t\t");
140  }
141
142  /**
143   * An example how to use the above methods.
144   *
145   * @param args ignored.
146   */
147  public static void main(final String[] args) {
148    logThreads(Logger.getAnonymousLogger(), Level.INFO, "Threads active:");
149  }
150}