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      ExtendedThreadInformation(final ThreadInfo thread) {
34          this.threadInfo = thread;
35      }
36  
37      @Override
38      public void printThreadInfo(final StringBuilder sb) {
39          StringBuilders.appendDqValue(sb, threadInfo.getThreadName());
40          sb.append(" Id=").append(threadInfo.getThreadId()).append(' ');
41          formatState(sb, threadInfo);
42          if (threadInfo.isSuspended()) {
43              sb.append(" (suspended)");
44          }
45          if (threadInfo.isInNative()) {
46              sb.append(" (in native)");
47          }
48          sb.append('\n');
49      }
50  
51      @Override
52      public void printStack(final StringBuilder sb, final StackTraceElement[] stack) {
53          int i = 0;
54          for (final StackTraceElement element : stack) {
55              sb.append("\tat ").append(element.toString());
56              sb.append('\n');
57              if (i == 0 && threadInfo.getLockInfo() != null) {
58                  final Thread.State ts = threadInfo.getThreadState();
59                  switch (ts) {
60                      case BLOCKED:
61                          sb.append("\t-  blocked on ");
62                          formatLock(sb, threadInfo.getLockInfo());
63                          sb.append('\n');
64                          break;
65                      case WAITING:
66                          sb.append("\t-  waiting on ");
67                          formatLock(sb, threadInfo.getLockInfo());
68                          sb.append('\n');
69                          break;
70                      case TIMED_WAITING:
71                          sb.append("\t-  waiting on ");
72                          formatLock(sb, threadInfo.getLockInfo());
73                          sb.append('\n');
74                          break;
75                      default:
76                  }
77              }
78  
79              for (final MonitorInfo mi : threadInfo.getLockedMonitors()) {
80                  if (mi.getLockedStackDepth() == i) {
81                      sb.append("\t-  locked ");
82                      formatLock(sb, mi);
83                      sb.append('\n');
84                  }
85              }
86              ++i;
87          }
88  
89          final LockInfo[] locks = threadInfo.getLockedSynchronizers();
90          if (locks.length > 0) {
91              sb.append("\n\tNumber of locked synchronizers = ").append(locks.length).append('\n');
92              for (final LockInfo li : locks) {
93                  sb.append("\t- ");
94                  formatLock(sb, li);
95                  sb.append('\n');
96              }
97          }
98      }
99  
100     private void formatLock(final StringBuilder sb, final LockInfo lock) {
101         sb.append('<').append(lock.getIdentityHashCode()).append("> (a ");
102         sb.append(lock.getClassName()).append(')');
103     }
104 
105     private void formatState(final StringBuilder sb, final ThreadInfo info) {
106         final Thread.State state = info.getThreadState();
107         sb.append(state);
108         switch (state) {
109             case BLOCKED: {
110                 sb.append(" (on object monitor owned by \"");
111                 sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId()).append(')');
112                 break;
113             }
114             case WAITING: {
115                 final StackTraceElement element = info.getStackTrace()[0];
116                 final String className = element.getClassName();
117                 final String method = element.getMethodName();
118                 if (className.equals("java.lang.Object") && method.equals("wait")) {
119                     sb.append(" (on object monitor");
120                     if (info.getLockOwnerName() != null) {
121                         sb.append(" owned by \"");
122                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
123                     }
124                     sb.append(')');
125                 } else if (className.equals("java.lang.Thread") && method.equals("join")) {
126                     sb.append(" (on completion of thread ").append(info.getLockOwnerId()).append(')');
127                 } else {
128                     sb.append(" (parking for lock");
129                     if (info.getLockOwnerName() != null) {
130                         sb.append(" owned by \"");
131                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
132                     }
133                     sb.append(')');
134                 }
135                 break;
136             }
137             case TIMED_WAITING: {
138                 final StackTraceElement element = info.getStackTrace()[0];
139                 final String className = element.getClassName();
140                 final String method = element.getMethodName();
141                 if (className.equals("java.lang.Object") && method.equals("wait")) {
142                     sb.append(" (on object monitor");
143                     if (info.getLockOwnerName() != null) {
144                         sb.append(" owned by \"");
145                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
146                     }
147                     sb.append(')');
148                 } else if (className.equals("java.lang.Thread") && method.equals("sleep")) {
149                     sb.append(" (sleeping)");
150                 } else if (className.equals("java.lang.Thread") && method.equals("join")) {
151                     sb.append(" (on completion of thread ").append(info.getLockOwnerId()).append(')');
152                 } else {
153                     sb.append(" (parking for lock");
154                     if (info.getLockOwnerName() != null) {
155                         sb.append(" owned by \"");
156                         sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
157                     }
158                     sb.append(')');
159                 }
160                 break;
161             }
162             default:
163                 break;
164         }
165     }
166 }