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 }