JsonThrowablePatternConverter.java 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * @notice
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache license, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the license for the specific language governing permissions and
  16. * limitations under the license.
  17. */
  18. package org.elasticsearch.common.logging;
  19. import org.apache.logging.log4j.core.LogEvent;
  20. import org.apache.logging.log4j.core.config.Configuration;
  21. import org.apache.logging.log4j.core.config.plugins.Plugin;
  22. import org.apache.logging.log4j.core.pattern.ConverterKeys;
  23. import org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter;
  24. import org.apache.logging.log4j.core.pattern.PatternConverter;
  25. import org.apache.logging.log4j.core.pattern.ThrowablePatternConverter;
  26. import org.apache.logging.log4j.util.Strings;
  27. import org.elasticsearch.xcontent.json.JsonStringEncoder;
  28. import java.nio.charset.Charset;
  29. import java.util.StringJoiner;
  30. /**
  31. * Outputs the Throwable portion of the LoggingEvent as a Json formatted field with array
  32. * "exception": [ "stacktrace", "lines", "as", "array", "elements" ]
  33. *
  34. * Reusing @link org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter which already converts a Throwable from
  35. * LoggingEvent into a multiline string
  36. */
  37. @Plugin(name = "JsonThrowablePatternConverter", category = PatternConverter.CATEGORY)
  38. @ConverterKeys({ "exceptionAsJson" })
  39. public final class JsonThrowablePatternConverter extends ThrowablePatternConverter {
  40. private final ExtendedThrowablePatternConverter throwablePatternConverter;
  41. /**
  42. * Private as only expected to be used by log4j2 newInstance method
  43. */
  44. private JsonThrowablePatternConverter(final Configuration config, final String[] options) {
  45. super("JsonThrowablePatternConverter", "throwable", options, config);
  46. this.throwablePatternConverter = ExtendedThrowablePatternConverter.newInstance(config, options);
  47. }
  48. /**
  49. * Gets an instance of the class.
  50. *
  51. * @param config The current Configuration.
  52. * @param options pattern options, may be null. If first element is "short",
  53. * only the first line of the throwable will be formatted.
  54. * @return instance of class.
  55. */
  56. public static JsonThrowablePatternConverter newInstance(final Configuration config, final String[] options) {
  57. return new JsonThrowablePatternConverter(config, options);
  58. }
  59. /**
  60. * {@inheritDoc}
  61. */
  62. @Override
  63. public void format(final LogEvent event, final StringBuilder toAppendTo) {
  64. String consoleStacktrace = formatStacktrace(event);
  65. if (Strings.isNotEmpty(consoleStacktrace)) {
  66. String jsonStacktrace = formatJson(consoleStacktrace);
  67. toAppendTo.append(", ");
  68. toAppendTo.append(jsonStacktrace);
  69. }
  70. }
  71. private String formatStacktrace(LogEvent event) {
  72. StringBuilder stringBuilder = new StringBuilder();
  73. throwablePatternConverter.format(event, stringBuilder);
  74. return stringBuilder.toString();
  75. }
  76. private String formatJson(String consoleStacktrace) {
  77. String lineSeparator = options.getSeparator() + "\t|" + options.getSeparator();
  78. String[] split = consoleStacktrace.split(lineSeparator);
  79. StringJoiner stringJoiner = new StringJoiner(",\n", "\n\"stacktrace\": [", "]");
  80. for (String line : split) {
  81. stringJoiner.add(wrapAsJson(line));
  82. }
  83. return stringJoiner.toString();
  84. }
  85. private String wrapAsJson(String line) {
  86. byte[] bytes = JsonStringEncoder.getInstance().quoteAsUTF8(line);
  87. return "\"" + new String(bytes, Charset.defaultCharset()) + "\"";
  88. }
  89. @Override
  90. public boolean handlesThrowable() {
  91. return true;
  92. }
  93. }