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 */ 017package org.apache.logging.log4j.core.filter; 018 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.logging.log4j.Level; 025import org.apache.logging.log4j.Marker; 026import org.apache.logging.log4j.core.Filter; 027import org.apache.logging.log4j.core.LogEvent; 028import org.apache.logging.log4j.core.Logger; 029import org.apache.logging.log4j.core.config.Node; 030import org.apache.logging.log4j.core.config.plugins.Plugin; 031import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 032import org.apache.logging.log4j.core.config.plugins.PluginElement; 033import org.apache.logging.log4j.core.config.plugins.PluginFactory; 034import org.apache.logging.log4j.core.util.KeyValuePair; 035import org.apache.logging.log4j.message.Message; 036import org.apache.logging.log4j.message.StructuredDataMessage; 037 038/** 039 * Filter based on data in a StructuredDataMessage. 040 */ 041@Plugin(name = "StructuredDataFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true) 042public final class StructuredDataFilter extends MapFilter { 043 044 private static final long serialVersionUID = 1L; 045 046 private StructuredDataFilter(final Map<String, List<String>> map, final boolean oper, final Result onMatch, 047 final Result onMismatch) { 048 super(map, oper, onMatch, onMismatch); 049 } 050 051 @Override 052 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg, 053 final Throwable t) { 054 if (msg instanceof StructuredDataMessage) { 055 return filter((StructuredDataMessage) msg); 056 } 057 return Result.NEUTRAL; 058 } 059 060 @Override 061 public Result filter(final LogEvent event) { 062 final Message msg = event.getMessage(); 063 if (msg instanceof StructuredDataMessage) { 064 return filter((StructuredDataMessage) msg); 065 } 066 return super.filter(event); 067 } 068 069 protected Result filter(final StructuredDataMessage message) { 070 boolean match = false; 071 for (final Map.Entry<String, List<String>> entry : getMap().entrySet()) { 072 final String toMatch = getValue(message, entry.getKey()); 073 if (toMatch != null) { 074 match = entry.getValue().contains(toMatch); 075 } else { 076 match = false; 077 } 078 if ((!isAnd() && match) || (isAnd() && !match)) { 079 break; 080 } 081 } 082 return match ? onMatch : onMismatch; 083 } 084 085 private String getValue(final StructuredDataMessage data, final String key) { 086 if (key.equalsIgnoreCase("id")) { 087 return data.getId().toString(); 088 } else if (key.equalsIgnoreCase("id.name")) { 089 return data.getId().getName(); 090 } else if (key.equalsIgnoreCase("type")) { 091 return data.getType(); 092 } else if (key.equalsIgnoreCase("message")) { 093 return data.getFormattedMessage(); 094 } else { 095 return data.getData().get(key); 096 } 097 } 098 099 /** 100 * Create the StructuredDataFilter. 101 * @param pairs Key and value pairs. 102 * @param oper The operator to perform. If not "or" the operation will be an "and". 103 * @param match The action to perform on a match. 104 * @param mismatch The action to perform on a mismatch. 105 * @return The StructuredDataFilter. 106 */ 107 @PluginFactory 108 public static StructuredDataFilter createFilter( 109 @PluginElement("Pairs") final KeyValuePair[] pairs, 110 @PluginAttribute("operator") final String oper, 111 @PluginAttribute("onMatch") final Result match, 112 @PluginAttribute("onMismatch") final Result mismatch) { 113 if (pairs == null || pairs.length == 0) { 114 LOGGER.error("keys and values must be specified for the StructuredDataFilter"); 115 return null; 116 } 117 final Map<String, List<String>> map = new HashMap<String, List<String>>(); 118 for (final KeyValuePair pair : pairs) { 119 final String key = pair.getKey(); 120 if (key == null) { 121 LOGGER.error("A null key is not valid in MapFilter"); 122 continue; 123 } 124 final String value = pair.getValue(); 125 if (value == null) { 126 LOGGER.error("A null value for key " + key + " is not allowed in MapFilter"); 127 continue; 128 } 129 List<String> list = map.get(pair.getKey()); 130 if (list != null) { 131 list.add(value); 132 } else { 133 list = new ArrayList<String>(); 134 list.add(value); 135 map.put(pair.getKey(), list); 136 } 137 } 138 if (map.isEmpty()) { 139 LOGGER.error("StructuredDataFilter is not configured with any valid key value pairs"); 140 return null; 141 } 142 final boolean isAnd = oper == null || !oper.equalsIgnoreCase("or"); 143 return new StructuredDataFilter(map, isAnd, match, mismatch); 144 } 145}