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 org.apache.logging.log4j.core.LogEvent;
20 import org.apache.logging.log4j.core.StringLayout;
21 import org.apache.logging.log4j.core.config.Configuration;
22 import org.apache.logging.log4j.core.config.LoggerConfig;
23 import org.apache.logging.log4j.core.util.Constants;
24 import org.apache.logging.log4j.core.util.StringEncoder;
25 import org.apache.logging.log4j.util.Strings;
26
27 import java.io.UnsupportedEncodingException;
28 import java.nio.charset.Charset;
29 import java.nio.charset.StandardCharsets;
30
31
32
33
34
35
36
37
38
39
40
41 public abstract class AbstractStringLayout extends AbstractLayout<String> implements StringLayout {
42
43 public interface Serializer {
44 String toSerializable(final LogEvent event);
45 }
46
47
48
49
50
51 public interface Serializer2 {
52 StringBuilder toSerializable(final LogEvent event, final StringBuilder builder);
53 }
54
55
56
57
58 protected static final int DEFAULT_STRING_BUILDER_SIZE = 1024;
59
60 private static final ThreadLocal<StringBuilder> threadLocal = new ThreadLocal<>();
61
62 private Encoder<StringBuilder> textEncoder;
63
64
65
66
67
68
69 protected static StringBuilder getStringBuilder() {
70 StringBuilder result = threadLocal.get();
71 if (result == null) {
72 result = new StringBuilder(DEFAULT_STRING_BUILDER_SIZE);
73 threadLocal.set(result);
74 }
75 result.setLength(0);
76 return result;
77 }
78
79
80 private static boolean isPreJava8() {
81 final String version = System.getProperty("java.version");
82 final String[] parts = version.split("\\.");
83 try {
84 final int major = Integer.parseInt(parts[1]);
85 return major < 8;
86 } catch (final Exception ex) {
87 return true;
88 }
89 }
90
91
92
93
94 private transient Charset charset;
95
96 private final String charsetName;
97
98 private final Serializer footerSerializer;
99
100 private final Serializer headerSerializer;
101
102 private final boolean useCustomEncoding;
103
104 protected AbstractStringLayout(final Charset charset) {
105 this(charset, (byte[]) null, (byte[]) null);
106 }
107
108
109
110
111
112
113
114
115 protected AbstractStringLayout(final Charset aCharset, final byte[] header, final byte[] footer) {
116 super(null, header, footer);
117 this.headerSerializer = null;
118 this.footerSerializer = null;
119 this.charset = aCharset == null ? StandardCharsets.UTF_8 : aCharset;
120 this.charsetName = this.charset.name();
121 useCustomEncoding = isPreJava8()
122 && (StandardCharsets.ISO_8859_1.equals(aCharset) || StandardCharsets.US_ASCII.equals(aCharset));
123 textEncoder = Constants.ENABLE_DIRECT_ENCODERS ? new StringBuilderEncoder(charset) : null;
124 }
125
126
127
128
129
130
131
132
133
134 protected AbstractStringLayout(final Configuration config, final Charset aCharset,
135 final Serializer headerSerializer, final Serializer footerSerializer) {
136 super(config, null, null);
137 this.headerSerializer = headerSerializer;
138 this.footerSerializer = footerSerializer;
139 this.charset = aCharset == null ? StandardCharsets.UTF_8 : aCharset;
140 this.charsetName = this.charset.name();
141 useCustomEncoding = isPreJava8()
142 && (StandardCharsets.ISO_8859_1.equals(aCharset) || StandardCharsets.US_ASCII.equals(aCharset));
143 textEncoder = Constants.ENABLE_DIRECT_ENCODERS ? new StringBuilderEncoder(charset) : null;
144 }
145
146
147
148
149
150
151 protected Encoder<StringBuilder> getStringBuilderEncoder() {
152 if (textEncoder == null) {
153 textEncoder = new StringBuilderEncoder(getCharset());
154 }
155 return textEncoder;
156 }
157
158 protected byte[] getBytes(final String s) {
159 if (useCustomEncoding) {
160 return StringEncoder.encodeSingleByteChars(s);
161 }
162 try {
163 return s.getBytes(charsetName);
164 } catch (final UnsupportedEncodingException e) {
165 return s.getBytes(charset);
166 }
167 }
168
169 @Override
170 public Charset getCharset() {
171 return charset;
172 }
173
174
175
176
177 @Override
178 public String getContentType() {
179 return "text/plain";
180 }
181
182
183
184
185
186
187 @Override
188 public byte[] getFooter() {
189 return serializeToBytes(footerSerializer, super.getFooter());
190 }
191
192 public Serializer getFooterSerializer() {
193 return footerSerializer;
194 }
195
196
197
198
199
200
201 @Override
202 public byte[] getHeader() {
203 return serializeToBytes(headerSerializer, super.getHeader());
204 }
205
206 public Serializer getHeaderSerializer() {
207 return headerSerializer;
208 }
209
210 protected byte[] serializeToBytes(final Serializer serializer, final byte[] defaultValue) {
211 final String serializable = serializeToString(serializer);
212 if (serializer == null) {
213 return defaultValue;
214 }
215 return StringEncoder.toBytes(serializable, getCharset());
216 }
217
218 protected String serializeToString(final Serializer serializer) {
219 if (serializer == null) {
220 return null;
221 }
222 final LoggerConfig rootLogger = getConfiguration().getRootLogger();
223
224 final LogEvent logEvent = rootLogger.getLogEventFactory().createEvent(rootLogger.getName(), null, Strings.EMPTY,
225 rootLogger.getLevel(), null, null, null);
226 return serializer.toSerializable(logEvent);
227 }
228
229
230
231
232
233
234
235 @Override
236 public byte[] toByteArray(final LogEvent event) {
237 return getBytes(toSerializable(event));
238 }
239
240 }