View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.message;
    18
    19  import java.lang.management.LockInfo;
    20  import java.lang.management.MonitorInfo;
    21  import java.lang.management.ThreadInfo;
    22
    23  import org.apache.logging.log4j.util.StringBuilders;
    24
    25  /**
    26   * Provides information on locks and monitors in the thread dump. This class requires Java 1.6 to compile and
    27   * run.
    28   */
    29  class ExtendedThreadInformation implements ThreadInformation {
    30
    31      private final ThreadInfo threadInfo;
    32
    33
    34      public ExtendedThreadInformation(final ThreadInfo thread) {
    35          this.threadInfo = thread;
    36      }
    37
    38      @Override
    39      public void printThreadInfo(final StringBuilder sb) {
    40          StringBuilders.appendDqValue(sb, threadInfo.getThreadName());
    41          sb.append(" Id=").append(threadInfo.getThreadId()).append(' ');
    42          formatState(sb, threadInfo);
    43          if (threadInfo.isSuspended()) {
    44              sb.append(" (suspended)");
    45          }
    46          if (threadInfo.isInNative()) {
    47              sb.append(" (in native)");
    48          }
    49          sb.append('\n');
    50      }
    51
    52      @Override
    53      public void printStack(final StringBuilder sb, final StackTraceElement[] stack) {
    54          int i = 0;
    55          for (final StackTraceElement element : stack) {
    56              sb.append("\tat ").append(element.toString());
    57              sb.append('\n');
    58              if (i == 0 && threadInfo.getLockInfo() != null) {
    59                  final Thread.State ts = threadInfo.getThreadState();
    60                  switch (ts) {
    61                      case BLOCKED:
    62                          sb.append("\t-  blocked on ");
    63                          formatLock(sb, threadInfo.getLockInfo());
    64                          sb.append('\n');
    65                          break;
    66                      case WAITING:
    67                          sb.append("\t-  waiting on ");
    68                          formatLock(sb, threadInfo.getLockInfo());
    69                          sb.append('\n');
    70                          break;
    71                      case TIMED_WAITING:
    72                          sb.append("\t-  waiting on ");
    73                          formatLock(sb, threadInfo.getLockInfo());
    74                          sb.append('\n');
    75                          break;
    76                      default:
    77                  }
    78              }
    79
    80              for (final MonitorInfo mi : threadInfo.getLockedMonitors()) {
    81                  if (mi.getLockedStackDepth() == i) {
    82                      sb.append("\t-  locked ");
    83                      formatLock(sb, mi);
    84                      sb.append('\n');
    85                  }
    86              }
    87              ++i;
    88          }
    89
    90          final LockInfo[] locks = threadInfo.getLockedSynchronizers();
    91          if (locks.length > 0) {
    92              sb.append("\n\tNumber of locked synchronizers = ").append(locks.length).append('\n');
    93              for (final LockInfo li : locks) {
    94                  sb.append("\t- ");
    95                  formatLock(sb, li);
    96                  sb.append('\n');
    97              }
    98          }
    99      }
    100
    101     private void formatLock(final StringBuilder sb, final LockInfo lock) {
    102         sb.append('<').append(lock.getIdentityHashCode()).append("> (a ");
    103         sb.append(lock.getClassName()).append(')');
    104     }
    105
    106     private void formatState(final StringBuilder sb, final ThreadInfo info) {
    107         final Thread.State state = info.getThreadState();
    108         sb.append(state);
    109         switch (state) {
    110             case BLOCKED: {
    111                 sb.append(" (on object monitor owned by \"");
    112                 sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId()).append(')');
    113                 break;
    114             }
    115             case WAITING: {
    116                 final StackTraceElement element = info.getStackTrace()[0];
    117                 final String className = element.getClassName();
    118                 final String method = element.getMethodName();
    119                 if (className.equals("java.lang.Object") && method.equals("wait")) {
    120                     sb.append(" (on object monitor");
    121                     if (info.getLockOwnerName() != null) {
    122                         sb.append(" owned by \"");
    123                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
    124                     }
    125                     sb.append(')');
    126                 } else if (className.equals("java.lang.Thread") && method.equals("join")) {
    127                     sb.append(" (on completion of thread ").append(info.getLockOwnerId()).append(')');
    128                 } else {
    129                     sb.append(" (parking for lock");
    130                     if (info.getLockOwnerName() != null) {
    131                         sb.append(" owned by \"");
    132                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
    133                     }
    134                     sb.append(')');
    135                 }
    136                 break;
    137             }
    138             case TIMED_WAITING: {
    139                 final StackTraceElement element = info.getStackTrace()[0];
    140                 final String className = element.getClassName();
    141                 final String method = element.getMethodName();
    142                 if (className.equals("java.lang.Object") && method.equals("wait")) {
    143                     sb.append(" (on object monitor");
    144                     if (info.getLockOwnerName() != null) {
    145                         sb.append(" owned by \"");
    146                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
    147                     }
    148                     sb.append(')');
    149                 } else if (className.equals("java.lang.Thread") && method.equals("sleep")) {
    150                     sb.append(" (sleeping)");
    151                 } else if (className.equals("java.lang.Thread") && method.equals("join")) {
    152                     sb.append(" (on completion of thread ").append(info.getLockOwnerId()).append(')');
    153                 } else {
    154                     sb.append(" (parking for lock");
    155                     if (info.getLockOwnerName() != null) {
    156                         sb.append(" owned by \"");
    157                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
    158                     }
    159                     sb.append(')');
    160                 }
    161                 break;
    162             }
    163             default:
    164                 break;
    165         }
    166     }
    167 }