1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.layout;
18
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22
23 import javax.script.SimpleBindings;
24
25 import org.apache.logging.log4j.Logger;
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.config.Configuration;
28 import org.apache.logging.log4j.core.config.Node;
29 import org.apache.logging.log4j.core.config.plugins.Plugin;
30 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
31 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
32 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
33 import org.apache.logging.log4j.core.config.plugins.PluginElement;
34 import org.apache.logging.log4j.core.impl.LocationAware;
35 import org.apache.logging.log4j.core.pattern.PatternFormatter;
36 import org.apache.logging.log4j.core.pattern.PatternParser;
37 import org.apache.logging.log4j.core.script.AbstractScript;
38 import org.apache.logging.log4j.core.script.ScriptRef;
39 import org.apache.logging.log4j.status.StatusLogger;
40
41
42
43
44 @Plugin(name = "ScriptPatternSelector", category = Node.CATEGORY, elementType = PatternSelector.ELEMENT_TYPE, printObject = true)
45 public class ScriptPatternSelector implements PatternSelector, LocationAware {
46
47
48
49
50 public static class Builder implements org.apache.logging.log4j.core.util.Builder<ScriptPatternSelector> {
51
52 @PluginElement("Script")
53 private AbstractScript script;
54
55 @PluginElement("PatternMatch")
56 private PatternMatch[] properties;
57
58 @PluginBuilderAttribute("defaultPattern")
59 private String defaultPattern;
60
61 @PluginBuilderAttribute("alwaysWriteExceptions")
62 private boolean alwaysWriteExceptions = true;
63
64 @PluginBuilderAttribute("disableAnsi")
65 private boolean disableAnsi;
66
67 @PluginBuilderAttribute("noConsoleNoAnsi")
68 private boolean noConsoleNoAnsi;
69
70 @PluginConfiguration
71 private Configuration configuration;
72
73 private Builder() {
74
75 }
76
77 @Override
78 public ScriptPatternSelector build() {
79 if (script == null) {
80 LOGGER.error("A Script, ScriptFile or ScriptRef element must be provided for this ScriptFilter");
81 return null;
82 }
83 if (script instanceof ScriptRef) {
84 if (configuration.getScriptManager().getScript(script.getName()) == null) {
85 LOGGER.error("No script with name {} has been declared.", script.getName());
86 return null;
87 }
88 }
89 if (defaultPattern == null) {
90 defaultPattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
91 }
92 if (properties == null || properties.length == 0) {
93 LOGGER.warn("No marker patterns were provided");
94 return null;
95 }
96 return new ScriptPatternSelector(script, properties, defaultPattern, alwaysWriteExceptions, disableAnsi,
97 noConsoleNoAnsi, configuration);
98 }
99
100 public Builder setScript(final AbstractScript script) {
101 this.script = script;
102 return this;
103 }
104
105 public Builder setProperties(final PatternMatch[] properties) {
106 this.properties = properties;
107 return this;
108 }
109
110 public Builder setDefaultPattern(final String defaultPattern) {
111 this.defaultPattern = defaultPattern;
112 return this;
113 }
114
115 public Builder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) {
116 this.alwaysWriteExceptions = alwaysWriteExceptions;
117 return this;
118 }
119
120 public Builder setDisableAnsi(final boolean disableAnsi) {
121 this.disableAnsi = disableAnsi;
122 return this;
123 }
124
125 public Builder setNoConsoleNoAnsi(final boolean noConsoleNoAnsi) {
126 this.noConsoleNoAnsi = noConsoleNoAnsi;
127 return this;
128 }
129
130 public Builder setConfiguration(final Configuration config) {
131 this.configuration = config;
132 return this;
133 }
134 }
135
136 private final Map<String, PatternFormatter[]> formatterMap = new HashMap<>();
137
138 private final Map<String, String> patternMap = new HashMap<>();
139
140 private final PatternFormatter[] defaultFormatters;
141
142 private final String defaultPattern;
143
144 private static Logger LOGGER = StatusLogger.getLogger();
145 private final AbstractScript script;
146 private final Configuration configuration;
147 private final boolean requiresLocation;
148
149
150
151
152 @Deprecated
153 public ScriptPatternSelector(final AbstractScript script, final PatternMatch[] properties, final String defaultPattern,
154 final boolean alwaysWriteExceptions, final boolean disableAnsi,
155 final boolean noConsoleNoAnsi, final Configuration config) {
156 this.script = script;
157 this.configuration = config;
158 if (!(script instanceof ScriptRef)) {
159 config.getScriptManager().addScript(script);
160 }
161 final PatternParser parser = PatternLayout.createPatternParser(config);
162 boolean needsLocation = false;
163 for (final PatternMatch property : properties) {
164 try {
165 final List<PatternFormatter> list = parser.parse(property.getPattern(), alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi);
166 PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
167 formatterMap.put(property.getKey(), formatters);
168 patternMap.put(property.getKey(), property.getPattern());
169 for (int i = 0; !needsLocation && i < formatters.length; ++i) {
170 needsLocation = formatters[i].requiresLocation();
171 }
172 } catch (final RuntimeException ex) {
173 throw new IllegalArgumentException("Cannot parse pattern '" + property.getPattern() + "'", ex);
174 }
175 }
176 try {
177 final List<PatternFormatter> list = parser.parse(defaultPattern, alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi);
178 defaultFormatters = list.toArray(new PatternFormatter[0]);
179 this.defaultPattern = defaultPattern;
180 for (int i = 0; !needsLocation && i < defaultFormatters.length; ++i) {
181 needsLocation = defaultFormatters[i].requiresLocation();
182 }
183 } catch (final RuntimeException ex) {
184 throw new IllegalArgumentException("Cannot parse pattern '" + defaultPattern + "'", ex);
185 }
186 this.requiresLocation = needsLocation;
187 }
188
189 @Override
190 public boolean requiresLocation() {
191 return requiresLocation;
192 }
193
194 @Override
195 public PatternFormatter[] getFormatters(final LogEvent event) {
196 final SimpleBindings bindings = new SimpleBindings();
197 bindings.putAll(configuration.getProperties());
198 bindings.put("substitutor", configuration.getStrSubstitutor());
199 bindings.put("logEvent", event);
200 final Object object = configuration.getScriptManager().execute(script.getName(), bindings);
201 if (object == null) {
202 return defaultFormatters;
203 }
204 final PatternFormatter[] patternFormatter = formatterMap.get(object.toString());
205
206 return patternFormatter == null ? defaultFormatters : patternFormatter;
207 }
208
209
210
211
212
213
214
215 @PluginBuilderFactory
216 public static Builder newBuilder() {
217 return new Builder();
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232 @Deprecated
233 public static ScriptPatternSelector createSelector(
234 final AbstractScript script,
235 final PatternMatch[] properties,
236 final String defaultPattern,
237 final boolean alwaysWriteExceptions,
238 final boolean noConsoleNoAnsi,
239 final Configuration configuration) {
240 final Builder builder = newBuilder();
241 builder.setScript(script);
242 builder.setProperties(properties);
243 builder.setDefaultPattern(defaultPattern);
244 builder.setAlwaysWriteExceptions(alwaysWriteExceptions);
245 builder.setNoConsoleNoAnsi(noConsoleNoAnsi);
246 builder.setConfiguration(configuration);
247 return builder.build();
248 }
249
250 @Override
251 public String toString() {
252 final StringBuilder sb = new StringBuilder();
253 boolean first = true;
254 for (final Map.Entry<String, String> entry : patternMap.entrySet()) {
255 if (!first) {
256 sb.append(", ");
257 }
258 sb.append("key=\"").append(entry.getKey()).append("\", pattern=\"").append(entry.getValue()).append("\"");
259 first = false;
260 }
261 if (!first) {
262 sb.append(", ");
263 }
264 sb.append("default=\"").append(defaultPattern).append("\"");
265 return sb.toString();
266 }
267 }