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.appender.routing;
18  
19  import static org.apache.logging.log4j.core.appender.routing.RoutingAppender.STATIC_VARIABLES_KEY;
20  
21  import java.util.Objects;
22  import java.util.concurrent.ConcurrentMap;
23  
24  import javax.script.Bindings;
25  
26  import org.apache.logging.log4j.Logger;
27  import org.apache.logging.log4j.core.LogEvent;
28  import org.apache.logging.log4j.core.config.Configuration;
29  import org.apache.logging.log4j.core.config.plugins.Plugin;
30  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
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.config.plugins.validation.constraints.Required;
35  import org.apache.logging.log4j.core.script.AbstractScript;
36  import org.apache.logging.log4j.core.script.ScriptManager;
37  import org.apache.logging.log4j.status.StatusLogger;
38  
39  /**
40   * Contains the individual Route elements.
41   */
42  @Plugin(name = "Routes", category = "Core", printObject = true)
43  public final class Routes {
44  
45      private static final String LOG_EVENT_KEY = "logEvent";
46  
47      public static class Builder implements org.apache.logging.log4j.core.util.Builder<Routes>  {
48  
49          @PluginConfiguration 
50          private Configuration configuration;
51  
52          @PluginAttribute("pattern") 
53          private String pattern;
54          
55          @PluginElement("Script")
56          private AbstractScript patternScript;
57  
58          @PluginElement("Routes")
59          @Required
60          private Route[] routes;
61  
62          @Override
63          public Routes build() {
64              if (routes == null || routes.length == 0) {
65                  LOGGER.error("No Routes configured.");
66                  return null;
67              }
68              if (patternScript != null && pattern != null) {
69                  LOGGER.warn("In a Routes element, you must configure either a Script element or a pattern attribute.");
70              }
71              if (patternScript != null) {
72                  if (configuration == null) {
73                      LOGGER.error("No Configuration defined for Routes; required for Script");
74                  } else {
75                      configuration.getScriptManager().addScript(patternScript);
76                  }
77              }
78              return new Routes(configuration, patternScript, pattern, routes);
79          }
80  
81          public Configuration getConfiguration() {
82              return configuration;
83          }
84  
85          public String getPattern() {
86              return pattern;
87          }
88  
89          public AbstractScript getPatternScript() {
90              return patternScript;
91          }
92  
93          public Route[] getRoutes() {
94              return routes;
95          }
96  
97          public Builder withConfiguration(@SuppressWarnings("hiding") final Configuration configuration) {
98              this.configuration = configuration;
99              return this;
100         }
101 
102         public Builder withPattern(@SuppressWarnings("hiding") final String pattern) {
103             this.pattern = pattern;
104             return this;
105         }
106 
107         public Builder withPatternScript(@SuppressWarnings("hiding") final AbstractScript patternScript) {
108             this.patternScript = patternScript;
109             return this;
110         }
111 
112         public Builder withRoutes(@SuppressWarnings("hiding") final Route[] routes) {
113             this.routes = routes;
114             return this;
115         }
116         
117     }
118 
119     private static final Logger LOGGER = StatusLogger.getLogger();
120 
121     /**
122      * Creates the Routes.
123      * @param pattern The pattern.
124      * @param routes An array of Route elements.
125      * @return The Routes container.
126      * @deprecated since 2.7; use {@link #newBuilder()}.
127      */
128     @Deprecated
129     public static Routes createRoutes(
130             final String pattern,
131             final Route... routes) {
132         if (routes == null || routes.length == 0) {
133             LOGGER.error("No routes configured");
134             return null;
135         }
136         return new Routes(null, null, pattern, routes);
137     }
138 
139     @PluginBuilderFactory
140     public static Builder newBuilder() {
141         return new Builder();
142     }
143     
144     private final Configuration configuration;
145     
146     private final String pattern;
147 
148     private final AbstractScript patternScript;
149     
150     // TODO Why not make this a Map or add a Map.
151     private final Route[] routes;
152     
153     private Routes(final Configuration configuration, final AbstractScript patternScript, final String pattern, final Route... routes) {
154         this.configuration = configuration;
155         this.patternScript = patternScript;
156         this.pattern = pattern;
157         this.routes = routes;
158     }
159 
160     /**
161      * Returns the pattern.
162      * @param event The log event passed to the script (if there is a script.)
163      * @param scriptStaticVariables The script's static variables.
164      * @return the pattern.
165      */
166     public String getPattern(final LogEvent event, final ConcurrentMap<Object, Object> scriptStaticVariables) {
167         if (patternScript != null) {
168             final ScriptManager scriptManager = configuration.getScriptManager();
169             final Bindings bindings = scriptManager.createBindings(patternScript);
170             bindings.put(STATIC_VARIABLES_KEY, scriptStaticVariables);
171             bindings.put(LOG_EVENT_KEY, event);
172             final Object object = scriptManager.execute(patternScript.getName(), bindings);
173             bindings.remove(LOG_EVENT_KEY);
174             return Objects.toString(object, null);
175         }
176         return pattern;
177     }
178 
179     /**
180      * Gets the optional script that decides which route to pick.
181      * @return the optional script that decides which route to pick. May be null.
182      */
183     public AbstractScript getPatternScript() {
184         return patternScript;
185     }
186 
187     public Route getRoute(final String key) {
188         for (final Route route : routes) {
189             if (Objects.equals(route.getKey(), key)) {
190                 return route;
191             }
192         }
193         return null;
194     }
195 
196     /**
197      * Returns the array of Route elements.
198      * @return an array of Route elements.
199      */
200     public Route[] getRoutes() {
201         return routes;
202     }
203 
204     @Override
205     public String toString() {
206         final StringBuilder sb = new StringBuilder("{");
207         boolean first = true;
208         for (final Route route : routes) {
209             if (!first) {
210                 sb.append(',');
211             }
212             first = false;
213             sb.append(route.toString());
214         }
215         sb.append('}');
216         return sb.toString();
217 
218     }
219 
220 }