View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.core.filter;
    18
    19  import java.util.ArrayList;
    20  import java.util.HashMap;
    21  import java.util.Iterator;
    22  import java.util.List;
    23  import java.util.Map;
    24
    25  import org.apache.logging.log4j.Level;
    26  import org.apache.logging.log4j.Marker;
    27  import org.apache.logging.log4j.ThreadContext;
    28  import org.apache.logging.log4j.core.Filter;
    29  import org.apache.logging.log4j.core.LogEvent;
    30  import org.apache.logging.log4j.core.Logger;
    31  import org.apache.logging.log4j.core.config.Node;
    32  import org.apache.logging.log4j.core.config.plugins.Plugin;
    33  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    34  import org.apache.logging.log4j.core.config.plugins.PluginElement;
    35  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    36  import org.apache.logging.log4j.core.util.KeyValuePair;
    37  import org.apache.logging.log4j.message.Message;
    38
    39  /**
    40   * Filter based on a value in the Thread Context Map (MDC).
    41   */
    42  @Plugin(name = "ThreadContextMapFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
    43  public class ThreadContextMapFilter extends MapFilter {
    44
    45      private static final long serialVersionUID = 1L;
    46
    47      private final String key;
    48      private final String value;
    49
    50      private final boolean useMap;
    51
    52      public ThreadContextMapFilter(final Map<String, List<String>> pairs, final boolean oper, final Result onMatch,
    53                                    final Result onMismatch) {
    54          super(pairs, oper, onMatch, onMismatch);
    55          if (pairs.size() == 1) {
    56              final Iterator<Map.Entry<String, List<String>>> iter = pairs.entrySet().iterator();
    57              final Map.Entry<String, List<String>> entry = iter.next();
    58              if (entry.getValue().size() == 1) {
    59                  this.key = entry.getKey();
    60                  this.value = entry.getValue().get(0);
    61                  this.useMap = false;
    62              } else {
    63                  this.key = null;
    64                  this.value = null;
    65                  this.useMap = true;
    66              }
    67          } else {
    68              this.key = null;
    69              this.value = null;
    70              this.useMap = true;
    71          }
    72      }
    73
    74      @Override
    75      public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
    76                           final Object... params) {
    77          return filter();
    78      }
    79
    80      @Override
    81      public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
    82                           final Throwable t) {
    83          return filter();
    84      }
    85
    86      @Override
    87      public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
    88                           final Throwable t) {
    89          return filter();
    90      }
    91
    92      private Result filter() {
    93          boolean match = false;
    94          if (useMap) {
    95              for (final Map.Entry<String, List<String>> entry : getMap().entrySet()) {
    96                  final String toMatch = ThreadContext.get(entry.getKey());
    97                  if (toMatch != null) {
    98                      match = entry.getValue().contains(toMatch);
    99                  } else {
    100                     match = false;
    101                 }
    102                 if ((!isAnd() && match) || (isAnd() && !match)) {
    103                     break;
    104                 }
    105             }
    106         } else {
    107             match = value.equals(ThreadContext.get(key));
    108         }
    109         return match ? onMatch : onMismatch;
    110     }
    111
    112     @Override
    113     public Result filter(final LogEvent event) {
    114         return super.filter(event.getContextMap()) ? onMatch : onMismatch;
    115     }
    116
    117     @PluginFactory
    118     public static ThreadContextMapFilter createFilter(
    119             @PluginElement("Pairs") final KeyValuePair[] pairs,
    120             @PluginAttribute("operator") final String oper,
    121             @PluginAttribute("onMatch") final Result match,
    122             @PluginAttribute("onMismatch") final Result mismatch) {
    123         if (pairs == null || pairs.length == 0) {
    124             LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
    125             return null;
    126         }
    127         final Map<String, List<String>> map = new HashMap<String, List<String>>();
    128         for (final KeyValuePair pair : pairs) {
    129             final String key = pair.getKey();
    130             if (key == null) {
    131                 LOGGER.error("A null key is not valid in MapFilter");
    132                 continue;
    133             }
    134             final String value = pair.getValue();
    135             if (value == null) {
    136                 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
    137                 continue;
    138             }
    139             List<String> list = map.get(pair.getKey());
    140             if (list != null) {
    141                 list.add(value);
    142             } else {
    143                 list = new ArrayList<String>();
    144                 list.add(value);
    145                 map.put(pair.getKey(), list);
    146             }
    147         }
    148         if (map.isEmpty()) {
    149             LOGGER.error("ThreadContextMapFilter is not configured with any valid key value pairs");
    150             return null;
    151         }
    152         final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
    153         return new ThreadContextMapFilter(map, isAnd, match, mismatch);
    154     }
    155 }