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.pattern;
018    
019    import java.util.Map;
020    import java.util.Set;
021    import java.util.TreeSet;
022    
023    import org.apache.logging.log4j.core.LogEvent;
024    import org.apache.logging.log4j.core.config.plugins.Plugin;
025    import 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" })
035    public 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    }