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.nio.charset.Charset;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.logging.log4j.core.LogEvent;
25 import org.apache.logging.log4j.core.config.Configuration;
26 import org.apache.logging.log4j.core.config.DefaultConfiguration;
27 import org.apache.logging.log4j.core.config.plugins.Plugin;
28 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
29 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
30 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
31 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
32 import org.apache.logging.log4j.core.config.plugins.PluginElement;
33 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
34 import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
35 import org.apache.logging.log4j.core.pattern.PatternFormatter;
36 import org.apache.logging.log4j.core.pattern.PatternParser;
37 import org.apache.logging.log4j.core.pattern.RegexReplacement;
38 import org.apache.logging.log4j.core.util.Charsets;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 @Plugin(name = "PatternLayout", category = "Core", elementType = "layout", printObject = true)
54 public final class PatternLayout extends AbstractStringLayout {
55
56
57
58
59
60 public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
61
62
63
64
65
66 public static final String TTCC_CONVERSION_PATTERN =
67 "%r [%t] %p %c %x - %m%n";
68
69
70
71
72
73 public static final String SIMPLE_CONVERSION_PATTERN =
74 "%d [%t] %p %c - %m%n";
75
76
77 public static final String KEY = "Converter";
78
79
80
81
82 private final List<PatternFormatter> formatters;
83
84
85
86
87 private final String conversionPattern;
88
89
90
91
92
93 private final Configuration config;
94
95 private final RegexReplacement replace;
96
97 private final boolean alwaysWriteExceptions;
98
99 private final boolean noConsoleNoAnsi;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 private PatternLayout(final Configuration config, final RegexReplacement replace, final String pattern,
115 final Charset charset, final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi,
116 final String header, final String footer) {
117 super(charset, toBytes(header, charset), toBytes(footer, charset));
118 this.replace = replace;
119 this.conversionPattern = pattern;
120 this.config = config;
121 this.alwaysWriteExceptions = alwaysWriteExceptions;
122 this.noConsoleNoAnsi = noConsoleNoAnsi;
123 final PatternParser parser = createPatternParser(config);
124 this.formatters = parser.parse(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, this.alwaysWriteExceptions, this.noConsoleNoAnsi);
125 }
126
127 private static byte[] toBytes(String str, Charset charset) {
128 if (str != null) {
129 return str.getBytes(charset != null ? charset : Charset.defaultCharset());
130 }
131 return null;
132 }
133
134 private byte[] strSubstitutorReplace(final byte... b) {
135 if (b != null && config != null) {
136 final Charset cs = getCharset();
137 return config.getStrSubstitutor().replace(new String(b, cs)).getBytes(cs);
138 }
139 return b;
140 }
141
142 @Override
143 public byte[] getHeader() {
144 return strSubstitutorReplace(super.getHeader());
145 }
146
147 @Override
148 public byte[] getFooter() {
149 return strSubstitutorReplace(super.getFooter());
150 }
151
152
153
154
155
156
157 public String getConversionPattern() {
158 return conversionPattern;
159 }
160
161
162
163
164
165
166
167
168 @Override
169 public Map<String, String> getContentFormat()
170 {
171 final Map<String, String> result = new HashMap<String, String>();
172 result.put("structured", "false");
173 result.put("formatType", "conversion");
174 result.put("format", conversionPattern);
175 return result;
176 }
177
178
179
180
181
182
183
184
185 @Override
186 public String toSerializable(final LogEvent event) {
187 final StringBuilder buf = new StringBuilder();
188 for (final PatternFormatter formatter : formatters) {
189 formatter.format(event, buf);
190 }
191 String str = buf.toString();
192 if (replace != null) {
193 str = replace.format(str);
194 }
195 return str;
196 }
197
198
199
200
201
202
203 public static PatternParser createPatternParser(final Configuration config) {
204 if (config == null) {
205 return new PatternParser(config, KEY, LogEventPatternConverter.class);
206 }
207 PatternParser parser = config.getComponent(KEY);
208 if (parser == null) {
209 parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
210 config.addComponent(KEY, parser);
211 parser = (PatternParser) config.getComponent(KEY);
212 }
213 return parser;
214 }
215
216 @Override
217 public String toString() {
218 return conversionPattern;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 @PluginFactory
243 public static PatternLayout createLayout(
244 @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern,
245 @PluginConfiguration final Configuration config,
246 @PluginElement("Replace") final RegexReplacement replace,
247 @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset,
248 @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions,
249 @PluginAttribute(value = "noConsoleNoAnsi", defaultBoolean = false) final boolean noConsoleNoAnsi,
250 @PluginAttribute("header") final String header,
251 @PluginAttribute("footer") final String footer) {
252 return newBuilder()
253 .withPattern(pattern)
254 .withConfiguration(config)
255 .withRegexReplacement(replace)
256 .withCharset(charset)
257 .withAlwaysWriteExceptions(alwaysWriteExceptions)
258 .withNoConsoleNoAnsi(noConsoleNoAnsi)
259 .withHeader(header)
260 .withFooter(footer)
261 .build();
262 }
263
264
265
266
267
268
269
270
271 public static PatternLayout createDefaultLayout() {
272 return newBuilder().build();
273 }
274
275
276
277
278
279 @PluginBuilderFactory
280 public static Builder newBuilder() {
281 return new Builder();
282 }
283
284
285
286
287 public static class Builder implements org.apache.logging.log4j.core.util.Builder<PatternLayout> {
288
289
290
291
292 @PluginBuilderAttribute
293 private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
294
295 @PluginConfiguration
296 private Configuration configuration = null;
297
298 @PluginElement("Replace")
299 private RegexReplacement regexReplacement = null;
300
301 @PluginBuilderAttribute
302 private Charset charset = Charsets.UTF_8;
303
304 @PluginBuilderAttribute
305 private boolean alwaysWriteExceptions = true;
306
307 @PluginBuilderAttribute
308 private boolean noConsoleNoAnsi = false;
309
310 @PluginBuilderAttribute
311 private String header = null;
312
313 @PluginBuilderAttribute
314 private String footer = null;
315
316 private Builder() {
317 }
318
319
320
321 public Builder withPattern(final String pattern) {
322 this.pattern = pattern;
323 return this;
324 }
325
326
327 public Builder withConfiguration(final Configuration configuration) {
328 this.configuration = configuration;
329 return this;
330 }
331
332 public Builder withRegexReplacement(final RegexReplacement regexReplacement) {
333 this.regexReplacement = regexReplacement;
334 return this;
335 }
336
337 public Builder withCharset(final Charset charset) {
338 this.charset = charset;
339 return this;
340 }
341
342 public Builder withAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
343 this.alwaysWriteExceptions = alwaysWriteExceptions;
344 return this;
345 }
346
347 public Builder withNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
348 this.noConsoleNoAnsi = noConsoleNoAnsi;
349 return this;
350 }
351
352 public Builder withHeader(final String header) {
353 this.header = header;
354 return this;
355 }
356
357 public Builder withFooter(final String footer) {
358 this.footer = footer;
359 return this;
360 }
361
362 @Override
363 public PatternLayout build() {
364
365 if (configuration == null) {
366 configuration = new DefaultConfiguration();
367 }
368 return new PatternLayout(configuration, regexReplacement, pattern, charset, alwaysWriteExceptions,
369 noConsoleNoAnsi, header, footer);
370 }
371 }
372 }