001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.appender.routing; 018 019import static org.apache.logging.log4j.core.appender.routing.RoutingAppender.STATIC_VARIABLES_KEY; 020 021import java.util.Objects; 022import java.util.concurrent.ConcurrentMap; 023 024import javax.script.Bindings; 025 026import org.apache.logging.log4j.Logger; 027import org.apache.logging.log4j.core.Core; 028import org.apache.logging.log4j.core.LogEvent; 029import org.apache.logging.log4j.core.config.Configuration; 030import org.apache.logging.log4j.core.config.plugins.Plugin; 031import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 032import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 033import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 034import org.apache.logging.log4j.core.config.plugins.PluginElement; 035import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 036import org.apache.logging.log4j.core.script.AbstractScript; 037import org.apache.logging.log4j.core.script.ScriptManager; 038import org.apache.logging.log4j.status.StatusLogger; 039 040/** 041 * Contains the individual Route elements. 042 */ 043@Plugin(name = "Routes", category = Core.CATEGORY_NAME, printObject = true) 044public final class Routes { 045 046 private static final String LOG_EVENT_KEY = "logEvent"; 047 048 public static class Builder implements org.apache.logging.log4j.core.util.Builder<Routes> { 049 050 @PluginConfiguration 051 private Configuration configuration; 052 053 @PluginAttribute("pattern") 054 private String pattern; 055 056 @PluginElement("Script") 057 private AbstractScript patternScript; 058 059 @PluginElement("Routes") 060 @Required 061 private Route[] routes; 062 063 @Override 064 public Routes build() { 065 if (routes == null || routes.length == 0) { 066 LOGGER.error("No Routes configured."); 067 return null; 068 } 069 if ((patternScript != null && pattern != null) || (patternScript == null && pattern == null)) { 070 LOGGER.warn("In a Routes element, you must configure either a Script element or a pattern attribute."); 071 } 072 if (patternScript != null) { 073 if (configuration == null) { 074 LOGGER.error("No Configuration defined for Routes; required for Script"); 075 } else { 076 configuration.getScriptManager().addScript(patternScript); 077 } 078 } 079 return new Routes(configuration, patternScript, pattern, routes); 080 } 081 082 public Configuration getConfiguration() { 083 return configuration; 084 } 085 086 public String getPattern() { 087 return pattern; 088 } 089 090 public AbstractScript getPatternScript() { 091 return patternScript; 092 } 093 094 public Route[] getRoutes() { 095 return routes; 096 } 097 098 public Builder withConfiguration(@SuppressWarnings("hiding") final Configuration configuration) { 099 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}