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.lang.reflect.Field; 020import java.util.Arrays; 021import java.util.Comparator; 022import java.util.regex.Matcher; 023import java.util.regex.Pattern; 024 025import org.apache.logging.log4j.Level; 026import org.apache.logging.log4j.Marker; 027import org.apache.logging.log4j.core.Filter; 028import org.apache.logging.log4j.core.LogEvent; 029import org.apache.logging.log4j.core.Logger; 030import org.apache.logging.log4j.core.config.Node; 031import org.apache.logging.log4j.core.config.plugins.Plugin; 032import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 033import org.apache.logging.log4j.core.config.plugins.PluginElement; 034import org.apache.logging.log4j.core.config.plugins.PluginFactory; 035import org.apache.logging.log4j.message.Message; 036 037/** 038 * This filter returns the onMatch result if the message matches the regular expression. 039 * 040 * The "useRawMsg" attribute can be used to indicate whether the regular expression should be applied to the result of 041 * calling Message.getMessageFormat (true) or Message.getFormattedMessage() (false). The default is false. 042 * 043 */ 044@Plugin(name = "RegexFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true) 045public final class RegexFilter extends AbstractFilter { 046 047 private static final long serialVersionUID = 1L; 048 049 private static final int DEFAULT_PATTERN_FLAGS = 0; 050 private final Pattern pattern; 051 private final boolean useRawMessage; 052 053 private RegexFilter(final boolean raw, final Pattern pattern, final Result onMatch, final Result onMismatch) { 054 super(onMatch, onMismatch); 055 this.pattern = pattern; 056 this.useRawMessage = raw; 057 } 058 059 @Override 060 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg, 061 final Object... params) { 062 return filter(msg); 063 } 064 065 @Override 066 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg, 067 final Throwable t) { 068 if (msg == null) { 069 return onMismatch; 070 } 071 return filter(msg.toString()); 072 } 073 074 @Override 075 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg, 076 final Throwable t) { 077 if (msg == null) { 078 return onMismatch; 079 } 080 final String text = useRawMessage ? msg.getFormat() : msg.getFormattedMessage(); 081 return filter(text); 082 } 083 084 @Override 085 public Result filter(final LogEvent event) { 086 final String text = useRawMessage ? event.getMessage().getFormat() : event.getMessage().getFormattedMessage(); 087 return filter(text); 088 } 089 090 private Result filter(final String msg) { 091 if (msg == null) { 092 return onMismatch; 093 } 094 final Matcher m = pattern.matcher(msg); 095 return m.matches() ? onMatch : onMismatch; 096 } 097 098 @Override 099 public String toString() { 100 final StringBuilder sb = new StringBuilder(); 101 sb.append("useRaw=").append(useRawMessage); 102 sb.append(", pattern=").append(pattern.toString()); 103 return sb.toString(); 104 } 105 106 /** 107 * Create a Filter that matches a regular expression. 108 * 109 * @param regex 110 * The regular expression to match. 111 * @param patternFlags 112 * An array of Stirngs where each String is a {@link Pattern#compile(String, int)} compilation flag. 113 * @param useRawMsg 114 * If true, the raw message will be used, otherwise the formatted message will be used. 115 * @param match 116 * The action to perform when a match occurs. 117 * @param mismatch 118 * The action to perform when a mismatch occurs. 119 * @return The RegexFilter. 120 * @throws IllegalAccessException 121 * @throws IllegalArgumentException 122 */ 123 @PluginFactory 124 public static RegexFilter createFilter( 125 //@formatter:off 126 @PluginAttribute("regex") final String regex, 127 @PluginElement("PatternFlags") final String[] patternFlags, 128 @PluginAttribute("useRawMsg") final Boolean useRawMsg, 129 @PluginAttribute("onMatch") final Result match, 130 @PluginAttribute("onMismatch") final Result mismatch) 131 //@formatter:on 132 throws IllegalArgumentException, IllegalAccessException { 133 if (regex == null) { 134 LOGGER.error("A regular expression must be provided for RegexFilter"); 135 return null; 136 } 137 return new RegexFilter(useRawMsg, Pattern.compile(regex, toPatternFlags(patternFlags)), match, mismatch); 138 } 139 140 private static int toPatternFlags(final String[] patternFlags) throws IllegalArgumentException, 141 IllegalAccessException { 142 if (patternFlags == null || patternFlags.length == 0) { 143 return DEFAULT_PATTERN_FLAGS; 144 } 145 final Field[] fields = Pattern.class.getDeclaredFields(); 146 final Comparator<Field> comparator = new Comparator<Field>() { 147 148 @Override 149 public int compare(final Field f1, final Field f2) { 150 return f1.getName().compareTo(f2.getName()); 151 } 152 }; 153 Arrays.sort(fields, comparator); 154 final String[] fieldNames = new String[fields.length]; 155 for (int i = 0; i < fields.length; i++) { 156 fieldNames[i] = fields[i].getName(); 157 } 158 int flags = DEFAULT_PATTERN_FLAGS; 159 for (final String test : patternFlags) { 160 final int index = Arrays.binarySearch(fieldNames, test); 161 if (index >= 0) { 162 final Field field = fields[index]; 163 flags |= field.getInt(Pattern.class); 164 } 165 } 166 return flags; 167 } 168}