1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.layout;
18
19 import java.io.IOException;
20 import java.io.InterruptedIOException;
21 import java.io.LineNumberReader;
22 import java.io.PrintWriter;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.nio.charset.Charset;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.logging.log4j.core.config.plugins.Plugin;
31 import org.apache.logging.log4j.core.config.plugins.PluginAttr;
32 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
33 import org.apache.logging.log4j.core.helpers.Transform;
34 import org.apache.logging.log4j.core.LogEvent;
35 import org.apache.logging.log4j.message.Message;
36 import org.apache.logging.log4j.message.MultiformatMessage;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 @Plugin(name = "XMLLayout", type = "Core", elementType = "layout", printObject = true)
74 public class XMLLayout extends AbstractStringLayout {
75
76 private static final int DEFAULT_SIZE = 256;
77
78 private static final String[] FORMATS = new String[] {"xml"};
79
80 private final boolean locationInfo;
81 private final boolean properties;
82 private final boolean complete;
83
84 protected XMLLayout(boolean locationInfo, boolean properties, boolean complete, Charset charset) {
85 super(charset);
86 this.locationInfo = locationInfo;
87 this.properties = properties;
88 this.complete = complete;
89 }
90
91
92
93
94
95
96
97 public String toSerializable(final LogEvent event) {
98 StringBuilder buf = new StringBuilder(DEFAULT_SIZE);
99
100
101
102 buf.append("<log4j:event logger=\"");
103 String name = event.getLoggerName();
104 if (name.length() == 0) {
105 name = "root";
106 }
107 buf.append(Transform.escapeTags(name));
108 buf.append("\" timestamp=\"");
109 buf.append(event.getMillis());
110 buf.append("\" level=\"");
111 buf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
112 buf.append("\" thread=\"");
113 buf.append(Transform.escapeTags(event.getThreadName()));
114 buf.append("\">\r\n");
115
116 Message msg = event.getMessage();
117 if (msg != null) {
118 boolean xmlSupported = false;
119 if (msg instanceof MultiformatMessage) {
120 String[] formats = ((MultiformatMessage) msg).getFormats();
121 for (String format : formats) {
122 if (format.equalsIgnoreCase("XML")) {
123 xmlSupported = true;
124 }
125 }
126 }
127 if (xmlSupported) {
128 buf.append("<log4j:message>");
129 buf.append(((MultiformatMessage) msg).getFormattedMessage(FORMATS));
130 buf.append("</log4j:message>");
131 } else {
132 buf.append("<log4j:message><![CDATA[");
133
134
135 Transform.appendEscapingCDATA(buf, event.getMessage().getFormattedMessage());
136 buf.append("]]></log4j:message>\r\n");
137 }
138 }
139
140 if (event.getContextStack().getDepth() > 0) {
141 buf.append("<log4j:NDC><![CDATA[");
142 Transform.appendEscapingCDATA(buf, event.getContextStack().toString());
143 buf.append("]]></log4j:NDC>\r\n");
144 }
145
146 Throwable throwable = event.getThrown();
147 if (throwable != null) {
148 List<String> s = getThrowableString(throwable);
149 buf.append("<log4j:throwable><![CDATA[");
150 for (String str : s) {
151 Transform.appendEscapingCDATA(buf, str);
152 buf.append("\r\n");
153 }
154 buf.append("]]></log4j:throwable>\r\n");
155 }
156
157 if (locationInfo) {
158 StackTraceElement element = event.getSource();
159 buf.append("<log4j:locationInfo class=\"");
160 buf.append(Transform.escapeTags(element.getClassName()));
161 buf.append("\" method=\"");
162 buf.append(Transform.escapeTags(element.getMethodName()));
163 buf.append("\" file=\"");
164 buf.append(Transform.escapeTags(element.getFileName()));
165 buf.append("\" line=\"");
166 buf.append(element.getLineNumber());
167 buf.append("\"/>\r\n");
168 }
169
170 if (properties && event.getContextMap().size() > 0) {
171 buf.append("<log4j:properties>\r\n");
172 for (Map.Entry<String, String> entry : event.getContextMap().entrySet()) {
173 buf.append("<log4j:data name=\"");
174 buf.append(Transform.escapeTags(entry.getKey()));
175 buf.append("\" value=\"");
176 buf.append(Transform.escapeTags(String.valueOf(entry.getValue())));
177 buf.append("\"/>\r\n");
178 }
179 buf.append("</log4j:properties>\r\n");
180 }
181
182 buf.append("</log4j:event>\r\n\r\n");
183
184 return buf.toString();
185 }
186
187
188
189
190
191 @Override
192 public byte[] getHeader() {
193 if (!complete) {
194 return null;
195 }
196 StringBuilder sbuf = new StringBuilder();
197 sbuf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
198 sbuf.append("<log4j:eventSet xmlns:log4j=\"http://logging.apache.org/log4j/\">\r\n");
199 return sbuf.toString().getBytes(getCharset());
200 }
201
202
203
204
205
206
207 @Override
208 public byte[] getFooter() {
209 if (!complete) {
210 return null;
211 }
212 StringBuilder sbuf = new StringBuilder();
213 sbuf.append("</log4j:eventSet>\r\n");
214 return sbuf.toString().getBytes(getCharset());
215 }
216
217 List<String> getThrowableString(Throwable throwable) {
218 StringWriter sw = new StringWriter();
219 PrintWriter pw = new PrintWriter(sw);
220 try {
221 throwable.printStackTrace(pw);
222 } catch (RuntimeException ex) {
223
224 }
225 pw.flush();
226 LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
227 ArrayList<String> lines = new ArrayList<String>();
228 try {
229 String line = reader.readLine();
230 while (line != null) {
231 lines.add(line);
232 line = reader.readLine();
233 }
234 } catch (IOException ex) {
235 if (ex instanceof InterruptedIOException) {
236 Thread.currentThread().interrupt();
237 }
238 lines.add(ex.toString());
239 }
240 return lines;
241 }
242
243
244
245
246
247
248
249
250
251 @PluginFactory
252 public static XMLLayout createLayout(@PluginAttr("locationInfo") String locationInfo,
253 @PluginAttr("properties") String properties,
254 @PluginAttr("complete") String complete,
255 @PluginAttr("charset") String charset) {
256 Charset c = Charset.isSupported("UTF-8") ? Charset.forName("UTF-8") : Charset.defaultCharset();
257 if (charset != null) {
258 if (Charset.isSupported(charset)) {
259 c = Charset.forName(charset);
260 } else {
261 LOGGER.error("Charset " + charset + " is not supported for layout, using " + c.displayName());
262 }
263 }
264 boolean info = locationInfo == null ? false : Boolean.valueOf(locationInfo);
265 boolean props = properties == null ? false : Boolean.valueOf(properties);
266 boolean comp = complete == null ? false : Boolean.valueOf(complete);
267 return new XMLLayout(info, props, comp, c);
268 }
269 }