    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.filter;
    018
    019    import java.util.ArrayList;
    020    import java.util.HashMap;
    021    import java.util.List;
    022    import java.util.Map;
    023
    024    import org.apache.logging.log4j.Level;
    025    import org.apache.logging.log4j.Marker;
    026    import org.apache.logging.log4j.core.Filter;
    027    import org.apache.logging.log4j.core.LogEvent;
    028    import org.apache.logging.log4j.core.Logger;
    029    import org.apache.logging.log4j.core.config.Node;
    030    import org.apache.logging.log4j.core.config.plugins.Plugin;
    031    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    032    import org.apache.logging.log4j.core.config.plugins.PluginElement;
    033    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    034    import org.apache.logging.log4j.core.util.KeyValuePair;
    035    import org.apache.logging.log4j.message.MapMessage;
    036    import org.apache.logging.log4j.message.Message;
    037
    038    /**
    039     * A Filter that operates on a Map.
    040     */
    041    @Plugin(name = "MapFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
    042    public class MapFilter extends AbstractFilter {
    043
    044        private static final long serialVersionUID = 1L;
    045
    046        private final Map<String, List<String>> map;
    047
    048        private final boolean isAnd;
    049
    050        protected MapFilter(final Map<String, List<String>> map, final boolean oper, final Result onMatch,
    051                            final Result onMismatch) {
    052            super(onMatch, onMismatch);
    053            if (map == null) {
    054                throw new NullPointerException("key cannot be null");
    055            }
    056            this.isAnd = oper;
    057            this.map = map;
    058        }
    059
    060        @Override
    061        public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
    062                             final Throwable t) {
    063            if (msg instanceof MapMessage) {
    064                return filter(((MapMessage) msg).getData()) ? onMatch : onMismatch;
    065            }
    066            return Result.NEUTRAL;
    067        }
    068
    069        @Override
    070        public Result filter(final LogEvent event) {
    071            final Message msg = event.getMessage();
    072            if (msg instanceof MapMessage) {
    073                return filter(((MapMessage) msg).getData()) ? onMatch : onMismatch;
    074            }
    075            return Result.NEUTRAL;
    076        }
    077
    078        protected boolean filter(final Map<String, String> data) {
    079            boolean match = false;
    080            for (final Map.Entry<String, List<String>> entry : map.entrySet()) {
    081                final String toMatch = data.get(entry.getKey());
    082                if (toMatch != null) {
    083                    match = entry.getValue().contains(toMatch);
    084                } else {
    085                    match = false;
    086                }
    087                if ((!isAnd && match) || (isAnd && !match)) {
    088                    break;
    089                }
    090            }
    091            return match;
    092        }
    093
    094        @Override
    095        public String toString() {
    096            final StringBuilder sb = new StringBuilder();
    097            sb.append("isAnd=").append(isAnd);
    098            if (map.size() > 0) {
    099                sb.append(", {");
    100                boolean first = true;
    101                for (final Map.Entry<String, List<String>> entry : map.entrySet()) {
    102                    if (!first) {
    103                        sb.append(", ");
    104                    }
    105                    first = false;
    106                    final List<String> list = entry.getValue();
    107                    final String value = list.size() > 1 ? list.get(0) : list.toString();
    108                    sb.append(entry.getKey()).append('=').append(value);
    109                }
    110                sb.append('}');
    111            }
    112            return sb.toString();
    113        }
    114
    115        protected boolean isAnd() {
    116            return isAnd;
    117        }
    118
    119        protected Map<String, List<String>> getMap() {
    120            return map;
    121        }
    122
    123        @PluginFactory
    124        public static MapFilter createFilter(
    125                @PluginElement("Pairs") final KeyValuePair[] pairs,
    126                @PluginAttribute("operator") final String oper,
    127                @PluginAttribute("onMatch") final Result match,
    128                @PluginAttribute("onMismatch") final Result mismatch) {
    129            if (pairs == null || pairs.length == 0) {
    130                LOGGER.error("keys and values must be specified for the MapFilter");
    131                return null;
    132            }
    133            final Map<String, List<String>> map = new HashMap<String, List<String>>();
    134            for (final KeyValuePair pair : pairs) {
    135                final String key = pair.getKey();
    136                if (key == null) {
    137                    LOGGER.error("A null key is not valid in MapFilter");
    138                    continue;
    139                }
    140                final String value = pair.getValue();
    141                if (value == null) {
    142                    LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
    143                    continue;
    144                }
    145                List<String> list = map.get(pair.getKey());
    146                if (list != null) {
    147                    list.add(value);
    148                } else {
    149                    list = new ArrayList<String>();
    150                    list.add(value);
    151                    map.put(pair.getKey(), list);
    152                }
    153            }
    154            if (map.isEmpty()) {
    155                LOGGER.error("MapFilter is not configured with any valid key value pairs");
    156                return null;
    157            }
    158            final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
    159            return new MapFilter(map, isAnd, match, mismatch);
    160        }
    161    }