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
36
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 @Plugin(name = "XMLLayout", type = "Core", elementType = "layout", printObject = true)
72 public class XMLLayout extends AbstractStringLayout {
73
74 private static final int DEFAULT_SIZE = 256;
75
76 private final boolean locationInfo;
77 private final boolean properties;
78 private final boolean complete;
79
80 protected XMLLayout(boolean locationInfo, boolean properties, boolean complete, Charset charset) {
81 super(charset);
82 this.locationInfo = locationInfo;
83 this.properties = properties;
84 this.complete = complete;
85 }
86
87
88
89
90
91
92 public String formatAs(final LogEvent event) {
93 StringBuilder buf = new StringBuilder(DEFAULT_SIZE);
94
95
96
97 buf.append("<log4j:event logger=\"");
98 String name = event.getLoggerName();
99 if (name.length() == 0) {
100 name = "root";
101 }
102 buf.append(Transform.escapeTags(name));
103 buf.append("\" timestamp=\"");
104 buf.append(event.getMillis());
105 buf.append("\" level=\"");
106 buf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
107 buf.append("\" thread=\"");
108 buf.append(Transform.escapeTags(event.getThreadName()));
109 buf.append("\">\r\n");
110
111 buf.append("<log4j:message><![CDATA[");
112
113
114 Transform.appendEscapingCDATA(buf, event.getMessage().getFormattedMessage());
115 buf.append("]]></log4j:message>\r\n");
116
117 if (event.getContextStack().size() > 0) {
118 buf.append("<log4j:NDC><![CDATA[");
119 Transform.appendEscapingCDATA(buf, event.getContextStack().toString());
120 buf.append("]]></log4j:NDC>\r\n");
121 }
122
123 Throwable throwable = event.getThrown();
124 if (throwable != null) {
125 List<String> s = getThrowableString(throwable);
126 buf.append("<log4j:throwable><![CDATA[");
127 for (String str : s) {
128 Transform.appendEscapingCDATA(buf, str);
129 buf.append("\r\n");
130 }
131 buf.append("]]></log4j:throwable>\r\n");
132 }
133
134 if (locationInfo) {
135 StackTraceElement element = event.getSource();
136 buf.append("<log4j:locationInfo class=\"");
137 buf.append(Transform.escapeTags(element.getClassName()));
138 buf.append("\" method=\"");
139 buf.append(Transform.escapeTags(element.getMethodName()));
140 buf.append("\" file=\"");
141 buf.append(Transform.escapeTags(element.getFileName()));
142 buf.append("\" line=\"");
143 buf.append(element.getLineNumber());
144 buf.append("\"/>\r\n");
145 }
146
147 if (properties && event.getContextMap().size() > 0) {
148 buf.append("<log4j:properties>\r\n");
149 for (Map.Entry<String, String> entry : event.getContextMap().entrySet()) {
150 buf.append("<log4j:data name=\"");
151 buf.append(Transform.escapeTags(entry.getKey()));
152 buf.append("\" value=\"");
153 buf.append(Transform.escapeTags(String.valueOf(entry.getValue())));
154 buf.append("\"/>\r\n");
155 }
156 buf.append("</log4j:properties>\r\n");
157 }
158
159 buf.append("</log4j:event>\r\n\r\n");
160
161 return buf.toString();
162 }
163
164
165
166
167
168 @Override
169 public byte[] getHeader() {
170 if (!complete) {
171 return null;
172 }
173 StringBuilder sbuf = new StringBuilder();
174 sbuf.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
175 sbuf.append("<log4j:eventSet xmlns:log4j=\"http://logging.apache.org/log4j/\">\r\n");
176 return sbuf.toString().getBytes(getCharset());
177 }
178
179
180
181
182
183
184 @Override
185 public byte[] getFooter() {
186 if (!complete) {
187 return null;
188 }
189 StringBuilder sbuf = new StringBuilder();
190 sbuf.append("</log4j:eventSet>\r\n");
191 return sbuf.toString().getBytes(getCharset());
192 }
193
194 List<String> getThrowableString(Throwable throwable) {
195 StringWriter sw = new StringWriter();
196 PrintWriter pw = new PrintWriter(sw);
197 try {
198 throwable.printStackTrace(pw);
199 } catch (RuntimeException ex) {
200
201 }
202 pw.flush();
203 LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
204 ArrayList<String> lines = new ArrayList<String>();
205 try {
206 String line = reader.readLine();
207 while (line != null) {
208 lines.add(line);
209 line = reader.readLine();
210 }
211 } catch (IOException ex) {
212 if (ex instanceof InterruptedIOException) {
213 Thread.currentThread().interrupt();
214 }
215 lines.add(ex.toString());
216 }
217 return lines;
218 }
219
220
221
222
223
224
225
226
227
228 @PluginFactory
229 public static XMLLayout createLayout(@PluginAttr("locationInfo") String locationInfo,
230 @PluginAttr("properties") String properties,
231 @PluginAttr("complete") String complete,
232 @PluginAttr("charset") String charset) {
233 Charset c = Charset.isSupported("UTF-8") ? Charset.forName("UTF-8") : Charset.defaultCharset();
234 if (charset != null) {
235 if (Charset.isSupported(charset)) {
236 c = Charset.forName(charset);
237 } else {
238 LOGGER.error("Charset " + charset + " is not supported for layout, using " + c.displayName());
239 }
240 }
241 boolean info = locationInfo == null ? false : Boolean.valueOf(locationInfo);
242 boolean props = properties == null ? false : Boolean.valueOf(properties);
243 boolean comp = complete == null ? false : Boolean.valueOf(complete);
244 return new XMLLayout(info, props, comp, c);
245 }
246 }