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