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 org.apache.logging.log4j.Level;
020    import org.apache.logging.log4j.Marker;
021    import org.apache.logging.log4j.ThreadContext;
022    import org.apache.logging.log4j.core.LogEvent;
023    import org.apache.logging.log4j.core.Logger;
024    import org.apache.logging.log4j.core.config.plugins.Plugin;
025    import org.apache.logging.log4j.core.config.plugins.PluginAttr;
026    import org.apache.logging.log4j.core.config.plugins.PluginElement;
027    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
028    import org.apache.logging.log4j.core.helpers.KeyValuePair;
029    import org.apache.logging.log4j.message.Message;
030    
031    import java.util.HashMap;
032    import java.util.Locale;
033    import java.util.Map;
034    
035    /**
036     * Compare against a log level that is associated with an MDC value.
037     */
038    @Plugin(name = "DynamicThresholdFilter", type = "Core", elementType = "filter", printObject = true)
039    public final class DynamicThresholdFilter extends AbstractFilter {
040        private Map<String, Level> levelMap = new HashMap<String, Level>();
041        private Level defaultThreshold = Level.ERROR;
042        private String key;
043    
044        private DynamicThresholdFilter(String key, Map<String, Level> pairs, Level defaultLevel,
045                                       Result onMatch, Result onMismatch) {
046            super(onMatch, onMismatch);
047            if (key == null) {
048                throw new NullPointerException("key cannot be null");
049            }
050            this.key = key;
051            this.levelMap = pairs;
052            this.defaultThreshold = defaultLevel;
053        }
054    
055        public String getKey() {
056            return this.key;
057        }
058    
059        @Override
060        public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
061            return filter(level);
062        }
063    
064        @Override
065        public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
066            return filter(level);
067        }
068    
069        @Override
070        public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
071            return filter(level);
072        }
073    
074        @Override
075        public Result filter(LogEvent event) {
076            return filter(event.getLevel());
077        }
078    
079        private Result filter(Level level) {
080            Object value = ThreadContext.get(key);
081            if (value != null) {
082                Level ctxLevel = levelMap.get(value);
083                if (ctxLevel == null) {
084                    ctxLevel = defaultThreshold;
085                }
086                return level.isAtLeastAsSpecificAs(ctxLevel) ? onMatch : onMismatch;
087            }
088            return Result.NEUTRAL;
089    
090        }
091    
092        public Map<String, Level> getLevelMap() {
093            return levelMap;
094        }
095    
096        @Override
097        public String toString() {
098            StringBuilder sb = new StringBuilder();
099            sb.append("key=").append(key);
100            sb.append(", default=").append(defaultThreshold);
101            if (levelMap.size() > 0) {
102                sb.append("{");
103                boolean first = true;
104                for (Map.Entry<String, Level> entry : levelMap.entrySet()) {
105                    if (!first) {
106                        sb.append(", ");
107                        first = false;
108                    }
109                    sb.append(entry.getKey()).append("=").append(entry.getValue());
110                }
111                sb.append("}");
112            }
113            return sb.toString();
114        }
115    
116        /**
117         * Create the DynamicThresholdFilter.
118         * @param key The name of the key to compare.
119         * @param pairs An array of value and Level pairs.
120         * @param levelName The default Level.
121         * @param match The action to perform if a match occurs.
122         * @param mismatch The action to perform if no match occurs.
123         * @return The DynamicThresholdFilter.
124         */
125        @PluginFactory
126        public static DynamicThresholdFilter createFilter(@PluginAttr("key") String key,
127                                                          @PluginElement("pairs") KeyValuePair[] pairs,
128                                                          @PluginAttr("defaultThreshold") String levelName,
129                                                          @PluginAttr("onmatch") String match,
130                                                          @PluginAttr("onmismatch") String mismatch) {
131            Result onMatch = Result.toResult(match);
132            Result onMismatch = Result.toResult(mismatch);
133            Map<String, Level> map = new HashMap<String, Level>();
134            for (KeyValuePair pair : pairs) {
135                map.put(pair.getKey(), Level.toLevel(pair.getValue()));
136            }
137            Level level = Level.toLevel(levelName, Level.ERROR);
138            return new DynamicThresholdFilter(key, map, level, onMatch, onMismatch);
139        }
140    }