/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache license, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the license for the specific language governing permissions and
 * limitations under the license.
 */
package org.apache.logging.log4j.core.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import org.apache.logging.log4j.core.pattern.JAnsiTextRenderer;
import org.apache.logging.log4j.core.pattern.PlainTextRenderer;
import org.apache.logging.log4j.core.pattern.TextRenderer;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.Patterns;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Strings;

Contains options which control how a Throwable pattern is formatted.
/** * Contains options which control how a {@link Throwable} pattern is formatted. */
public final class ThrowableFormatOptions { private static final int DEFAULT_LINES = Integer.MAX_VALUE;
Default instance of ThrowableFormatOptions.
/** * Default instance of {@code ThrowableFormatOptions}. */
protected static final ThrowableFormatOptions DEFAULT = new ThrowableFormatOptions();
Format the whole stack trace.
/** * Format the whole stack trace. */
private static final String FULL = "full";
Do not format the exception.
/** * Do not format the exception. */
private static final String NONE = "none";
Format only the first line of the throwable.
/** * Format only the first line of the throwable. */
private static final String SHORT = "short";
ANSI renderer
/** * ANSI renderer */
private final TextRenderer textRenderer;
The number of lines to write.
/** * The number of lines to write. */
private final int lines;
The stack trace separator.
/** * The stack trace separator. */
private final String separator; private final String suffix;
The list of packages to filter.
/** * The list of packages to filter. */
private final List<String> ignorePackages; public static final String CLASS_NAME = "short.className"; public static final String METHOD_NAME = "short.methodName"; public static final String LINE_NUMBER = "short.lineNumber"; public static final String FILE_NAME = "short.fileName"; public static final String MESSAGE = "short.message"; public static final String LOCALIZED_MESSAGE = "short.localizedMessage";
Constructs the options for printing stack trace.
Params:
  • lines – The number of lines.
  • separator – The stack trace separator.
  • ignorePackages – The packages to filter.
  • textRenderer – The ANSI renderer
  • suffix –
/** * Constructs the options for printing stack trace. * * @param lines * The number of lines. * @param separator * The stack trace separator. * @param ignorePackages * The packages to filter. * @param textRenderer * The ANSI renderer * @param suffix */
protected ThrowableFormatOptions(final int lines, final String separator, final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix) { this.lines = lines; this.separator = separator == null ? Strings.LINE_SEPARATOR : separator; this.ignorePackages = ignorePackages; this.textRenderer = textRenderer == null ? PlainTextRenderer.getInstance() : textRenderer; this.suffix = suffix; }
Constructs the options for printing stack trace.
Params:
  • packages – The packages to filter.
/** * Constructs the options for printing stack trace. * * @param packages * The packages to filter. */
protected ThrowableFormatOptions(final List<String> packages) { this(DEFAULT_LINES, null, packages, null, null); }
Constructs the options for printing stack trace.
/** * Constructs the options for printing stack trace. */
protected ThrowableFormatOptions() { this(DEFAULT_LINES, null, null, null, null); }
Returns the number of lines to write.
Returns:The number of lines to write.
/** * Returns the number of lines to write. * * @return The number of lines to write. */
public int getLines() { return this.lines; }
Returns the stack trace separator.
Returns:The stack trace separator.
/** * Returns the stack trace separator. * * @return The stack trace separator. */
public String getSeparator() { return this.separator; }
Returns the message rendered.
Returns:the message rendered.
/** * Returns the message rendered. * * @return the message rendered. */
public TextRenderer getTextRenderer() { return textRenderer; }
Returns the list of packages to ignore (filter out).
Returns:The list of packages to ignore (filter out).
/** * Returns the list of packages to ignore (filter out). * * @return The list of packages to ignore (filter out). */
public List<String> getIgnorePackages() { return this.ignorePackages; }
Determines if all lines should be printed.
Returns:true for all lines, false otherwise.
/** * Determines if all lines should be printed. * * @return true for all lines, false otherwise. */
public boolean allLines() { return this.lines == DEFAULT_LINES; }
Determines if any lines should be printed.
Returns:true for any lines, false otherwise.
/** * Determines if any lines should be printed. * * @return true for any lines, false otherwise. */
public boolean anyLines() { return this.lines > 0; }
Returns the minimum between the lines and the max lines.
Params:
  • maxLines – The maximum number of lines.
Returns:The number of lines to print.
/** * Returns the minimum between the lines and the max lines. * * @param maxLines * The maximum number of lines. * @return The number of lines to print. */
public int minLines(final int maxLines) { return this.lines > maxLines ? maxLines : this.lines; }
Determines if there are any packages to filter.
Returns:true if there are packages, false otherwise.
/** * Determines if there are any packages to filter. * * @return true if there are packages, false otherwise. */
public boolean hasPackages() { return this.ignorePackages != null && !this.ignorePackages.isEmpty(); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override public String toString() { final StringBuilder s = new StringBuilder(); s.append('{') .append(allLines() ? FULL : this.lines == 2 ? SHORT : anyLines() ? String.valueOf(this.lines) : NONE) .append('}'); s.append("{separator(").append(this.separator).append(")}"); if (hasPackages()) { s.append("{filters("); for (final String p : this.ignorePackages) { s.append(p).append(','); } s.deleteCharAt(s.length() - 1); s.append(")}"); } return s.toString(); }
Creates a new instance based on the array of options.
Params:
  • options – The array of options.
Returns:A new initialized instance.
/** * Creates a new instance based on the array of options. * * @param options * The array of options. * @return A new initialized instance. */
public static ThrowableFormatOptions newInstance(String[] options) { if (options == null || options.length == 0) { return DEFAULT; } // NOTE: The following code is present for backward compatibility // and was copied from Extended/RootThrowablePatternConverter. // This supports a single option with the format: // %xEx{["none"|"short"|"full"|depth],[filters(packages)} // However, the convention for multiple options should be: // %xEx{["none"|"short"|"full"|depth]}[{filters(packages)}] if (options.length == 1 && Strings.isNotEmpty(options[0])) { final String[] opts = options[0].split(Patterns.COMMA_SEPARATOR, 2); final String first = opts[0].trim(); try (final Scanner scanner = new Scanner(first)) { if (opts.length > 1 && (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT) || first.equalsIgnoreCase(NONE) || scanner.hasNextInt())) { options = new String[] { first, opts[1].trim() }; } } } int lines = DEFAULT.lines; String separator = DEFAULT.separator; List<String> packages = DEFAULT.ignorePackages; TextRenderer ansiRenderer = DEFAULT.textRenderer; String suffix = DEFAULT.getSuffix(); for (final String rawOption : options) { if (rawOption != null) { final String option = rawOption.trim(); if (option.isEmpty()) { // continue; } else if (option.startsWith("separator(") && option.endsWith(")")) { separator = option.substring("separator(".length(), option.length() - 1); } else if (option.startsWith("filters(") && option.endsWith(")")) { final String filterStr = option.substring("filters(".length(), option.length() - 1); if (filterStr.length() > 0) { final String[] array = filterStr.split(Patterns.COMMA_SEPARATOR); if (array.length > 0) { packages = new ArrayList<>(array.length); for (String token : array) { token = token.trim(); if (token.length() > 0) { packages.add(token); } } } } } else if (option.equalsIgnoreCase(NONE)) { lines = 0; } else if (option.equalsIgnoreCase(SHORT) || option.equalsIgnoreCase(CLASS_NAME) || option.equalsIgnoreCase(METHOD_NAME) || option.equalsIgnoreCase(LINE_NUMBER) || option.equalsIgnoreCase(FILE_NAME) || option.equalsIgnoreCase(MESSAGE) || option.equalsIgnoreCase(LOCALIZED_MESSAGE)) { lines = 2; } else if (option.startsWith("ansi(") && option.endsWith(")") || option.equals("ansi")) { if (Loader.isJansiAvailable()) { final String styleMapStr = option.equals("ansi") ? Strings.EMPTY : option.substring("ansi(".length(), option.length() - 1); ansiRenderer = new JAnsiTextRenderer(new String[] { null, styleMapStr }, JAnsiTextRenderer.DefaultExceptionStyleMap); } else { StatusLogger.getLogger().warn( "You requested ANSI exception rendering but JANSI is not on the classpath. Please see https://logging.apache.org/log4j/2.x/runtime-dependencies.html"); } } else if (option.startsWith("S(") && option.endsWith(")")){ suffix = option.substring("S(".length(), option.length() - 1); } else if (option.startsWith("suffix(") && option.endsWith(")")){ suffix = option.substring("suffix(".length(), option.length() - 1); } else if (!option.equalsIgnoreCase(FULL)) { lines = Integer.parseInt(option); } } } return new ThrowableFormatOptions(lines, separator, packages, ansiRenderer, suffix); } public String getSuffix() { return suffix; } }