View Javadoc

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