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", category = "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        public String getConversionPattern() {
130            return conversionPattern;
131        }
132    
133        /**
134         * PatternLayout's content format is specified by:<p/>
135         * Key: "structured" Value: "false"<p/>
136         * Key: "formatType" Value: "conversion" (format uses the keywords supported by OptionConverter)<p/>
137         * Key: "format" Value: provided "conversionPattern" param
138         * @return Map of content format keys supporting PatternLayout
139         */
140        public Map<String, String> getContentFormat()
141        {
142            Map<String, String> result = new HashMap<String, String>();
143            result.put("structured", "false");
144            result.put("formatType", "conversion");
145            result.put("format", conversionPattern);
146            return result;
147        }
148    
149        /**
150         * Formats a logging event to a writer.
151         *
152         *
153         * @param event logging event to be formatted.
154         * @return The event formatted as a String.
155         */
156        public String toSerializable(final LogEvent event) {
157            final StringBuilder buf = new StringBuilder();
158            for (final PatternFormatter formatter : formatters) {
159                formatter.format(event, buf);
160            }
161            String str = buf.toString();
162            if (replace != null) {
163                str = replace.format(str);
164            }
165            return str;
166        }
167    
168        /**
169         * Create a PatternParser.
170         * @param config The Configuration.
171         * @return The PatternParser.
172         */
173        public static PatternParser createPatternParser(final Configuration config) {
174            if (config == null) {
175                return new PatternParser(config, KEY, LogEventPatternConverter.class);
176            }
177            PatternParser parser = (PatternParser) config.getComponent(KEY);
178            if (parser == null) {
179                parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
180                config.addComponent(KEY, parser);
181                parser = (PatternParser) config.getComponent(KEY);
182            }
183            return parser;
184        }
185    
186        @Override
187        public String toString() {
188            return conversionPattern;
189        }
190    
191        /**
192         * Create a pattern layout.
193         * @param pattern The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN.
194         * @param config The Configuration. Some Converters require access to the Interpolator.
195         * @param replace A Regex replacement String.
196         * @param charsetName The character set.
197         * @return The PatternLayout.
198         */
199        @PluginFactory
200        public static PatternLayout createLayout(@PluginAttr("pattern") final String pattern,
201                                                 @PluginConfiguration final Configuration config,
202                                                 @PluginElement("replace") final RegexReplacement replace,
203                                                 @PluginAttr("charset") final String charsetName) {
204            final Charset charset = Charsets.getSupportedCharset(charsetName);
205            return new PatternLayout(config, replace, pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, charset);
206        }
207    }