    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 java.util.List;
    020
    021    import org.apache.logging.log4j.core.LogEvent;
    022    import org.apache.logging.log4j.core.config.Configuration;
    023    import org.apache.logging.log4j.core.config.plugins.Plugin;
    024    import org.apache.logging.log4j.core.layout.PatternLayout;
    025    import org.apache.logging.log4j.core.util.Patterns;
    026
    027    /**
    028     * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
    029     */
    030    @Plugin(name = "style", category = PatternConverter.CATEGORY)
    031    @ConverterKeys({ "style" })
    032    public final class StyleConverter extends LogEventPatternConverter implements AnsiConverter {
    033
    034        /**
    035         * Gets an instance of the class.
    036         *
    037         * @param config
    038         *            The current Configuration.
    039         * @param options
    040         *            pattern options, may be null. If first element is "short", only the first line of the throwable will
    041         *            be formatted.
    042         * @return instance of class.
    043         */
    044        public static StyleConverter newInstance(final Configuration config, final String[] options) {
    045            if (options.length < 1) {
    046                LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length);
    047                return null;
    048            }
    049            if (options[0] == null) {
    050                LOGGER.error("No pattern supplied on style");
    051                return null;
    052            }
    053            if (options[1] == null) {
    054                LOGGER.error("No style attributes provided");
    055                return null;
    056            }
    057            final PatternParser parser = PatternLayout.createPatternParser(config);
    058            final List<PatternFormatter> formatters = parser.parse(options[0]);
    059            final String style = AnsiEscape.createSequence(options[1].split(Patterns.COMMA_SEPARATOR));
    060            final boolean noConsoleNoAnsi = options.length > 2
    061                    && (PatternParser.NO_CONSOLE_NO_ANSI + "=true").equals(options[2]);
    062            final boolean hideAnsi = noConsoleNoAnsi && System.console() == null;
    063            return new StyleConverter(formatters, style, hideAnsi);
    064        }
    065
    066        private final List<PatternFormatter> patternFormatters;
    067
    068        private final boolean noAnsi;
    069
    070        private final String style;
    071
    072        private final String defaultStyle;
    073
    074        /**
    075         * Constructs the converter.
    076         *
    077         * @param patternFormatters
    078         *            The PatternFormatters to generate the text to manipulate.
    079         * @param style
    080         *            The style that should encapsulate the pattern.
    081         * @param noAnsi
    082         *            If true, do not output ANSI escape codes.
    083         */
    084        private StyleConverter(final List<PatternFormatter> patternFormatters, final String style, final boolean noAnsi) {
    085            super("style", "style");
    086            this.patternFormatters = patternFormatters;
    087            this.style = style;
    088            this.defaultStyle = AnsiEscape.getDefaultStyle();
    089            this.noAnsi = noAnsi;
    090        }
    091
    092        /**
    093         * {@inheritDoc}
    094         */
    095        @Override
    096        public void format(final LogEvent event, final StringBuilder toAppendTo) {
    097            final StringBuilder buf = new StringBuilder();
    098            for (final PatternFormatter formatter : patternFormatters) {
    099                formatter.format(event, buf);
    100            }
    101
    102            if (buf.length() > 0) {
    103                if (noAnsi) {
    104                    // faster to test and do this than setting style and defaultStyle to empty strings.
    105                    toAppendTo.append(buf.toString());
    106                } else {
    107                    toAppendTo.append(style).append(buf.toString()).append(defaultStyle);
    108                }
    109            }
    110        }
    111
    112        @Override
    113        public boolean handlesThrowable() {
    114            for (final PatternFormatter formatter : patternFormatters) {
    115                if (formatter.handlesThrowable()) {
    116                    return true;
    117                }
    118            }
    119            return false;
    120        }
    121
    122        /**
    123         * Returns a String suitable for debugging.
    124         *
    125         * @return a String suitable for debugging.
    126         */
    127        @Override
    128        public String toString() {
    129            final StringBuilder sb = new StringBuilder();
    130            sb.append(super.toString());
    131            sb.append("[style=");
    132            sb.append(style);
    133            sb.append(", defaultStyle=");
    134            sb.append(defaultStyle);
    135            sb.append(", patternFormatters=");
    136            sb.append(patternFormatters);
    137            sb.append(", noAnsi=");
    138            sb.append(noAnsi);
    139            sb.append(']');
    140            return sb.toString();
    141        }
    142
    143    }