1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
27
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 }