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