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