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 }