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