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