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