View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.layout;
18  
19  import org.apache.logging.log4j.Logger;
20  import org.apache.logging.log4j.core.LogEvent;
21  import org.apache.logging.log4j.core.config.Configuration;
22  import org.apache.logging.log4j.core.config.Node;
23  import org.apache.logging.log4j.core.config.plugins.Plugin;
24  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
25  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
26  import org.apache.logging.log4j.core.config.plugins.PluginElement;
27  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
28  import org.apache.logging.log4j.core.pattern.PatternFormatter;
29  import org.apache.logging.log4j.core.pattern.PatternParser;
30  import org.apache.logging.log4j.core.script.AbstractScript;
31  import org.apache.logging.log4j.core.script.ScriptRef;
32  import org.apache.logging.log4j.status.StatusLogger;
33  
34  import javax.script.SimpleBindings;
35  import java.util.HashMap;
36  import java.util.List;
37  import java.util.Map;
38  
39  /**
40   * Selects the pattern to use based on the Marker in the LogEvent.
41   */
42  @Plugin(name = "ScriptPatternSelector", category = Node.CATEGORY, elementType = PatternSelector.ELEMENT_TYPE, printObject = true)
43  public class ScriptPatternSelector implements PatternSelector {
44  
45      private final Map<String, PatternFormatter[]> formatterMap = new HashMap<>();
46  
47      private final Map<String, String> patternMap = new HashMap<>();
48  
49      private final PatternFormatter[] defaultFormatters;
50  
51      private final String defaultPattern;
52  
53      private static Logger LOGGER = StatusLogger.getLogger();
54      private final AbstractScript script;
55      private final Configuration configuration;
56  
57  
58      public ScriptPatternSelector(final AbstractScript script, final PatternMatch[] properties, final String defaultPattern,
59                                   final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi,
60                                   final Configuration config) {
61          this.script = script;
62          this.configuration = config;
63          if (!(script instanceof ScriptRef)) {
64              config.getScriptManager().addScript(script);
65          }
66          final PatternParser parser = PatternLayout.createPatternParser(config);
67          for (final PatternMatch property : properties) {
68              try {
69                  final List<PatternFormatter> list = parser.parse(property.getPattern(), alwaysWriteExceptions, noConsoleNoAnsi);
70                  formatterMap.put(property.getKey(), list.toArray(new PatternFormatter[list.size()]));
71                  patternMap.put(property.getKey(), property.getPattern());
72              } catch (final RuntimeException ex) {
73                  throw new IllegalArgumentException("Cannot parse pattern '" + property.getPattern() + "'", ex);
74              }
75          }
76          try {
77              final List<PatternFormatter> list = parser.parse(defaultPattern, alwaysWriteExceptions, noConsoleNoAnsi);
78              defaultFormatters = list.toArray(new PatternFormatter[list.size()]);
79              this.defaultPattern = defaultPattern;
80          } catch (final RuntimeException ex) {
81              throw new IllegalArgumentException("Cannot parse pattern '" + defaultPattern + "'", ex);
82          }
83      }
84  
85      @Override
86      public PatternFormatter[] getFormatters(final LogEvent event) {
87          final SimpleBindings bindings = new SimpleBindings();
88          bindings.putAll(configuration.getProperties());
89          bindings.put("substitutor", configuration.getStrSubstitutor());
90          bindings.put("logEvent", event);
91          final Object object = configuration.getScriptManager().execute(script.getName(), bindings);
92          if (object == null) {
93              return defaultFormatters;
94          }
95          final PatternFormatter[] patternFormatter = formatterMap.get(object.toString());
96  
97          return patternFormatter == null ? defaultFormatters : patternFormatter;
98      }
99  
100 
101     @PluginFactory
102     public static ScriptPatternSelector createSelector(@PluginElement("Script") final AbstractScript script,
103                                                        @PluginElement("PatternMatch") final PatternMatch[] properties,
104                                                        @PluginAttribute("defaultPattern") String defaultPattern,
105                                                        @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions,
106                                                        @PluginAttribute(value = "noConsoleNoAnsi", defaultBoolean = false) final boolean noConsoleNoAnsi,
107                                                        @PluginConfiguration final Configuration config) {
108         if (script == null) {
109             LOGGER.error("A Script, ScriptFile or ScriptRef element must be provided for this ScriptFilter");
110             return null;
111         }
112         if (script instanceof ScriptRef) {
113             if (config.getScriptManager().getScript(script.getName()) == null) {
114                 LOGGER.error("No script with name {} has been declared.", script.getName());
115                 return null;
116             }
117         }
118         if (defaultPattern == null) {
119             defaultPattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
120         }
121         if (properties == null || properties.length == 0) {
122             LOGGER.warn("No marker patterns were provided");
123         }
124         return new ScriptPatternSelector(script, properties, defaultPattern, alwaysWriteExceptions, noConsoleNoAnsi, config);
125     }
126 
127     @Override
128     public String toString() {
129         final StringBuilder sb = new StringBuilder();
130         boolean first = true;
131         for (final Map.Entry<String, String> entry : patternMap.entrySet()) {
132             if (!first) {
133                 sb.append(", ");
134             }
135             sb.append("key=\"").append(entry.getKey()).append("\", pattern=\"").append(entry.getValue()).append("\"");
136             first = false;
137         }
138         if (!first) {
139             sb.append(", ");
140         }
141         sb.append("default=\"").append(defaultPattern).append("\"");
142         return sb.toString();
143     }
144 }