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 org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.Marker;
21  import org.apache.logging.log4j.core.LogEvent;
22  import org.apache.logging.log4j.core.Logger;
23  import org.apache.logging.log4j.core.config.plugins.Plugin;
24  import org.apache.logging.log4j.core.config.plugins.PluginAttr;
25  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
26  import org.apache.logging.log4j.core.helpers.KeyValuePair;
27  import org.apache.logging.log4j.message.Message;
28  import org.apache.logging.log4j.message.StructuredDataMessage;
29  
30  import java.util.ArrayList;
31  import java.util.HashMap;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Map;
35  
36  /**
37   * Filter based on data in a StructuredDataMessage.
38   */
39  @Plugin(name = "StructuredDataFilter", type = "Core", elementType = "filter", printObject = true)
40  public final class StructuredDataFilter extends MapFilter {
41  
42      private StructuredDataFilter(Map<String, List<String>> map, boolean oper, Result onMatch, Result onMismatch) {
43          super(map, oper, onMatch, onMismatch);
44      }
45  
46      @Override
47      public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
48          if (msg instanceof StructuredDataMessage) {
49              return filter((StructuredDataMessage) msg);
50          }
51          return Result.NEUTRAL;
52      }
53  
54      @Override
55      public Result filter(LogEvent event) {
56          Message msg = event.getMessage();
57          if (msg instanceof StructuredDataMessage) {
58              return filter((StructuredDataMessage) msg);
59          }
60          return super.filter(event);
61      }
62  
63      protected Result filter(StructuredDataMessage message) {
64          boolean match = false;
65          for (Map.Entry<String, List<String>> entry : getMap().entrySet()) {
66              String toMatch = getValue(message, entry.getKey());
67              if (toMatch != null) {
68                  match = entry.getValue().contains(toMatch);
69              } else {
70                  match = false;
71              }
72              if ((!isAnd() && match) || (isAnd() && !match)) {
73                  break;
74              }
75          }
76          return match ? onMatch : onMismatch;
77      }
78  
79      private String getValue(StructuredDataMessage data, String key) {
80          if (key.equalsIgnoreCase("id")) {
81              return data.getId().toString();
82          } else if (key.equalsIgnoreCase("id.name")) {
83              return data.getId().getName();
84          } else if (key.equalsIgnoreCase("type")) {
85              return data.getType();
86          } else if (key.equalsIgnoreCase("message")) {
87              return data.getFormattedMessage();
88          } else {
89              return data.getData().get(key);
90          }
91      }
92  
93      /**
94       * Create the StructuredDataFilter.
95       * @param pairs Key and value pairs.
96       * @param oper The operator to perform. If not "or" the operation will be an "and".
97       * @param match The action to perform on a match.
98       * @param mismatch The action to perform on a mismatch.
99       * @return The StructuredDataFilter.
100      */
101     @PluginFactory
102     public static StructuredDataFilter createFilter(@PluginAttr("pairs") KeyValuePair[] pairs,
103                                                     @PluginAttr("operator") String oper,
104                                                     @PluginAttr("onmatch") String match,
105                                                     @PluginAttr("onmismatch") String mismatch) {
106         if (pairs == null || pairs.length == 0) {
107             LOGGER.error("keys and values must be specified for the StructuredDataFilter");
108             return null;
109         }
110         Map<String, List<String>> map = new HashMap<String, List<String>>();
111         for (KeyValuePair pair : pairs) {
112             String key = pair.getKey();
113             if (key == null) {
114                 LOGGER.error("A null key is not valid in MapFilter");
115                 continue;
116             }
117             String value = pair.getValue();
118             if (value == null) {
119                 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter");
120                 continue;
121             }
122             List<String> list = map.get(pair.getKey());
123             if (list != null) {
124                 list.add(value);
125             } else {
126                 list = new ArrayList<String>();
127                 list.add(value);
128                 map.put(pair.getKey(), list);
129             }
130         }
131         if (map.size() == 0) {
132             LOGGER.error("StructuredDataFilter is not configured with any valid key value pairs");
133             return null;
134         }
135         boolean isAnd = oper == null || !oper.equalsIgnoreCase("or");
136         Result onMatch = Result.toResult(match);
137         Result onMismatch = Result.toResult(mismatch);
138         return new StructuredDataFilter(map, isAnd, onMatch, onMismatch);
139     }
140 }