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