001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.monitoring;
020
021import java.lang.management.ManagementFactory;
022import java.lang.management.ThreadInfo;
023import java.lang.management.ThreadMXBean;
024
025import org.apache.yetus.audience.InterfaceAudience;
026
027@InterfaceAudience.Private
028public abstract class ThreadMonitoring {
029
030  private static final ThreadMXBean threadBean = 
031    ManagementFactory.getThreadMXBean();
032  private static final int STACK_DEPTH = 20;
033
034  public static ThreadInfo getThreadInfo(Thread t) {
035    long tid = t.getId();
036    return threadBean.getThreadInfo(tid, STACK_DEPTH);
037  }
038    
039
040  /**
041   * Format the given ThreadInfo object as a String.
042   * @param indent a prefix for each line, used for nested indentation
043   */
044  public static String formatThreadInfo(ThreadInfo threadInfo, String indent) {
045    StringBuilder sb = new StringBuilder();
046    appendThreadInfo(sb, threadInfo, indent);
047    return sb.toString();
048  }
049
050  /**
051   * Print all of the thread's information and stack traces.
052   * 
053   * @param sb
054   * @param info
055   * @param indent
056   */
057  public static void appendThreadInfo(StringBuilder sb,
058                                      ThreadInfo info,
059                                      String indent) {
060    boolean contention = threadBean.isThreadContentionMonitoringEnabled();
061
062    if (info == null) {
063      sb.append(indent).append("Inactive (perhaps exited while monitoring was done)\n");
064      return;
065    }
066    String taskName = getTaskName(info.getThreadId(), info.getThreadName());
067    sb.append(indent).append("Thread ").append(taskName).append(":\n");
068    
069    Thread.State state = info.getThreadState();
070    sb.append(indent).append("  State: ").append(state).append("\n");
071    sb.append(indent).append("  Blocked count: ").append(info.getBlockedCount()).append("\n");
072    sb.append(indent).append("  Waited count: ").append(info.getWaitedCount()).append("\n");
073    if (contention) {
074      sb.append(indent).append("  Blocked time: " + info.getBlockedTime()).append("\n");
075      sb.append(indent).append("  Waited time: " + info.getWaitedTime()).append("\n");
076    }
077    if (state == Thread.State.WAITING) {
078      sb.append(indent).append("  Waiting on ").append(info.getLockName()).append("\n");
079    } else  if (state == Thread.State.BLOCKED) {
080      sb.append(indent).append("  Blocked on ").append(info.getLockName()).append("\n");
081      sb.append(indent).append("  Blocked by ").append(
082        getTaskName(info.getLockOwnerId(), info.getLockOwnerName())).append("\n");
083    }
084    sb.append(indent).append("  Stack:").append("\n");
085    for (StackTraceElement frame: info.getStackTrace()) {
086      sb.append(indent).append("    ").append(frame.toString()).append("\n");
087    }
088  }
089  
090  private static String getTaskName(long id, String name) {
091    if (name == null) {
092      return Long.toString(id);
093    }
094    return id + " (" + name + ")";
095  }
096
097
098}