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.pattern;
018
019 import org.apache.logging.log4j.core.LogEvent;
020 import org.apache.logging.log4j.core.config.plugins.Plugin;
021 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
022 import org.apache.logging.log4j.core.impl.ThrowableProxy;
023 import org.apache.logging.log4j.core.util.Constants;
024
025 /**
026 * Outputs the Throwable portion of the LoggingEvent as a full stack trace
027 * unless this converter's option is 'short', where it just outputs the first line of the trace, or if
028 * the number of lines to print is explicitly specified.
029 * <p>
030 * The extended stack trace will also include the location of where the class was loaded from and the
031 * version of the jar if available.
032 */
033 @Plugin(name = "RootThrowablePatternConverter", category = PatternConverter.CATEGORY)
034 @ConverterKeys({ "rEx", "rThrowable", "rException" })
035 public final class RootThrowablePatternConverter extends ThrowablePatternConverter {
036
037 /**
038 * Private constructor.
039 *
040 * @param options options, may be null.
041 */
042 private RootThrowablePatternConverter(final String[] options) {
043 super("RootThrowable", "throwable", options);
044 }
045
046 /**
047 * Gets an instance of the class.
048 *
049 * @param options pattern options, may be null. If first element is "short",
050 * only the first line of the throwable will be formatted.
051 * @return instance of class.
052 */
053 public static RootThrowablePatternConverter newInstance(final String[] options) {
054 return new RootThrowablePatternConverter(options);
055 }
056
057 /**
058 * {@inheritDoc}
059 */
060 @Override
061 public void format(final LogEvent event, final StringBuilder toAppendTo) {
062 ThrowableProxy proxy = null;
063 if (event instanceof Log4jLogEvent) {
064 proxy = ((Log4jLogEvent) event).getThrownProxy();
065 }
066 final Throwable throwable = event.getThrown();
067 if (throwable != null && options.anyLines()) {
068 if (proxy == null) {
069 super.format(event, toAppendTo);
070 return;
071 }
072 final String trace = proxy.getCauseStackTraceAsString(options.getPackages());
073 final int len = toAppendTo.length();
074 if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) {
075 toAppendTo.append(' ');
076 }
077 if (!options.allLines() || !Constants.LINE_SEPARATOR.equals(options.getSeparator())) {
078 final StringBuilder sb = new StringBuilder();
079 final String[] array = trace.split(Constants.LINE_SEPARATOR);
080 final int limit = options.minLines(array.length) - 1;
081 for (int i = 0; i <= limit; ++i) {
082 sb.append(array[i]);
083 if (i < limit) {
084 sb.append(options.getSeparator());
085 }
086 }
087 toAppendTo.append(sb.toString());
088
089 } else {
090 toAppendTo.append(trace);
091 }
092 }
093 }
094 }