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.ThreadContext;
021 import org.apache.logging.log4j.Marker;
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.ArrayList;
032 import java.util.HashMap;
033 import java.util.Iterator;
034 import java.util.List;
035 import java.util.Map;
036
037 /**
038 * Filter based on a value in the Thread Context Map (MDC).
039 */
040 @Plugin(name = "ThreadContextMapFilter", category = "Core", elementType = "filter", printObject = true)
041 public class ThreadContextMapFilter extends MapFilter {
042
043 private final String key;
044 private final String value;
045
046 private final boolean useMap;
047
048 public ThreadContextMapFilter(final Map<String, List<String>> pairs, final boolean oper, final Result onMatch,
049 final Result onMismatch) {
050 super(pairs, oper, onMatch, onMismatch);
051 if (pairs.size() == 1) {
052 final Iterator<Map.Entry<String, List<String>>> iter = pairs.entrySet().iterator();
053 final Map.Entry<String, List<String>> entry = iter.next();
054 if (entry.getValue().size() == 1) {
055 this.key = entry.getKey();
056 this.value = entry.getValue().get(0);
057 this.useMap = false;
058 } else {
059 this.key = null;
060 this.value = null;
061 this.useMap = true;
062 }
063 } else {
064 this.key = null;
065 this.value = null;
066 this.useMap = true;
067 }
068 }
069
070 @Override
071 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
072 final Object... params) {
073 return filter();
074 }
075
076 @Override
077 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
078 final Throwable t) {
079 return filter();
080 }
081
082 @Override
083 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
084 final Throwable t) {
085 return filter();
086 }
087
088 private Result filter() {
089 boolean match = false;
090 if (useMap) {
091 for (final Map.Entry<String, List<String>> entry : getMap().entrySet()) {
092 final String toMatch = ThreadContext.get(entry.getKey());
093 if (toMatch != null) {
094 match = entry.getValue().contains(toMatch);
095 } else {
096 match = false;
097 }
098 if ((!isAnd() && match) || (isAnd() && !match)) {
099 break;
100 }
101 }
102 } else {
103 match = value.equals(ThreadContext.get(key));
104 }
105 return match ? onMatch : onMismatch;
106 }
107
108 @Override
109 public Result filter(final LogEvent event) {
110 return super.filter(event.getContextMap()) ? onMatch : onMismatch;
111 }
112
113 @PluginFactory
114 public static ThreadContextMapFilter createFilter(@PluginElement("pairs") final KeyValuePair[] pairs,
115 @PluginAttr("operator") final String oper,
116 @PluginAttr("onmatch") final String match,
117 @PluginAttr("onmismatch") final String mismatch) {
118 if (pairs == null || pairs.length == 0) {
119 LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
120 return null;
121 }
122 final Map<String, List<String>> map = new HashMap<String, List<String>>();
123 for (final KeyValuePair pair : pairs) {
124 final String key = pair.getKey();
125 if (key == null) {
126 LOGGER.error("A null key is not valid in MapFilter");
127 continue;
128 }
129 final String value = pair.getValue();
130 if (value == null) {
131 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
132 continue;
133 }
134 List<String> list = map.get(pair.getKey());
135 if (list != null) {
136 list.add(value);
137 } else {
138 list = new ArrayList<String>();
139 list.add(value);
140 map.put(pair.getKey(), list);
141 }
142 }
143 if (map.size() == 0) {
144 LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
145 return null;
146 }
147 final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
148 final Result onMatch = Result.toResult(match);
149 final Result onMismatch = Result.toResult(mismatch);
150 return new ThreadContextMapFilter(map, isAnd, onMatch, onMismatch);
151 }
152 }