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 */
017package org.apache.logging.log4j.core.pattern;
018
019import java.util.List;
020
021import org.apache.logging.log4j.core.LogEvent;
022import org.apache.logging.log4j.core.config.Configuration;
023import org.apache.logging.log4j.core.config.plugins.Plugin;
024import org.apache.logging.log4j.core.layout.PatternLayout;
025
026/**
027 * Returns the event's rendered message in a StringBuilder.
028 */
029@Plugin(name = "encode", category = PatternConverter.CATEGORY)
030@ConverterKeys({ "enc", "encode" })
031public final class EncodingPatternConverter extends LogEventPatternConverter {
032
033    private final List<PatternFormatter> formatters;
034
035    /**
036     * Private constructor.
037     *
038     * @param formatters The PatternFormatters to generate the text to manipulate.
039     */
040    private EncodingPatternConverter(final List<PatternFormatter> formatters) {
041        super("encode", "encode");
042        this.formatters = formatters;
043    }
044
045    /**
046     * Obtains an instance of pattern converter.
047     *
048     * @param config  The Configuration.
049     * @param options options, may be null.
050     * @return instance of pattern converter.
051     */
052    public static EncodingPatternConverter newInstance(final Configuration config, final String[] options) {
053        if (options.length != 1) {
054            LOGGER.error("Incorrect number of options on escape. Expected 1, received " + options.length);
055            return null;
056        }
057        if (options[0] == null) {
058            LOGGER.error("No pattern supplied on escape");
059            return null;
060        }
061        final PatternParser parser = PatternLayout.createPatternParser(config);
062        final List<PatternFormatter> formatters = parser.parse(options[0]);
063        return new EncodingPatternConverter(formatters);
064    }
065
066    /**
067     * {@inheritDoc}
068     */
069    @Override
070    public void format(final LogEvent event, final StringBuilder toAppendTo) {
071        final StringBuilder buf = new StringBuilder();
072        for (final PatternFormatter formatter : formatters) {
073            formatter.format(event, buf);
074        }
075        for (int i = 0; i < buf.length(); i++) {
076            final char c = buf.charAt(i);
077            switch (c) {
078                case '\r':
079                    toAppendTo.append("\\r");
080                    break;
081                case '\n':
082                    toAppendTo.append("\\n");
083                    break;
084                case '&':
085                    toAppendTo.append("&amp;");
086                    break;
087                case '<':
088                    toAppendTo.append("&lt;");
089                    break;
090                case '>':
091                    toAppendTo.append("&gt;");
092                    break;
093                case '"':
094                    toAppendTo.append("&quot;");
095                    break;
096                case '\'':
097                    toAppendTo.append("&apos;");
098                    break;
099                case '/':
100                    toAppendTo.append("&#x2F;");
101                    break;
102                default:
103                    toAppendTo.append(c);
104                    break;
105            }
106        }
107    }
108}