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.layout; 018 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.logging.log4j.Logger; 024import org.apache.logging.log4j.Marker; 025import org.apache.logging.log4j.core.LogEvent; 026import org.apache.logging.log4j.core.config.Configuration; 027import org.apache.logging.log4j.core.config.Node; 028import org.apache.logging.log4j.core.config.plugins.Plugin; 029import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 030import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 031import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 032import org.apache.logging.log4j.core.config.plugins.PluginElement; 033import org.apache.logging.log4j.core.pattern.PatternFormatter; 034import org.apache.logging.log4j.core.pattern.PatternParser; 035import org.apache.logging.log4j.status.StatusLogger; 036 037/** 038 * Selects the pattern to use based on the Marker in the LogEvent. 039 */ 040@Plugin(name = "MarkerPatternSelector", category = Node.CATEGORY, elementType = PatternSelector.ELEMENT_TYPE, printObject = true) 041public class MarkerPatternSelector implements PatternSelector { 042 043 /** 044 * Custom MarkerPatternSelector builder. Use the {@link MarkerPatternSelector#newBuilder() builder factory method} to create this. 045 */ 046 public static class Builder implements org.apache.logging.log4j.core.util.Builder<MarkerPatternSelector> { 047 048 @PluginElement("PatternMatch") 049 private PatternMatch[] properties; 050 051 @PluginBuilderAttribute("defaultPattern") 052 private String defaultPattern; 053 054 @PluginBuilderAttribute(value = "alwaysWriteExceptions") 055 private boolean alwaysWriteExceptions = true; 056 057 @PluginBuilderAttribute(value = "disableAnsi") 058 private boolean disableAnsi; 059 060 @PluginBuilderAttribute(value = "noConsoleNoAnsi") 061 private boolean noConsoleNoAnsi; 062 063 @PluginConfiguration 064 private Configuration configuration; 065 066 @Override 067 public MarkerPatternSelector build() { 068 if (defaultPattern == null) { 069 defaultPattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; 070 } 071 if (properties == null || properties.length == 0) { 072 LOGGER.warn("No marker patterns were provided with PatternMatch"); 073 return null; 074 } 075 return new MarkerPatternSelector(properties, defaultPattern, alwaysWriteExceptions, disableAnsi, 076 noConsoleNoAnsi, configuration); 077 } 078 079 public Builder setProperties(final PatternMatch[] properties) { 080 this.properties = properties; 081 return this; 082 } 083 084 public Builder setDefaultPattern(final String defaultPattern) { 085 this.defaultPattern = defaultPattern; 086 return this; 087 } 088 089 public Builder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) { 090 this.alwaysWriteExceptions = alwaysWriteExceptions; 091 return this; 092 } 093 094 public Builder setDisableAnsi(final boolean disableAnsi) { 095 this.disableAnsi = disableAnsi; 096 return this; 097 } 098 099 public Builder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) { 100 this.noConsoleNoAnsi = noConsoleNoAnsi; 101 return this; 102 } 103 104 public Builder setConfiguration(final Configuration configuration) { 105 this.configuration = configuration; 106 return this; 107 } 108 109 } 110 111 private final Map<String, PatternFormatter[]> formatterMap = new HashMap<>(); 112 113 private final Map<String, String> patternMap = new HashMap<>(); 114 115 private final PatternFormatter[] defaultFormatters; 116 117 private final String defaultPattern; 118 119 private static Logger LOGGER = StatusLogger.getLogger(); 120 121 122 /** 123 * @deprecated Use {@link #newBuilder()} instead. This will be private in a future version. 124 */ 125 @Deprecated 126 public MarkerPatternSelector(final PatternMatch[] properties, final String defaultPattern, 127 final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi, 128 final Configuration config) { 129 this(properties, defaultPattern, alwaysWriteExceptions, false, noConsoleNoAnsi, config); 130 } 131 132 private MarkerPatternSelector(final PatternMatch[] properties, final String defaultPattern, 133 final boolean alwaysWriteExceptions, final boolean disableAnsi, 134 final boolean noConsoleNoAnsi, final Configuration config) { 135 final PatternParser parser = PatternLayout.createPatternParser(config); 136 for (final PatternMatch property : properties) { 137 try { 138 final List<PatternFormatter> list = parser.parse(property.getPattern(), alwaysWriteExceptions, 139 disableAnsi, noConsoleNoAnsi); 140 formatterMap.put(property.getKey(), list.toArray(new PatternFormatter[list.size()])); 141 patternMap.put(property.getKey(), property.getPattern()); 142 } catch (final RuntimeException ex) { 143 throw new IllegalArgumentException("Cannot parse pattern '" + property.getPattern() + "'", ex); 144 } 145 } 146 try { 147 final List<PatternFormatter> list = parser.parse(defaultPattern, alwaysWriteExceptions, disableAnsi, 148 noConsoleNoAnsi); 149 defaultFormatters = list.toArray(new PatternFormatter[list.size()]); 150 this.defaultPattern = defaultPattern; 151 } catch (final RuntimeException ex) { 152 throw new IllegalArgumentException("Cannot parse pattern '" + defaultPattern + "'", ex); 153 } 154 } 155 156 @Override 157 public PatternFormatter[] getFormatters(final LogEvent event) { 158 final Marker marker = event.getMarker(); 159 if (marker == null) { 160 return defaultFormatters; 161 } 162 for (final String key : formatterMap.keySet()) { 163 if (marker.isInstanceOf(key)) { 164 return formatterMap.get(key); 165 } 166 } 167 return defaultFormatters; 168 } 169 170 /** 171 * Creates a builder for a custom ScriptPatternSelector. 172 * 173 * @return a ScriptPatternSelector builder. 174 */ 175 @PluginBuilderFactory 176 public static Builder newBuilder() { 177 return new Builder(); 178 } 179 180 /** 181 * Deprecated, use {@link #newBuilder()} instead. 182 * @param properties 183 * @param defaultPattern 184 * @param alwaysWriteExceptions 185 * @param noConsoleNoAnsi 186 * @param configuration 187 * @return a new MarkerPatternSelector. 188 * @deprecated Use {@link #newBuilder()} instead. 189 */ 190 @Deprecated 191 public static MarkerPatternSelector createSelector( 192 final PatternMatch[] properties, 193 final String defaultPattern, 194 final boolean alwaysWriteExceptions, 195 final boolean noConsoleNoAnsi, 196 final Configuration configuration) { 197 final Builder builder = newBuilder(); 198 builder.setProperties(properties); 199 builder.setDefaultPattern(defaultPattern); 200 builder.setAlwaysWriteExceptions(alwaysWriteExceptions); 201 builder.setNoConsoleNoAnsi(noConsoleNoAnsi); 202 builder.setConfiguration(configuration); 203 return builder.build(); 204 } 205 206 @Override 207 public String toString() { 208 final StringBuilder sb = new StringBuilder(); 209 boolean first = true; 210 for (final Map.Entry<String, String> entry : patternMap.entrySet()) { 211 if (!first) { 212 sb.append(", "); 213 } 214 sb.append("key=\"").append(entry.getKey()).append("\", pattern=\"").append(entry.getValue()).append("\""); 215 first = false; 216 } 217 if (!first) { 218 sb.append(", "); 219 } 220 sb.append("default=\"").append(defaultPattern).append("\""); 221 return sb.toString(); 222 } 223}