    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    }