1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.routing;
18
19 import java.util.Collections;
20 import java.util.Map;
21 import java.util.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.ConcurrentMap;
23
24 import org.apache.logging.log4j.core.Appender;
25 import org.apache.logging.log4j.core.Filter;
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.appender.AbstractAppender;
28 import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
29 import org.apache.logging.log4j.core.config.AppenderControl;
30 import org.apache.logging.log4j.core.config.Configuration;
31 import org.apache.logging.log4j.core.config.Node;
32 import org.apache.logging.log4j.core.config.plugins.Plugin;
33 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
34 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
35 import org.apache.logging.log4j.core.config.plugins.PluginElement;
36 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
37 import org.apache.logging.log4j.core.util.Booleans;
38
39
40
41
42
43
44
45
46
47 @Plugin(name = "Routing", category = "Core", elementType = "appender", printObject = true)
48 public final class RoutingAppender extends AbstractAppender {
49 private static final long serialVersionUID = 1L;
50 private static final String DEFAULT_KEY = "ROUTING_APPENDER_DEFAULT";
51 private final Routes routes;
52 private final Route defaultRoute;
53 private final Configuration config;
54 private final ConcurrentMap<String, AppenderControl> appenders = new ConcurrentHashMap<>();
55 private final RewritePolicy rewritePolicy;
56 private final PurgePolicy purgePolicy;
57
58 private RoutingAppender(final String name, final Filter filter, final boolean ignoreExceptions, final Routes routes,
59 final RewritePolicy rewritePolicy, final Configuration config, PurgePolicy purgePolicy) {
60 super(name, filter, null, ignoreExceptions);
61 this.routes = routes;
62 this.config = config;
63 this.rewritePolicy = rewritePolicy;
64 this.purgePolicy = purgePolicy;
65 if(this.purgePolicy != null) {
66 this.purgePolicy.initialize(this);
67 }
68 Route defRoute = null;
69 for (final Route route : routes.getRoutes()) {
70 if (route.getKey() == null) {
71 if (defRoute == null) {
72 defRoute = route;
73 } else {
74 error("Multiple default routes. Route " + route.toString() + " will be ignored");
75 }
76 }
77 }
78 defaultRoute = defRoute;
79 }
80
81 @Override
82 public void start() {
83
84 for (final Route route : routes.getRoutes()) {
85 if (route.getAppenderRef() != null) {
86 final Appender appender = config.getAppender(route.getAppenderRef());
87 if (appender != null) {
88 final String key = route == defaultRoute ? DEFAULT_KEY : route.getKey();
89 appenders.put(key, new AppenderControl(appender, null, null));
90 } else {
91 LOGGER.error("Appender " + route.getAppenderRef() + " cannot be located. Route ignored");
92 }
93 }
94 }
95 super.start();
96 }
97
98 @Override
99 public void stop() {
100 super.stop();
101 final Map<String, Appender> map = config.getAppenders();
102 for (final Map.Entry<String, AppenderControl> entry : appenders.entrySet()) {
103 final String name = entry.getValue().getAppender().getName();
104 if (!map.containsKey(name)) {
105 entry.getValue().getAppender().stop();
106 }
107 }
108 }
109
110 @Override
111 public void append(LogEvent event) {
112 if (rewritePolicy != null) {
113 event = rewritePolicy.rewrite(event);
114 }
115 final String key = config.getStrSubstitutor().replace(event, routes.getPattern());
116 final AppenderControl control = getControl(key, event);
117 if (control != null) {
118 control.callAppender(event);
119 }
120
121 if(purgePolicy != null) {
122 purgePolicy.update(key, event);
123 }
124 }
125
126 private synchronized AppenderControl getControl(final String key, final LogEvent event) {
127 AppenderControl control = appenders.get(key);
128 if (control != null) {
129 return control;
130 }
131 Route route = null;
132 for (final Route r : routes.getRoutes()) {
133 if (r.getAppenderRef() == null && key.equals(r.getKey())) {
134 route = r;
135 break;
136 }
137 }
138 if (route == null) {
139 route = defaultRoute;
140 control = appenders.get(DEFAULT_KEY);
141 if (control != null) {
142 return control;
143 }
144 }
145 if (route != null) {
146 final Appender app = createAppender(route, event);
147 if (app == null) {
148 return null;
149 }
150 control = new AppenderControl(app, null, null);
151 appenders.put(key, control);
152 }
153
154 return control;
155 }
156
157 private Appender createAppender(final Route route, final LogEvent event) {
158 final Node routeNode = route.getNode();
159 for (final Node node : routeNode.getChildren()) {
160 if (node.getType().getElementName().equals("appender")) {
161 final Node appNode = new Node(node);
162 config.createConfiguration(appNode, event);
163 if (appNode.getObject() instanceof Appender) {
164 final Appender app = appNode.getObject();
165 app.start();
166 return app;
167 }
168 LOGGER.error("Unable to create Appender of type " + node.getName());
169 return null;
170 }
171 }
172 LOGGER.error("No Appender was configured for route " + route.getKey());
173 return null;
174 }
175
176 public Map<String, AppenderControl> getAppenders() {
177 return Collections.unmodifiableMap(appenders);
178 }
179
180
181
182
183
184
185 public void deleteAppender(String key) {
186 LOGGER.debug("Stopping route with key" + key);
187 AppenderControl control = appenders.remove(key);
188 control.getAppender().stop();
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202 @PluginFactory
203 public static RoutingAppender createAppender(
204 @PluginAttribute("name") final String name,
205 @PluginAttribute("ignoreExceptions") final String ignore,
206 @PluginElement("Routes") final Routes routes,
207 @PluginConfiguration final Configuration config,
208 @PluginElement("RewritePolicy") final RewritePolicy rewritePolicy,
209 @PluginElement("PurgePolicy") final PurgePolicy purgePolicy,
210 @PluginElement("Filter") final Filter filter) {
211
212 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
213 if (name == null) {
214 LOGGER.error("No name provided for RoutingAppender");
215 return null;
216 }
217 if (routes == null) {
218 LOGGER.error("No routes defined for RoutingAppender");
219 return null;
220 }
221 return new RoutingAppender(name, filter, ignoreExceptions, routes, rewritePolicy, config, purgePolicy);
222 }
223 }