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 org.apache.logging.log4j.core.LogEvent;
020import org.apache.logging.log4j.core.config.plugins.Plugin;
021import org.apache.logging.log4j.message.MapMessage;
022import org.apache.logging.log4j.message.MapMessage.MapFormat;
023
024import java.util.Objects;
025
026/**
027 * Able to handle the contents of the LogEvent's MapMessage and either
028 * output the entire contents of the properties in a similar format to the
029 * java.util.Hashtable.toString(), or to output the value of a specific key
030 * within the Map.
031 */
032@Plugin(name = "MapPatternConverter", category = PatternConverter.CATEGORY)
033@ConverterKeys({ "K", "map", "MAP" })
034public final class MapPatternConverter extends LogEventPatternConverter {
035
036    private static final String JAVA_UNQUOTED = MapFormat.JAVA_UNQUOTED.name();
037
038    /**
039     * Name of property to output.
040     */
041    private final String key;
042
043    /**
044     * Format to use when no key is provided.
045     *
046     * @see MapFormat
047     * @since 2.11.2
048     */
049    private final String[] format;
050
051    /**
052     * Private constructor.
053     *
054     * @param options options, may be null.
055     */
056    private MapPatternConverter(final String[] options, String... format) {
057        super(options != null && options.length > 0 ? "MAP{" + options[0] + '}' : "MAP", "map");
058        key = options != null && options.length > 0 ? options[0] : null;
059        this.format = format;
060    }
061
062    /**
063     * Obtains an instance of {@link MapPatternConverter}.
064     *
065     * @param options options, may be null or first element contains name of property to format.
066     * @return instance of {@link MapPatternConverter}.
067     */
068    public static MapPatternConverter newInstance(final String[] options) {
069        return new MapPatternConverter(options, JAVA_UNQUOTED);
070    }
071
072    /**
073     * Obtain an instance of {@link MapPatternConverter}.
074     *
075     * @param options options, may be null or first element contains name of property to format.
076     * @param format the format to use if no options are given (i.e., options is null). Ignored if options is non-null.
077     * @return instance of {@link MapPatternConverter}.
078     * @since 2.11.2
079     */
080    public static MapPatternConverter newInstance(final String[] options, final MapFormat format) {
081        return new MapPatternConverter(options, Objects.toString(format, JAVA_UNQUOTED));
082    }
083
084    /**
085     * {@inheritDoc}
086     */
087    @Override
088    public void format(final LogEvent event, final StringBuilder toAppendTo) {
089        MapMessage msg;
090        if (event.getMessage() instanceof MapMessage) {
091            msg = (MapMessage) event.getMessage();
092        } else {
093            return;
094        }
095        // if there is no additional options, we output every single
096        // Key/Value pair for the Map in a similar format to Hashtable.toString()
097        if (key == null) {
098            msg.formatTo(format, toAppendTo);
099        } else {
100            // otherwise they just want a single key output
101            final String val = msg.get(key);
102
103            if (val != null) {
104                toAppendTo.append(val);
105            }
106        }
107    }
108}