1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
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.Map;
22
23 import org.apache.logging.log4j.core.Layout;
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.util.Constants;
29
30 /**
31 * Appends a series of JSON events as strings serialized as bytes.
32 *
33 * <h3>Complete well-formed JSON vs. fragment JSON</h3>
34 * <p>
35 * If you configure {@code complete="true"}, the appender outputs a well-formed JSON document. By default, with {@code complete="false"},
36 * you should include the output as an <em>external file</em> in a separate file to form a well-formed JSON document.
37 * </p>
38 * <p>
39 * A well-formed JSON event follows this pattern:
40 * </p>
41 *
42 * <pre>
43 * {
44 "timeMillis": 1,
45 "thread": "MyThreadName",
46 "level": "DEBUG",
47 "loggerName": "a.B",
48 "marker": {
49 "name": "Marker1",
50 "parents": [{
51 "name": "ParentMarker1",
52 "parents": [{
53 "name": "GrandMotherMarker"
54 }, {
55 "name": "GrandFatherMarker"
56 }]
57 }, {
58 "name": "GrandFatherMarker"
59 }]
60 },
61 "message": "Msg",
62 "thrown": {
63 "cause": {
64 "commonElementCount": 27,
65 "extendedStackTrace": [{
66 "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
67 "method": "createLogEvent",
68 "file": "LogEventFixtures.java",
69 "line": 53,
70 "exact": false,
71 "location": "test-classes/",
72 "version": "?"
73 }],
74 "localizedMessage": "testNPEx",
75 "message": "testNPEx",
76 "name": "java.lang.NullPointerException"
77 },
78 "commonElementCount": 0,
79 "extendedStackTrace": [{
80 "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
81 "method": "createLogEvent",
82 "file": "LogEventFixtures.java",
83 "line": 56,
84 "exact": true,
85 "location": "test-classes/",
86 "version": "?"
87 }, {
88 "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
89 "method": "testAllFeatures",
90 "file": "JsonLayoutTest.java",
91 "line": 105,
92 "exact": true,
93 "location": "test-classes/",
94 "version": "?"
95 }, {
96 "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
97 "method": "testLocationOnCompactOnMdcOn",
98 "file": "JsonLayoutTest.java",
99 "line": 268,
100 "exact": true,
101 "location": "test-classes/",
102 "version": "?"
103 }, {
104 "class": "sun.reflect.NativeMethodAccessorImpl",
105 "method": "invoke",
106 "line": -1,
107 "exact": false,
108 "location": "?",
109 "version": "1.7.0_55"
110 }, {
111 "class": "sun.reflect.NativeMethodAccessorImpl",
112 "method": "invoke",
113 "line": -1,
114 "exact": false,
115 "location": "?",
116 "version": "1.7.0_55"
117 }, {
118 "class": "sun.reflect.DelegatingMethodAccessorImpl",
119 "method": "invoke",
120 "line": -1,
121 "exact": false,
122 "location": "?",
123 "version": "1.7.0_55"
124 }, {
125 "class": "java.lang.reflect.Method",
126 "method": "invoke",
127 "line": -1,
128 "exact": false,
129 "location": "?",
130 "version": "1.7.0_55"
131 }, {
132 "class": "org.junit.runners.model.FrameworkMethod$1",
133 "method": "runReflectiveCall",
134 "file": "FrameworkMethod.java",
135 "line": 47,
136 "exact": true,
137 "location": "junit-4.11.jar",
138 "version": "?"
139 }, {
140 "class": "org.junit.internal.runners.model.ReflectiveCallable",
141 "method": "run",
142 "file": "ReflectiveCallable.java",
143 "line": 12,
144 "exact": true,
145 "location": "junit-4.11.jar",
146 "version": "?"
147 }, {
148 "class": "org.junit.runners.model.FrameworkMethod",
149 "method": "invokeExplosively",
150 "file": "FrameworkMethod.java",
151 "line": 44,
152 "exact": true,
153 "location": "junit-4.11.jar",
154 "version": "?"
155 }, {
156 "class": "org.junit.internal.runners.statements.InvokeMethod",
157 "method": "evaluate",
158 "file": "InvokeMethod.java",
159 "line": 17,
160 "exact": true,
161 "location": "junit-4.11.jar",
162 "version": "?"
163 }, {
164 "class": "org.junit.runners.ParentRunner",
165 "method": "runLeaf",
166 "file": "ParentRunner.java",
167 "line": 271,
168 "exact": true,
169 "location": "junit-4.11.jar",
170 "version": "?"
171 }, {
172 "class": "org.junit.runners.BlockJUnit4ClassRunner",
173 "method": "runChild",
174 "file": "BlockJUnit4ClassRunner.java",
175 "line": 70,
176 "exact": true,
177 "location": "junit-4.11.jar",
178 "version": "?"
179 }, {
180 "class": "org.junit.runners.BlockJUnit4ClassRunner",
181 "method": "runChild",
182 "file": "BlockJUnit4ClassRunner.java",
183 "line": 50,
184 "exact": true,
185 "location": "junit-4.11.jar",
186 "version": "?"
187 }, {
188 "class": "org.junit.runners.ParentRunner$3",
189 "method": "run",
190 "file": "ParentRunner.java",
191 "line": 238,
192 "exact": true,
193 "location": "junit-4.11.jar",
194 "version": "?"
195 }, {
196 "class": "org.junit.runners.ParentRunner$1",
197 "method": "schedule",
198 "file": "ParentRunner.java",
199 "line": 63,
200 "exact": true,
201 "location": "junit-4.11.jar",
202 "version": "?"
203 }, {
204 "class": "org.junit.runners.ParentRunner",
205 "method": "runChildren",
206 "file": "ParentRunner.java",
207 "line": 236,
208 "exact": true,
209 "location": "junit-4.11.jar",
210 "version": "?"
211 }, {
212 "class": "org.junit.runners.ParentRunner",
213 "method": "access$000",
214 "file": "ParentRunner.java",
215 "line": 53,
216 "exact": true,
217 "location": "junit-4.11.jar",
218 "version": "?"
219 }, {
220 "class": "org.junit.runners.ParentRunner$2",
221 "method": "evaluate",
222 "file": "ParentRunner.java",
223 "line": 229,
224 "exact": true,
225 "location": "junit-4.11.jar",
226 "version": "?"
227 }, {
228 "class": "org.junit.internal.runners.statements.RunBefores",
229 "method": "evaluate",
230 "file": "RunBefores.java",
231 "line": 26,
232 "exact": true,
233 "location": "junit-4.11.jar",
234 "version": "?"
235 }, {
236 "class": "org.junit.internal.runners.statements.RunAfters",
237 "method": "evaluate",
238 "file": "RunAfters.java",
239 "line": 27,
240 "exact": true,
241 "location": "junit-4.11.jar",
242 "version": "?"
243 }, {
244 "class": "org.junit.runners.ParentRunner",
245 "method": "run",
246 "file": "ParentRunner.java",
247 "line": 309,
248 "exact": true,
249 "location": "junit-4.11.jar",
250 "version": "?"
251 }, {
252 "class": "org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference",
253 "method": "run",
254 "file": "JUnit4TestReference.java",
255 "line": 50,
256 "exact": true,
257 "location": ".cp/",
258 "version": "?"
259 }, {
260 "class": "org.eclipse.jdt.internal.junit.runner.TestExecution",
261 "method": "run",
262 "file": "TestExecution.java",
263 "line": 38,
264 "exact": true,
265 "location": ".cp/",
266 "version": "?"
267 }, {
268 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
269 "method": "runTests",
270 "file": "RemoteTestRunner.java",
271 "line": 467,
272 "exact": true,
273 "location": ".cp/",
274 "version": "?"
275 }, {
276 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
277 "method": "runTests",
278 "file": "RemoteTestRunner.java",
279 "line": 683,
280 "exact": true,
281 "location": ".cp/",
282 "version": "?"
283 }, {
284 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
285 "method": "run",
286 "file": "RemoteTestRunner.java",
287 "line": 390,
288 "exact": true,
289 "location": ".cp/",
290 "version": "?"
291 }, {
292 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
293 "method": "main",
294 "file": "RemoteTestRunner.java",
295 "line": 197,
296 "exact": true,
297 "location": ".cp/",
298 "version": "?"
299 }],
300 "localizedMessage": "testIOEx",
301 "message": "testIOEx",
302 "name": "java.io.IOException",
303 "suppressed": [{
304 "commonElementCount": 0,
305 "extendedStackTrace": [{
306 "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
307 "method": "createLogEvent",
308 "file": "LogEventFixtures.java",
309 "line": 57,
310 "exact": true,
311 "location": "test-classes/",
312 "version": "?"
313 }, {
314 "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
315 "method": "testAllFeatures",
316 "file": "JsonLayoutTest.java",
317 "line": 105,
318 "exact": true,
319 "location": "test-classes/",
320 "version": "?"
321 }, {
322 "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
323 "method": "testLocationOnCompactOnMdcOn",
324 "file": "JsonLayoutTest.java",
325 "line": 268,
326 "exact": true,
327 "location": "test-classes/",
328 "version": "?"
329 }, {
330 "class": "sun.reflect.NativeMethodAccessorImpl",
331 "method": "invoke",
332 "line": -1,
333 "exact": false,
334 "location": "?",
335 "version": "1.7.0_55"
336 }, {
337 "class": "sun.reflect.NativeMethodAccessorImpl",
338 "method": "invoke",
339 "line": -1,
340 "exact": false,
341 "location": "?",
342 "version": "1.7.0_55"
343 }, {
344 "class": "sun.reflect.DelegatingMethodAccessorImpl",
345 "method": "invoke",
346 "line": -1,
347 "exact": false,
348 "location": "?",
349 "version": "1.7.0_55"
350 }, {
351 "class": "java.lang.reflect.Method",
352 "method": "invoke",
353 "line": -1,
354 "exact": false,
355 "location": "?",
356 "version": "1.7.0_55"
357 }, {
358 "class": "org.junit.runners.model.FrameworkMethod$1",
359 "method": "runReflectiveCall",
360 "file": "FrameworkMethod.java",
361 "line": 47,
362 "exact": true,
363 "location": "junit-4.11.jar",
364 "version": "?"
365 }, {
366 "class": "org.junit.internal.runners.model.ReflectiveCallable",
367 "method": "run",
368 "file": "ReflectiveCallable.java",
369 "line": 12,
370 "exact": true,
371 "location": "junit-4.11.jar",
372 "version": "?"
373 }, {
374 "class": "org.junit.runners.model.FrameworkMethod",
375 "method": "invokeExplosively",
376 "file": "FrameworkMethod.java",
377 "line": 44,
378 "exact": true,
379 "location": "junit-4.11.jar",
380 "version": "?"
381 }, {
382 "class": "org.junit.internal.runners.statements.InvokeMethod",
383 "method": "evaluate",
384 "file": "InvokeMethod.java",
385 "line": 17,
386 "exact": true,
387 "location": "junit-4.11.jar",
388 "version": "?"
389 }, {
390 "class": "org.junit.runners.ParentRunner",
391 "method": "runLeaf",
392 "file": "ParentRunner.java",
393 "line": 271,
394 "exact": true,
395 "location": "junit-4.11.jar",
396 "version": "?"
397 }, {
398 "class": "org.junit.runners.BlockJUnit4ClassRunner",
399 "method": "runChild",
400 "file": "BlockJUnit4ClassRunner.java",
401 "line": 70,
402 "exact": true,
403 "location": "junit-4.11.jar",
404 "version": "?"
405 }, {
406 "class": "org.junit.runners.BlockJUnit4ClassRunner",
407 "method": "runChild",
408 "file": "BlockJUnit4ClassRunner.java",
409 "line": 50,
410 "exact": true,
411 "location": "junit-4.11.jar",
412 "version": "?"
413 }, {
414 "class": "org.junit.runners.ParentRunner$3",
415 "method": "run",
416 "file": "ParentRunner.java",
417 "line": 238,
418 "exact": true,
419 "location": "junit-4.11.jar",
420 "version": "?"
421 }, {
422 "class": "org.junit.runners.ParentRunner$1",
423 "method": "schedule",
424 "file": "ParentRunner.java",
425 "line": 63,
426 "exact": true,
427 "location": "junit-4.11.jar",
428 "version": "?"
429 }, {
430 "class": "org.junit.runners.ParentRunner",
431 "method": "runChildren",
432 "file": "ParentRunner.java",
433 "line": 236,
434 "exact": true,
435 "location": "junit-4.11.jar",
436 "version": "?"
437 }, {
438 "class": "org.junit.runners.ParentRunner",
439 "method": "access$000",
440 "file": "ParentRunner.java",
441 "line": 53,
442 "exact": true,
443 "location": "junit-4.11.jar",
444 "version": "?"
445 }, {
446 "class": "org.junit.runners.ParentRunner$2",
447 "method": "evaluate",
448 "file": "ParentRunner.java",
449 "line": 229,
450 "exact": true,
451 "location": "junit-4.11.jar",
452 "version": "?"
453 }, {
454 "class": "org.junit.internal.runners.statements.RunBefores",
455 "method": "evaluate",
456 "file": "RunBefores.java",
457 "line": 26,
458 "exact": true,
459 "location": "junit-4.11.jar",
460 "version": "?"
461 }, {
462 "class": "org.junit.internal.runners.statements.RunAfters",
463 "method": "evaluate",
464 "file": "RunAfters.java",
465 "line": 27,
466 "exact": true,
467 "location": "junit-4.11.jar",
468 "version": "?"
469 }, {
470 "class": "org.junit.runners.ParentRunner",
471 "method": "run",
472 "file": "ParentRunner.java",
473 "line": 309,
474 "exact": true,
475 "location": "junit-4.11.jar",
476 "version": "?"
477 }, {
478 "class": "org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference",
479 "method": "run",
480 "file": "JUnit4TestReference.java",
481 "line": 50,
482 "exact": true,
483 "location": ".cp/",
484 "version": "?"
485 }, {
486 "class": "org.eclipse.jdt.internal.junit.runner.TestExecution",
487 "method": "run",
488 "file": "TestExecution.java",
489 "line": 38,
490 "exact": true,
491 "location": ".cp/",
492 "version": "?"
493 }, {
494 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
495 "method": "runTests",
496 "file": "RemoteTestRunner.java",
497 "line": 467,
498 "exact": true,
499 "location": ".cp/",
500 "version": "?"
501 }, {
502 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
503 "method": "runTests",
504 "file": "RemoteTestRunner.java",
505 "line": 683,
506 "exact": true,
507 "location": ".cp/",
508 "version": "?"
509 }, {
510 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
511 "method": "run",
512 "file": "RemoteTestRunner.java",
513 "line": 390,
514 "exact": true,
515 "location": ".cp/",
516 "version": "?"
517 }, {
518 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
519 "method": "main",
520 "file": "RemoteTestRunner.java",
521 "line": 197,
522 "exact": true,
523 "location": ".cp/",
524 "version": "?"
525 }],
526 "localizedMessage": "I am suppressed exception 1",
527 "message": "I am suppressed exception 1",
528 "name": "java.lang.IndexOutOfBoundsException"
529 }, {
530 "commonElementCount": 0,
531 "extendedStackTrace": [{
532 "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
533 "method": "createLogEvent",
534 "file": "LogEventFixtures.java",
535 "line": 58,
536 "exact": true,
537 "location": "test-classes/",
538 "version": "?"
539 }, {
540 "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
541 "method": "testAllFeatures",
542 "file": "JsonLayoutTest.java",
543 "line": 105,
544 "exact": true,
545 "location": "test-classes/",
546 "version": "?"
547 }, {
548 "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
549 "method": "testLocationOnCompactOnMdcOn",
550 "file": "JsonLayoutTest.java",
551 "line": 268,
552 "exact": true,
553 "location": "test-classes/",
554 "version": "?"
555 }, {
556 "class": "sun.reflect.NativeMethodAccessorImpl",
557 "method": "invoke",
558 "line": -1,
559 "exact": false,
560 "location": "?",
561 "version": "1.7.0_55"
562 }, {
563 "class": "sun.reflect.NativeMethodAccessorImpl",
564 "method": "invoke",
565 "line": -1,
566 "exact": false,
567 "location": "?",
568 "version": "1.7.0_55"
569 }, {
570 "class": "sun.reflect.DelegatingMethodAccessorImpl",
571 "method": "invoke",
572 "line": -1,
573 "exact": false,
574 "location": "?",
575 "version": "1.7.0_55"
576 }, {
577 "class": "java.lang.reflect.Method",
578 "method": "invoke",
579 "line": -1,
580 "exact": false,
581 "location": "?",
582 "version": "1.7.0_55"
583 }, {
584 "class": "org.junit.runners.model.FrameworkMethod$1",
585 "method": "runReflectiveCall",
586 "file": "FrameworkMethod.java",
587 "line": 47,
588 "exact": true,
589 "location": "junit-4.11.jar",
590 "version": "?"
591 }, {
592 "class": "org.junit.internal.runners.model.ReflectiveCallable",
593 "method": "run",
594 "file": "ReflectiveCallable.java",
595 "line": 12,
596 "exact": true,
597 "location": "junit-4.11.jar",
598 "version": "?"
599 }, {
600 "class": "org.junit.runners.model.FrameworkMethod",
601 "method": "invokeExplosively",
602 "file": "FrameworkMethod.java",
603 "line": 44,
604 "exact": true,
605 "location": "junit-4.11.jar",
606 "version": "?"
607 }, {
608 "class": "org.junit.internal.runners.statements.InvokeMethod",
609 "method": "evaluate",
610 "file": "InvokeMethod.java",
611 "line": 17,
612 "exact": true,
613 "location": "junit-4.11.jar",
614 "version": "?"
615 }, {
616 "class": "org.junit.runners.ParentRunner",
617 "method": "runLeaf",
618 "file": "ParentRunner.java",
619 "line": 271,
620 "exact": true,
621 "location": "junit-4.11.jar",
622 "version": "?"
623 }, {
624 "class": "org.junit.runners.BlockJUnit4ClassRunner",
625 "method": "runChild",
626 "file": "BlockJUnit4ClassRunner.java",
627 "line": 70,
628 "exact": true,
629 "location": "junit-4.11.jar",
630 "version": "?"
631 }, {
632 "class": "org.junit.runners.BlockJUnit4ClassRunner",
633 "method": "runChild",
634 "file": "BlockJUnit4ClassRunner.java",
635 "line": 50,
636 "exact": true,
637 "location": "junit-4.11.jar",
638 "version": "?"
639 }, {
640 "class": "org.junit.runners.ParentRunner$3",
641 "method": "run",
642 "file": "ParentRunner.java",
643 "line": 238,
644 "exact": true,
645 "location": "junit-4.11.jar",
646 "version": "?"
647 }, {
648 "class": "org.junit.runners.ParentRunner$1",
649 "method": "schedule",
650 "file": "ParentRunner.java",
651 "line": 63,
652 "exact": true,
653 "location": "junit-4.11.jar",
654 "version": "?"
655 }, {
656 "class": "org.junit.runners.ParentRunner",
657 "method": "runChildren",
658 "file": "ParentRunner.java",
659 "line": 236,
660 "exact": true,
661 "location": "junit-4.11.jar",
662 "version": "?"
663 }, {
664 "class": "org.junit.runners.ParentRunner",
665 "method": "access$000",
666 "file": "ParentRunner.java",
667 "line": 53,
668 "exact": true,
669 "location": "junit-4.11.jar",
670 "version": "?"
671 }, {
672 "class": "org.junit.runners.ParentRunner$2",
673 "method": "evaluate",
674 "file": "ParentRunner.java",
675 "line": 229,
676 "exact": true,
677 "location": "junit-4.11.jar",
678 "version": "?"
679 }, {
680 "class": "org.junit.internal.runners.statements.RunBefores",
681 "method": "evaluate",
682 "file": "RunBefores.java",
683 "line": 26,
684 "exact": true,
685 "location": "junit-4.11.jar",
686 "version": "?"
687 }, {
688 "class": "org.junit.internal.runners.statements.RunAfters",
689 "method": "evaluate",
690 "file": "RunAfters.java",
691 "line": 27,
692 "exact": true,
693 "location": "junit-4.11.jar",
694 "version": "?"
695 }, {
696 "class": "org.junit.runners.ParentRunner",
697 "method": "run",
698 "file": "ParentRunner.java",
699 "line": 309,
700 "exact": true,
701 "location": "junit-4.11.jar",
702 "version": "?"
703 }, {
704 "class": "org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference",
705 "method": "run",
706 "file": "JUnit4TestReference.java",
707 "line": 50,
708 "exact": true,
709 "location": ".cp/",
710 "version": "?"
711 }, {
712 "class": "org.eclipse.jdt.internal.junit.runner.TestExecution",
713 "method": "run",
714 "file": "TestExecution.java",
715 "line": 38,
716 "exact": true,
717 "location": ".cp/",
718 "version": "?"
719 }, {
720 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
721 "method": "runTests",
722 "file": "RemoteTestRunner.java",
723 "line": 467,
724 "exact": true,
725 "location": ".cp/",
726 "version": "?"
727 }, {
728 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
729 "method": "runTests",
730 "file": "RemoteTestRunner.java",
731 "line": 683,
732 "exact": true,
733 "location": ".cp/",
734 "version": "?"
735 }, {
736 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
737 "method": "run",
738 "file": "RemoteTestRunner.java",
739 "line": 390,
740 "exact": true,
741 "location": ".cp/",
742 "version": "?"
743 }, {
744 "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
745 "method": "main",
746 "file": "RemoteTestRunner.java",
747 "line": 197,
748 "exact": true,
749 "location": ".cp/",
750 "version": "?"
751 }],
752 "localizedMessage": "I am suppressed exception 2",
753 "message": "I am suppressed exception 2",
754 "name": "java.lang.IndexOutOfBoundsException"
755 }]
756 },
757 "loggerFQCN": "f.q.c.n",
758 "endOfBatch": false,
759 "contextMap": [{
760 "key": "MDC.B",
761 "value": "B_Value"
762 }, {
763 "key": "MDC.A",
764 "value": "A_Value"
765 }],
766 "contextStack": ["stack_msg1", "stack_msg2"],
767 "source": {
768 "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
769 "method": "createLogEvent",
770 "file": "LogEventFixtures.java",
771 "line": 54
772 }
773 }
774 * </pre>
775 * <p>
776 * If {@code complete="false"}, the appender does not write the JSON open array character "[" at the start of the document. and "]" and the
777 * end.
778 * </p>
779 * <p>
780 * This approach enforces the independence of the JsonLayout and the appender where you embed it.
781 * </p>
782 * <h3>Encoding</h3>
783 * <p>
784 * Appenders using this layout should have their {@code charset} set to {@code UTF-8} or {@code UTF-16}, otherwise events containing non
785 * ASCII characters could result in corrupted log files.
786 * </p>
787 * <h3>Pretty vs. compact XML</h3>
788 * <p>
789 * By default, the JSON layout is not compact (a.k.a. not "pretty") with {@code compact="false"}, which means the appender uses end-of-line
790 * characters and indents lines to format the text. If {@code compact="true"}, then no end-of-line or indentation is used. Message content
791 * may contain, of course, escaped end-of-lines.
792 * </p>
793 */
794 @Plugin(name = "JsonLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
795 public final class JsonLayout extends AbstractJacksonLayout {
796
797 static final String CONTENT_TYPE = "application/json";
798
799 private static final long serialVersionUID = 1L;
800
801 protected JsonLayout(final boolean locationInfo, final boolean properties, final boolean complete, final boolean compact,
802 boolean eventEol, final Charset charset) {
803 super(new JacksonFactory.JSON().newWriter(locationInfo, properties, compact), charset, compact, complete, eventEol);
804 }
805
806 /**
807 * Returns appropriate JSON header.
808 *
809 * @return a byte array containing the header, opening the JSON array.
810 */
811 @Override
812 public byte[] getHeader() {
813 if (!this.complete) {
814 return null;
815 }
816 final StringBuilder buf = new StringBuilder();
817 buf.append('[');
818 buf.append(this.eol);
819 return getBytes(buf.toString());
820 }
821
822 /**
823 * Returns appropriate JSON footer.
824 *
825 * @return a byte array containing the footer, closing the JSON array.
826 */
827 @Override
828 public byte[] getFooter() {
829 if (!this.complete) {
830 return null;
831 }
832 return getBytes(this.eol + ']' + this.eol);
833 }
834
835 @Override
836 public Map<String, String> getContentFormat() {
837 final Map<String, String> result = new HashMap<String, String>();
838 result.put("version", "2.0");
839 return result;
840 }
841
842 @Override
843 /**
844 * @return The content type.
845 */
846 public String getContentType() {
847 return CONTENT_TYPE + "; charset=" + this.getCharset();
848 }
849
850 /**
851 * Creates a JSON Layout.
852 *
853 * @param locationInfo
854 * If "true", includes the location information in the generated JSON.
855 * @param properties
856 * If "true", includes the thread context in the generated JSON.
857 * @param complete
858 * If "true", includes the JSON header and footer, defaults to "false".
859 * @param compact
860 * If "true", does not use end-of-lines and indentation, defaults to "false".
861 * @param eventEol
862 * If "true", forces an EOL after each log event (even if compact is "true"), defaults to "false". This
863 * allows one even per line, even in compact mode.
864 * @param charset
865 * The character set to use, if {@code null}, uses "UTF-8".
866 * @return A JSON Layout.
867 */
868 @PluginFactory
869 public static AbstractJacksonLayout createLayout(
870 // @formatter:off
871 @PluginAttribute(value = "locationInfo", defaultBoolean = false) final boolean locationInfo,
872 @PluginAttribute(value = "properties", defaultBoolean = false) final boolean properties,
873 @PluginAttribute(value = "complete", defaultBoolean = false) final boolean complete,
874 @PluginAttribute(value = "compact", defaultBoolean = false) final boolean compact,
875 @PluginAttribute(value = "eventEol", defaultBoolean = false) final boolean eventEol,
876 @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charset
877 // @formatter:on
878 ) {
879 return new JsonLayout(locationInfo, properties, complete, compact, eventEol, charset);
880 }
881
882 /**
883 * Creates a JSON Layout using the default settings.
884 *
885 * @return A JSON Layout.
886 */
887 public static AbstractJacksonLayout createDefaultLayout() {
888 return new JsonLayout(false, false, false, false, false, Constants.UTF_8);
889 }
890 }