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.io.InvalidObjectException;
20 import java.io.ObjectInputStream;
21 import java.io.Serializable;
22 import java.lang.management.ManagementFactory;
23 import java.lang.management.ThreadInfo;
24 import java.lang.management.ThreadMXBean;
25 import java.lang.reflect.Method;
26 import java.util.HashMap;
27 import java.util.Map;
28
29
30
31
32 public class ThreadDumpMessage implements Message {
33
34 private static final long serialVersionUID = -1103400781608841088L;
35
36 private static final ThreadInfoFactory FACTORY;
37
38 private volatile Map<ThreadInformation, StackTraceElement[]> threads;
39
40 private final String title;
41
42 private String formattedMessage;
43
44 static {
45 final Method[] methods = ThreadInfo.class.getMethods();
46 boolean basic = true;
47 for (final Method method : methods) {
48 if (method.getName().equals("getLockInfo")) {
49 basic = false;
50 break;
51 }
52 }
53 FACTORY = basic ? new BasicThreadInfoFactory() : new ExtendedThreadInfoFactory();
54 }
55
56
57
58
59
60 public ThreadDumpMessage(final String title) {
61 this.title = title == null ? "" : title;
62 threads = FACTORY.createThreadInfo();
63 }
64
65 private ThreadDumpMessage(final String formattedMsg, final String title) {
66 this.formattedMessage = formattedMsg;
67 this.title = title == null ? "" : title;
68 }
69
70 @Override
71 public String toString() {
72 final StringBuilder sb = new StringBuilder("ThreadDumpMessage[");
73 if (this.title.length() > 0) {
74 sb.append("Title=\"").append(this.title).append("\"");
75 }
76 sb.append("]");
77 return sb.toString();
78 }
79
80
81
82
83
84 @Override
85 public String getFormattedMessage() {
86 if (formattedMessage != null) {
87 return formattedMessage;
88 }
89 final StringBuilder sb = new StringBuilder(title);
90 if (title.length() > 0) {
91 sb.append("\n");
92 }
93 for (final Map.Entry<ThreadInformation, StackTraceElement[]> entry : threads.entrySet()) {
94 final ThreadInformation info = entry.getKey();
95 info.printThreadInfo(sb);
96 info.printStack(sb, entry.getValue());
97 sb.append("\n");
98 }
99 return sb.toString();
100 }
101
102
103
104
105
106 @Override
107 public String getFormat() {
108 return title == null ? "" : title;
109 }
110
111
112
113
114
115
116 @Override
117 public Object[] getParameters() {
118 return null;
119 }
120
121
122
123
124
125 protected Object writeReplace() {
126 return new ThreadDumpMessageProxy(this);
127 }
128
129 private void readObject(final ObjectInputStream stream)
130 throws InvalidObjectException {
131 throw new InvalidObjectException("Proxy required");
132 }
133
134
135
136
137 private static class ThreadDumpMessageProxy implements Serializable {
138
139 private static final long serialVersionUID = -3476620450287648269L;
140 private final String formattedMsg;
141 private final String title;
142
143 public ThreadDumpMessageProxy(final ThreadDumpMessage msg) {
144 this.formattedMsg = msg.getFormattedMessage();
145 this.title = msg.title;
146 }
147
148
149
150
151
152 protected Object readResolve() {
153 return new ThreadDumpMessage(formattedMsg, title);
154 }
155 }
156
157
158
159
160 private interface ThreadInfoFactory {
161 Map<ThreadInformation, StackTraceElement[]> createThreadInfo();
162 }
163
164
165
166
167 private static class BasicThreadInfoFactory implements ThreadInfoFactory {
168 @Override
169 public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
170 final Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
171 final Map<ThreadInformation, StackTraceElement[]> threads =
172 new HashMap<ThreadInformation, StackTraceElement[]>(map.size());
173 for (final Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) {
174 threads.put(new BasicThreadInformation(entry.getKey()), entry.getValue());
175 }
176 return threads;
177 }
178 }
179
180
181
182
183 private static class ExtendedThreadInfoFactory implements ThreadInfoFactory {
184 @Override
185 public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
186 final ThreadMXBean bean = ManagementFactory.getThreadMXBean();
187 final ThreadInfo[] array = bean.dumpAllThreads(true, true);
188
189 final Map<ThreadInformation, StackTraceElement[]> threads =
190 new HashMap<ThreadInformation, StackTraceElement[]>(array.length);
191 for (final ThreadInfo info : array) {
192 threads.put(new ExtendedThreadInformation(info), info.getStackTrace());
193 }
194 return threads;
195 }
196 }
197
198
199
200
201
202
203 @Override
204 public Throwable getThrowable() {
205 return null;
206 }
207 }