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