1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.layout;
18
19 import java.io.PrintWriter;
20 import java.io.StringWriter;
21 import java.nio.charset.StandardCharsets;
22 import java.util.List;
23 import java.util.Objects;
24
25 import org.apache.logging.log4j.core.Layout;
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.config.Node;
28 import org.apache.logging.log4j.core.config.plugins.Plugin;
29 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
30 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
31 import org.apache.logging.log4j.core.layout.AbstractStringLayout;
32 import org.apache.logging.log4j.core.layout.ByteBufferDestination;
33 import org.apache.logging.log4j.core.util.Transform;
34 import org.apache.logging.log4j.util.ReadOnlyStringMap;
35 import org.apache.logging.log4j.util.Strings;
36
37
38
39
40
41
42 @Plugin(name = "Log4j1XmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
43 public final class Log4j1XmlLayout extends AbstractStringLayout {
44
45 private final boolean locationInfo;
46 private final boolean properties;
47
48 @PluginFactory
49 public static Log4j1XmlLayout createLayout(
50
51 @PluginAttribute(value = "locationInfo") final boolean locationInfo,
52 @PluginAttribute(value = "properties") final boolean properties
53
54 ) {
55 return new Log4j1XmlLayout(locationInfo, properties);
56 }
57
58 private Log4j1XmlLayout(final boolean locationInfo, final boolean properties) {
59 super(StandardCharsets.UTF_8);
60 this.locationInfo = locationInfo;
61 this.properties = properties;
62 }
63
64 public boolean isLocationInfo() {
65 return locationInfo;
66 }
67
68 public boolean isProperties() {
69 return properties;
70 }
71
72 @Override
73 public void encode(final LogEvent event, final ByteBufferDestination destination) {
74 final StringBuilder text = getStringBuilder();
75 formatTo(event, text);
76 getStringBuilderEncoder().encode(text, destination);
77 }
78
79 @Override
80 public String toSerializable(final LogEvent event) {
81 final StringBuilder text = getStringBuilder();
82 formatTo(event, text);
83 return text.toString();
84 }
85
86 private void formatTo(final LogEvent event, final StringBuilder buf) {
87
88
89 buf.append("<log4j:event logger=\"");
90 buf.append(Transform.escapeHtmlTags(event.getLoggerName()));
91 buf.append("\" timestamp=\"");
92 buf.append(event.getTimeMillis());
93 buf.append("\" level=\"");
94 buf.append(Transform.escapeHtmlTags(String.valueOf(event.getLevel())));
95 buf.append("\" thread=\"");
96 buf.append(Transform.escapeHtmlTags(event.getThreadName()));
97 buf.append("\">\r\n");
98
99 buf.append("<log4j:message><![CDATA[");
100
101 Transform.appendEscapingCData(buf, event.getMessage().getFormattedMessage());
102 buf.append("]]></log4j:message>\r\n");
103
104 final List<String> ndc = event.getContextStack().asList();
105 if (!ndc.isEmpty()) {
106 buf.append("<log4j:NDC><![CDATA[");
107 Transform.appendEscapingCData(buf, Strings.join(ndc, ' '));
108 buf.append("]]></log4j:NDC>\r\n");
109 }
110
111 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
112 final Throwable thrown = event.getThrown();
113 if (thrown != null) {
114 buf.append("<log4j:throwable><![CDATA[");
115 final StringWriter w = new StringWriter();
116 thrown.printStackTrace(new PrintWriter(w));
117 Transform.appendEscapingCData(buf, w.toString());
118 buf.append("]]></log4j:throwable>\r\n");
119 }
120
121 if (locationInfo) {
122 final StackTraceElement source = event.getSource();
123 if (source != null) {
124 buf.append("<log4j:locationInfo class=\"");
125 buf.append(Transform.escapeHtmlTags(source.getClassName()));
126 buf.append("\" method=\"");
127 buf.append(Transform.escapeHtmlTags(source.getMethodName()));
128 buf.append("\" file=\"");
129 buf.append(Transform.escapeHtmlTags(source.getFileName()));
130 buf.append("\" line=\"");
131 buf.append(source.getLineNumber());
132 buf.append("\"/>\r\n");
133 }
134 }
135
136 if (properties) {
137 final ReadOnlyStringMap contextMap = event.getContextData();
138 if (!contextMap.isEmpty()) {
139 buf.append("<log4j:properties>\r\n");
140 contextMap.forEach((key, val) -> {
141 if (val != null) {
142 buf.append("<log4j:data name=\"");
143 buf.append(Transform.escapeHtmlTags(key));
144 buf.append("\" value=\"");
145 buf.append(Transform.escapeHtmlTags(Objects.toString(val, null)));
146 buf.append("\"/>\r\n");
147 }
148 });
149 buf.append("</log4j:properties>\r\n");
150 }
151 }
152
153 buf.append("</log4j:event>\r\n\r\n");
154 }
155
156 }