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