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, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.monitoring;
019
020import java.lang.management.ManagementFactory;
021import java.lang.management.ThreadInfo;
022import java.lang.management.ThreadMXBean;
023import org.apache.yetus.audience.InterfaceAudience;
024
025@InterfaceAudience.Private
026public abstract class ThreadMonitoring {
027
028  private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
029  private static final int STACK_DEPTH = 20;
030
031  public static ThreadInfo getThreadInfo(Thread t) {
032    long tid = t.getId();
033    return threadBean.getThreadInfo(tid, STACK_DEPTH);
034  }
035
036  /**
037   * Format the given ThreadInfo object as a String.
038   * @param indent a prefix for each line, used for nested indentation
039   */
040  public static String formatThreadInfo(ThreadInfo threadInfo, String indent) {
041    StringBuilder sb = new StringBuilder();
042    appendThreadInfo(sb, threadInfo, indent);
043    return sb.toString();
044  }
045
046  /**
047   * Print all of the thread's information and stack traces.
048   */
049  public static void appendThreadInfo(StringBuilder sb, ThreadInfo info, String indent) {
050    boolean contention = threadBean.isThreadContentionMonitoringEnabled();
051
052    if (info == null) {
053      sb.append(indent).append("Inactive (perhaps exited while monitoring was done)\n");
054      return;
055    }
056    String taskName = getTaskName(info.getThreadId(), info.getThreadName());
057    sb.append(indent).append("Thread ").append(taskName).append(":\n");
058
059    Thread.State state = info.getThreadState();
060    sb.append(indent).append("  State: ").append(state).append("\n");
061    sb.append(indent).append("  Blocked count: ").append(info.getBlockedCount()).append("\n");
062    sb.append(indent).append("  Waited count: ").append(info.getWaitedCount()).append("\n");
063    if (contention) {
064      sb.append(indent).append("  Blocked time: " + info.getBlockedTime()).append("\n");
065      sb.append(indent).append("  Waited time: " + info.getWaitedTime()).append("\n");
066    }
067    if (state == Thread.State.WAITING) {
068      sb.append(indent).append("  Waiting on ").append(info.getLockName()).append("\n");
069    } else if (state == Thread.State.BLOCKED) {
070      sb.append(indent).append("  Blocked on ").append(info.getLockName()).append("\n");
071      sb.append(indent).append("  Blocked by ")
072        .append(getTaskName(info.getLockOwnerId(), info.getLockOwnerName())).append("\n");
073    }
074    sb.append(indent).append("  Stack:").append("\n");
075    for (StackTraceElement frame : info.getStackTrace()) {
076      sb.append(indent).append("    ").append(frame.toString()).append("\n");
077    }
078  }
079
080  private static String getTaskName(long id, String name) {
081    if (name == null) {
082      return Long.toString(id);
083    }
084    return id + " (" + name + ")";
085  }
086
087}