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.ThrowableProxy; 022 023 import java.util.ArrayList; 024 import java.util.List; 025 import java.util.Scanner; 026 027 028 /** 029 * Outputs the Throwable portion of the LoggingEvent as a full stacktrace 030 * unless this converter's option is 'short', where it just outputs the first line of the trace, or if 031 * the number of lines to print is explicitly specified. 032 * <p> 033 * The extended stack trace will also include the location of where the class was loaded from and the 034 * version of the jar if available. 035 */ 036 @Plugin(name = "RootThrowablePatternConverter", type = "Converter") 037 @ConverterKeys({"rEx", "rThrowable", "rException" }) 038 public final class RootThrowablePatternConverter extends ThrowablePatternConverter { 039 040 private static final String FILTERS = "filters("; 041 042 private final List<String> packages; 043 044 /** 045 * Private constructor. 046 * 047 * @param options options, may be null. 048 */ 049 private RootThrowablePatternConverter(final String[] options) { 050 super("RootThrowable", "throwable", options); 051 List<String> tempPackages = null; 052 if (options != null && options.length > 1) { 053 if (options[1].startsWith(FILTERS) && options[1].endsWith(")")) { 054 final String filterStr = options[1].substring(FILTERS.length(), options[1].length() - 1); 055 final String[] array = filterStr.split(","); 056 if (array.length > 0) { 057 tempPackages = new ArrayList<String>(array.length); 058 for (final String token : array) { 059 tempPackages.add(token.trim()); 060 } 061 } 062 } 063 } 064 packages = tempPackages; 065 } 066 067 /** 068 * Gets an instance of the class. 069 * 070 * @param options pattern options, may be null. If first element is "short", 071 * only the first line of the throwable will be formatted. 072 * @return instance of class. 073 */ 074 public static RootThrowablePatternConverter newInstance(final String[] options) { 075 String type = null; 076 String[] array = options; 077 if (options != null && options.length == 1 && options[0].length() > 0) { 078 final String[] opts = options[0].split(",", 2); 079 final String first = opts[0].trim(); 080 String filter; 081 final Scanner scanner = new Scanner(first); 082 if (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT) || scanner.hasNextInt()) { 083 type = first; 084 filter = opts[1].trim(); 085 } else { 086 filter = options[0].trim(); 087 } 088 array = new String[] {type, filter}; 089 } 090 091 return new RootThrowablePatternConverter(array); 092 } 093 094 /** 095 * {@inheritDoc} 096 */ 097 @Override 098 public void format(final LogEvent event, final StringBuilder toAppendTo) { 099 final Throwable throwable = event.getThrown(); 100 if (throwable != null && lines > 0) { 101 if (!(throwable instanceof ThrowableProxy)) { 102 super.format(event, toAppendTo); 103 return; 104 } 105 final ThrowableProxy t = (ThrowableProxy) throwable; 106 final String trace = t.getRootCauseStackTrace(packages); 107 final int len = toAppendTo.length(); 108 if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) { 109 toAppendTo.append(" "); 110 } 111 if (lines != Integer.MAX_VALUE) { 112 final StringBuilder sb = new StringBuilder(); 113 final String[] array = trace.split("\n"); 114 final int limit = lines > array.length ? array.length : lines; 115 for (int i = 0; i < limit; ++i) { 116 sb.append(array[i]).append("\n"); 117 } 118 toAppendTo.append(sb.toString()); 119 120 } else { 121 toAppendTo.append(trace); 122 } 123 } 124 } 125 }