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    }