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.StringMapMessage;
022import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
023
024/**
025 * Able to handle the contents of the LogEvent's MapMessage and either
026 * output the entire contents of the properties in a similar format to the
027 * java.util.Hashtable.toString(), or to output the value of a specific key
028 * within the Map.
029 */
030@Plugin(name = "MapPatternConverter", category = PatternConverter.CATEGORY)
031@ConverterKeys({ "K", "map", "MAP" })
032public final class MapPatternConverter extends LogEventPatternConverter {
033    /**
034     * Name of property to output.
035     */
036    private final String key;
037
038    /**
039     * Private constructor.
040     *
041     * @param options options, may be null.
042     */
043    private MapPatternConverter(final String[] options) {
044        super(options != null && options.length > 0 ? "MAP{" + options[0] + '}' : "MAP", "map");
045        key = options != null && options.length > 0 ? options[0] : null;
046    }
047
048    /**
049     * Obtains an instance of PropertiesPatternConverter.
050     *
051     * @param options options, may be null or first element contains name of property to format.
052     * @return instance of PropertiesPatternConverter.
053     */
054    public static MapPatternConverter newInstance(final String[] options) {
055        return new MapPatternConverter(options);
056    }
057
058    /**
059     * {@inheritDoc}
060     */
061    @Override
062    public void format(final LogEvent event, final StringBuilder toAppendTo) {
063        StringMapMessage msg;
064        if (event.getMessage() instanceof StringMapMessage) {
065            msg = (StringMapMessage) event.getMessage();
066        } else {
067            return;
068        }
069        final IndexedReadOnlyStringMap sortedMap = msg.getIndexedReadOnlyStringMap();
070        // if there is no additional options, we output every single
071        // Key/Value pair for the Map in a similar format to Hashtable.toString()
072        if (key == null) {
073            if (sortedMap.isEmpty()) {
074                toAppendTo.append("{}");
075                return;
076            }
077            toAppendTo.append("{");
078            for (int i = 0; i < sortedMap.size(); i++) {
079                if (i > 0) {
080                    toAppendTo.append(", ");
081                }
082                toAppendTo.append(sortedMap.getKeyAt(i)).append('=').append((String)sortedMap.getValueAt(i));
083            }
084            toAppendTo.append('}');
085        } else {
086            // otherwise they just want a single key output
087            final String val = sortedMap.getValue(key);
088
089            if (val != null) {
090                toAppendTo.append(val);
091            }
092        }
093    }
094}