001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.layout;
018    
019    import java.nio.charset.Charset;
020    import java.util.HashMap;
021    import java.util.Map;
022    
023    import org.apache.logging.log4j.core.Layout;
024    import org.apache.logging.log4j.core.config.Node;
025    import org.apache.logging.log4j.core.config.plugins.Plugin;
026    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
027    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
028    import org.apache.logging.log4j.core.util.Constants;
029    
030    /**
031     * Appends a series of JSON events as strings serialized as bytes.
032     *
033     * <h3>Complete well-formed JSON vs. fragment JSON</h3>
034     * <p>
035     * If you configure {@code complete="true"}, the appender outputs a well-formed JSON document. By default, with {@code complete="false"},
036     * you should include the output as an <em>external file</em> in a separate file to form a well-formed JSON document.
037     * </p>
038     * <p>
039     * A well-formed JSON event follows this pattern:
040     * </p>
041     *
042     * <pre>
043     * {
044      "timeMillis": 1,
045      "thread": "MyThreadName",
046      "level": "DEBUG",
047      "loggerName": "a.B",
048      "marker": {
049        "name": "Marker1",
050        "parents": [{
051          "name": "ParentMarker1",
052          "parents": [{
053            "name": "GrandMotherMarker"
054          }, {
055            "name": "GrandFatherMarker"
056          }]
057        }, {
058          "name": "GrandFatherMarker"
059        }]
060      },
061      "message": "Msg",
062      "thrown": {
063        "cause": {
064          "commonElementCount": 27,
065          "extendedStackTrace": [{
066            "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
067            "method": "createLogEvent",
068            "file": "LogEventFixtures.java",
069            "line": 53,
070            "exact": false,
071            "location": "test-classes/",
072            "version": "?"
073          }],
074          "localizedMessage": "testNPEx",
075          "message": "testNPEx",
076          "name": "java.lang.NullPointerException"
077        },
078        "commonElementCount": 0,
079        "extendedStackTrace": [{
080          "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
081          "method": "createLogEvent",
082          "file": "LogEventFixtures.java",
083          "line": 56,
084          "exact": true,
085          "location": "test-classes/",
086          "version": "?"
087        }, {
088          "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
089          "method": "testAllFeatures",
090          "file": "JsonLayoutTest.java",
091          "line": 105,
092          "exact": true,
093          "location": "test-classes/",
094          "version": "?"
095        }, {
096          "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
097          "method": "testLocationOnCompactOnMdcOn",
098          "file": "JsonLayoutTest.java",
099          "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    }