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 }