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