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