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.layout;
018    
019    import java.util.HashMap;
020    import java.util.Map;
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.config.plugins.PluginAttr;
025    import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
026    import org.apache.logging.log4j.core.config.plugins.PluginElement;
027    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
028    import org.apache.logging.log4j.core.helpers.Charsets;
029    import org.apache.logging.log4j.core.helpers.OptionConverter;
030    import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
031    import org.apache.logging.log4j.core.pattern.PatternFormatter;
032    import org.apache.logging.log4j.core.pattern.PatternParser;
033    import org.apache.logging.log4j.core.pattern.RegexReplacement;
034    
035    import java.nio.charset.Charset;
036    import java.util.List;
037    
038    /**
039     * <p>A flexible layout configurable with pattern string. The goal of this class
040     * is to {@link org.apache.logging.log4j.core.Layout#toByteArray format} a {@link LogEvent} and return the results.
041     * The format of the result depends on the <em>conversion pattern</em>.
042     * <p>
043     * <p/>
044     * <p>The conversion pattern is closely related to the conversion
045     * pattern of the printf function in C. A conversion pattern is
046     * composed of literal text and format control expressions called
047     * <em>conversion specifiers</em>.
048     *
049     * See the Log4j Manual for details on the supported pattern converters.
050     */
051    @Plugin(name = "PatternLayout", type = "Core", elementType = "layout", printObject = true)
052    public final class PatternLayout extends AbstractStringLayout {
053        /**
054         * Default pattern string for log output. Currently set to the
055         * string <b>"%m%n"</b> which just prints the application supplied
056         * message.
057         */
058        public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
059    
060        /**
061         * A conversion pattern equivalent to the TTCCCLayout.
062         * Current value is <b>%r [%t] %p %c %x - %m%n</b>.
063         */
064        public static final String TTCC_CONVERSION_PATTERN =
065            "%r [%t] %p %c %x - %m%n";
066    
067        /**
068         * A simple pattern.
069         * Current value is <b>%d [%t] %p %c - %m%n</b>.
070         */
071        public static final String SIMPLE_CONVERSION_PATTERN =
072            "%d [%t] %p %c - %m%n";
073    
074        /** Key to identify pattern converters. */
075        public static final String KEY = "Converter";
076    
077        /**
078         * Initial converter for pattern.
079         */
080        private List<PatternFormatter> formatters;
081    
082        /**
083         * Conversion pattern.
084         */
085        private final String conversionPattern;
086    
087    
088        /**
089         * The current Configuration.
090         */
091        private final Configuration config;
092    
093        private final RegexReplacement replace;
094    
095        /**
096         * Constructs a EnhancedPatternLayout using the supplied conversion pattern.
097         *
098         * @param config The Configuration.
099         * @param replace The regular expression to match.
100         * @param pattern conversion pattern.
101         * @param charset The character set.
102         */
103        private PatternLayout(final Configuration config, final RegexReplacement replace, final String pattern,
104                             final Charset charset) {
105            super(charset);
106            this.replace = replace;
107            this.conversionPattern = pattern;
108            this.config = config;
109            final PatternParser parser = createPatternParser(config);
110            formatters = parser.parse(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, true);
111        }
112    
113        /**
114         * Set the <b>ConversionPattern</b> option. This is the string which
115         * controls formatting and consists of a mix of literal content and
116         * conversion specifiers.
117         *
118         * @param conversionPattern conversion pattern.
119         */
120        public void setConversionPattern(final String conversionPattern) {
121            final String pattern = OptionConverter.convertSpecialChars(conversionPattern);
122            if (pattern == null) {
123                return;
124            }
125            final PatternParser parser = createPatternParser(this.config);
126            formatters = parser.parse(pattern);
127        }
128    
129        /**
130         * PatternLayout's content format is specified by:<p/>
131         * Key: "structured" Value: "false"<p/>
132         * Key: "formatType" Value: "conversion" (format uses the keywords supported by OptionConverter)<p/>
133         * Key: "format" Value: provided "conversionPattern" param
134         * @return Map of content format keys supporting PatternLayout
135         */
136        public Map<String, String> getContentFormat()
137        {
138            Map<String, String> result = new HashMap<String, String>();
139            result.put("structured", "false");
140            result.put("formatType", "conversion");
141            result.put("format", conversionPattern);
142            return result;
143        }
144    
145        /**
146         * Formats a logging event to a writer.
147         *
148         *
149         * @param event logging event to be formatted.
150         * @return The event formatted as a String.
151         */
152        public String toSerializable(final LogEvent event) {
153            final StringBuilder buf = new StringBuilder();
154            for (final PatternFormatter formatter : formatters) {
155                formatter.format(event, buf);
156            }
157            String str = buf.toString();
158            if (replace != null) {
159                str = replace.format(str);
160            }
161            return str;
162        }
163    
164        /**
165         * Create a PatternParser.
166         * @param config The Configuration.
167         * @return The PatternParser.
168         */
169        public static PatternParser createPatternParser(final Configuration config) {
170            if (config == null) {
171                return new PatternParser(config, KEY, LogEventPatternConverter.class);
172            }
173            PatternParser parser = (PatternParser) config.getComponent(KEY);
174            if (parser == null) {
175                parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
176                config.addComponent(KEY, parser);
177                parser = (PatternParser) config.getComponent(KEY);
178            }
179            return parser;
180        }
181    
182        @Override
183        public String toString() {
184            return conversionPattern;
185        }
186    
187        /**
188         * Create a pattern layout.
189         * @param pattern The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN.
190         * @param config The Configuration. Some Converters require access to the Interpolator.
191         * @param replace A Regex replacement String.
192         * @param charsetName The character set.
193         * @return The PatternLayout.
194         */
195        @PluginFactory
196        public static PatternLayout createLayout(@PluginAttr("pattern") final String pattern,
197                                                 @PluginConfiguration final Configuration config,
198                                                 @PluginElement("replace") final RegexReplacement replace,
199                                                 @PluginAttr("charset") final String charsetName) {
200            final Charset charset = Charsets.getSupportedCharset(charsetName);
201            return new PatternLayout(config, replace, pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, charset);
202        }
203    }