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 public String getFormattedMessage() {
85 if (formattedMessage != null) {
86 return formattedMessage;
87 }
88 final StringBuilder sb = new StringBuilder(title);
89 if (title.length() > 0) {
90 sb.append("\n");
91 }
92 for (final Map.Entry<ThreadInformation, StackTraceElement[]> entry : threads.entrySet()) {
93 final ThreadInformation info = entry.getKey();
94 info.printThreadInfo(sb);
95 info.printStack(sb, entry.getValue());
96 sb.append("\n");
97 }
98 return sb.toString();
99 }
100
101
102
103
104
105 public String getFormat() {
106 return title == null ? "" : title;
107 }
108
109
110
111
112
113
114 public Object[] getParameters() {
115 return null;
116 }
117
118
119
120
121
122 protected Object writeReplace() {
123 return new ThreadDumpMessageProxy(this);
124 }
125
126 private void readObject(final ObjectInputStream stream)
127 throws InvalidObjectException {
128 throw new InvalidObjectException("Proxy required");
129 }
130
131
132
133
134 private static class ThreadDumpMessageProxy implements Serializable {
135
136 private static final long serialVersionUID = -3476620450287648269L;
137 private final String formattedMsg;
138 private final String title;
139
140 public ThreadDumpMessageProxy(final ThreadDumpMessage msg) {
141 this.formattedMsg = msg.getFormattedMessage();
142 this.title = msg.title;
143 }
144
145
146
147
148
149 protected Object readResolve() {
150 return new ThreadDumpMessage(formattedMsg, title);
151 }
152 }
153
154
155
156
157 private interface ThreadInfoFactory {
158 Map<ThreadInformation, StackTraceElement[]> createThreadInfo();
159 }
160
161
162
163
164 private static class BasicThreadInfoFactory implements ThreadInfoFactory {
165 public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
166 final Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
167 final Map<ThreadInformation, StackTraceElement[]> threads =
168 new HashMap<ThreadInformation, StackTraceElement[]>(map.size());
169 for (final Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) {
170 threads.put(new BasicThreadInformation(entry.getKey()), entry.getValue());
171 }
172 return threads;
173 }
174 }
175
176
177
178
179 private static class ExtendedThreadInfoFactory implements ThreadInfoFactory {
180 public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
181 final ThreadMXBean bean = ManagementFactory.getThreadMXBean();
182 final ThreadInfo[] array = bean.dumpAllThreads(true, true);
183
184 final Map<ThreadInformation, StackTraceElement[]> threads =
185 new HashMap<ThreadInformation, StackTraceElement[]>(array.length);
186 for (final ThreadInfo info : array) {
187 threads.put(new ExtendedThreadInformation(info), info.getStackTrace());
188 }
189 return threads;
190 }
191 }
192
193
194
195
196
197
198 public Throwable getThrowable() {
199 return null;
200 }
201 }